Hello community,
here is the log from the commit of package python-ordered-namespace for
openSUSE:Factory checked in at 2019-07-23 22:40:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ordered-namespace (Old)
and /work/SRC/openSUSE:Factory/.python-ordered-namespace.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ordered-namespace"
Tue Jul 23 22:40:51 2019 rev:5 rq:717901 version:2019.6.8
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-ordered-namespace/python-ordered-namespace.changes
2019-06-06 18:16:17.932704010 +0200
+++
/work/SRC/openSUSE:Factory/.python-ordered-namespace.new.4126/python-ordered-namespace.changes
2019-07-23 22:40:55.454906835 +0200
@@ -1,0 +2,8 @@
+Tue Jul 23 13:40:19 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 2019.6.8:
+ * Jupyter/iPython pretty printing works even better than before. Everything
lines up and is easier to read at a glance.
+ * Tab auto-completion now shows both class methods and data attribute.
Previously it only showed data attributes.
+ * Full support for pickle serialization/deserialization.
+
+-------------------------------------------------------------------
Old:
----
ordered_namespace-2018.6.26.tar.gz
New:
----
ordered_namespace-2019.6.8.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-ordered-namespace.spec ++++++
--- /var/tmp/diff_new_pack.x51m1i/_old 2019-07-23 22:40:56.102906015 +0200
+++ /var/tmp/diff_new_pack.x51m1i/_new 2019-07-23 22:40:56.122905989 +0200
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-ordered-namespace
-Version: 2018.6.26
+Version: 2019.6.8
Release: 0
Summary: Python namespace class
License: MIT
++++++ ordered_namespace-2018.6.26.tar.gz -> ordered_namespace-2019.6.8.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ordered_namespace-2018.6.26/PKG-INFO
new/ordered_namespace-2019.6.8/PKG-INFO
--- old/ordered_namespace-2018.6.26/PKG-INFO 2018-06-27 01:54:24.000000000
+0200
+++ new/ordered_namespace-2019.6.8/PKG-INFO 2019-06-09 05:57:42.000000000
+0200
@@ -1,11 +1,11 @@
Metadata-Version: 1.0
Name: ordered_namespace
-Version: 2018.6.26
-Summary: An easy-to-use Python namespace class derived from OrderedDict,
including tab-completion
+Version: 2019.6.8
+Summary: An easy-to-use Python namespace class derived from OrderedDict,
includes tab-completion
Home-page: https://github.com/who8mylunch/OrderedNamespace
Author: Pierre V. Villeneuve
Author-email: [email protected]
License: MIT
Description: UNKNOWN
-Keywords: namespace,ordereddict,structure
+Keywords: namespace,ordereddict,structure,dotdict,tab-completion
Platform: UNKNOWN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ordered_namespace-2018.6.26/README.md
new/ordered_namespace-2019.6.8/README.md
--- old/ordered_namespace-2018.6.26/README.md 2017-07-18 04:03:52.000000000
+0200
+++ new/ordered_namespace-2019.6.8/README.md 2019-06-08 23:05:09.000000000
+0200
@@ -1,6 +1,6 @@
# OrderedNamespace
-Namespaces are a great idea and this one is mine.
+Dot-accessible attributes and namespaces are great ideas and this one is mine.
What's the big deal? Python dicts are just fine, but in the Jupyter/IPython
interactive environment I hate having to deal with brackets and quotes when
using tab-based auto-completion to get a quick glance at the contents of an
object.
@@ -68,4 +68,3 @@
- http://ipython.readthedocs.io/en/stable/config/integrating.html
- https://github.com/ipython/ipython/blob/master/IPython/lib/pretty.py
- https://docs.python.org/3/library/functions.html#dir
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ordered_namespace-2018.6.26/ordered_namespace/core.py
new/ordered_namespace-2019.6.8/ordered_namespace/core.py
--- old/ordered_namespace-2018.6.26/ordered_namespace/core.py 2018-06-27
01:51:59.000000000 +0200
+++ new/ordered_namespace-2019.6.8/ordered_namespace/core.py 2019-06-09
05:48:13.000000000 +0200
@@ -1,46 +1,48 @@
from collections import OrderedDict, UserDict
import re
+__all__ = ['Struct']
-
-def convert_to_struct(value):
+def safe_convert_to_struct(value, nested=False):
"""Convert the following to Structs:
- dicts
- list elements that are dicts
- ???
- This function is harmless to call on arbitrary variables.
+ This function is harmless to call on un-handled variables.
"""
direct_converts = [dict, OrderedDict, UserDict]
if type(value) in direct_converts:
# Convert dict-like things to Struct
- value = Struct(value)
+ value = Struct(value, nested=nested)
elif isinstance(value, list):
# Process list elements
- value = [convert_to_struct(z) for z in value]
+ value = [safe_convert_to_struct(z, nested=nested) for z in value]
+ elif isinstance(value, tuple):
+ # Process list elements
+ value = tupe([safe_convert_to_struct(z, nested=nested) for z in value])
# Done
return value
-class Struct:
+class Struct():
"""Ordered namespace class
"""
# Regular expression pattern for valid Python attributes
# https://docs.python.org/3/reference/lexical_analysis.html#identifiers
- # _valid_key_pattern = re.compile('[a-zA-Z_][a-zA-Z0-9_]*')
_valid_key_pattern = re.compile('[a-zA-Z][a-zA-Z0-9_]*')
_special_names = ['_odict']
_repr_max_width = 13
- def __init__(self, *args, **kwargs):
+ def __init__(self, *args, nested=False, **kwargs):
"""Ordered namespace class
"""
self.__dict__['_odict'] = OrderedDict()
-
+ self.__dict__['_nested'] = nested
self.update(*args, **kwargs)
def update(self, *args, **kwargs):
@@ -48,6 +50,7 @@
"""
d = {}
d.update(*args, **kwargs)
+
for key, value in d.items():
self[key] = value
@@ -57,18 +60,22 @@
attribute names (e.g. dict class instance methods).
"""
if not isinstance(key, str):
+ # attributes must be a string
return False
elif hasattr({}, key):
+ # attributes cannot be same as existing dict method
return False
elif key in self._special_names:
+ # attributes cannot be same as pre-identified special names
return False
else:
+ # attributes must match valid key pattern
return self._valid_key_pattern.match(key)
def asdict(self):
"""Return a recursive dict representation of self
"""
- d = dict(self._odict)
+ d = self._odict
for k,v in d.items():
if isinstance(v, Struct):
@@ -77,7 +84,7 @@
return d
#--------------------------------
- # Expose a few standard dict methods
+ # Expose standard dict methods
def items(self):
return self._odict.items()
@@ -90,13 +97,16 @@
def pop(self, key):
return self._odict.pop(key)
+ def copy(self):
+ return self._odict.copy()
+
#--------------------------------
# Expose essential dict internal methods
def __setattr__(self, key, value):
"""Set an item with dot-style access while testing for invalid names
"""
if not self._valid_key(key):
- raise AttributeError('Invalid attribute name: {}'.format(key))
+ raise AttributeError('Invalid key/attribute name: {}'.format(key))
try:
self[key] = value
@@ -105,20 +115,18 @@
def __setitem__(self, key, value):
if not self._valid_key(key):
- raise KeyError('Invalid attribute name: {}'.format(key))
+ raise KeyError('Invalid key/attribute name: {}'.format(key))
- value = convert_to_struct(value)
- # if isinstance(value, dict) and key not in self._special_names:
- # # Convert dict to Struct
- # value = Struct(value)
- # elif isinstance(value, list):
- # # Find elements to convert from dict to Struct
- # change = []
- # for k, v in enumerate(value):
- # if isinstance(v, dict):
- # change.append(k)
+ if self._nested:
+ self._odict[key] = safe_convert_to_struct(value, nested=True)
+ else:
+ self._odict[key] = value
+
+ def __getstate__(self):
+ return self.__dict__.copy()
- self._odict[key] = value
+ def __setstate__(self, state):
+ self.__dict__.update(state)
def __getattr__(self, key):
return self._odict[key]
@@ -141,11 +149,6 @@
def __contains__(self, key):
return self._odict.__contains__(key)
- def __dir__(self):
-
"""http://ipython.readthedocs.io/en/stable/config/integrating.html#tab-completion
- """
- return self._odict.keys()
-
def __eq__(self, other):
return self._odict.__eq__(other)
@@ -153,13 +156,16 @@
return self._odict.__ne__(other)
def __repr__(self):
- return self._odict.__repr__()
+ if self:
+ return '%s(%r)' % (self.__class__.__name__, self.items())
+ else:
+ return '%s()' % (self.__class__.__name__,)
- # def _ipython_key_completions_(self):
- #
"""http://ipython.readthedocs.io/en/stable/config/integrating.html#tab-completion
- # """
- # print('sdfdsfdf')
- # return self.__dir__()
+ def __dir__(self):
+
"""http://ipython.readthedocs.io/en/stable/config/integrating.html#tab-completion
+ https://amir.rachum.com/blog/2016/10/05/python-dynamic-attributes
+ """
+ return super().__dir__() + [str(k) for k in self._odict.keys()]
def _repr_pretty_(self, p, cycle):
"""Derived from IPython's dict and sequence pretty printer functions,
@@ -168,28 +174,24 @@
if cycle:
p.text('{...}')
else:
- keys = self.keys()
+ delim_start = self.__class__.__name__ + '{'
+ delim_end = '}'
+
+ with p.group(indent=len(delim_start), open=delim_start,
close=delim_end):
+ # Loop over items
+ for ix, (key, value) in p._enumerate(self.items()):
+ p.break_()
+
+ key_txt = '{:s}: '.format(key)
+ L = len(key_txt)
+
+ p.indentation += L
+ p.text(key_txt)
+ p.pretty(value)
+ p.text(',')
+ p.indentation -= L
- if keys:
- delim_start = '[{'
- delim_end = '}]'
-
- wid_max_max = self._repr_max_width
- wid_max = max([len(k) for k in keys])
- wid_max = min([wid_max, wid_max_max])
- key_template = '{{:{:d}s}}: '.format(wid_max)
-
- with p.group(len(delim_start), delim_start, delim_end):
- # Loop over item keys
- for idx, key in p._enumerate(keys):
- if idx:
- p.text(',')
- p.breakable()
-
- p.text(key_template.format(key))
- p.pretty(self[key])
- else:
- p.text('{}')
+ p.break_()
#------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ordered_namespace-2018.6.26/ordered_namespace.egg-info/PKG-INFO
new/ordered_namespace-2019.6.8/ordered_namespace.egg-info/PKG-INFO
--- old/ordered_namespace-2018.6.26/ordered_namespace.egg-info/PKG-INFO
2018-06-27 01:54:24.000000000 +0200
+++ new/ordered_namespace-2019.6.8/ordered_namespace.egg-info/PKG-INFO
2019-06-09 05:57:42.000000000 +0200
@@ -1,11 +1,11 @@
Metadata-Version: 1.0
Name: ordered-namespace
-Version: 2018.6.26
-Summary: An easy-to-use Python namespace class derived from OrderedDict,
including tab-completion
+Version: 2019.6.8
+Summary: An easy-to-use Python namespace class derived from OrderedDict,
includes tab-completion
Home-page: https://github.com/who8mylunch/OrderedNamespace
Author: Pierre V. Villeneuve
Author-email: [email protected]
License: MIT
Description: UNKNOWN
-Keywords: namespace,ordereddict,structure
+Keywords: namespace,ordereddict,structure,dotdict,tab-completion
Platform: UNKNOWN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ordered_namespace-2018.6.26/setup.py
new/ordered_namespace-2019.6.8/setup.py
--- old/ordered_namespace-2018.6.26/setup.py 2018-06-27 01:43:06.000000000
+0200
+++ new/ordered_namespace-2019.6.8/setup.py 2019-06-09 05:57:37.000000000
+0200
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
-version = '2018.6.26'
+version = '2019.6.8'
setup(
name='ordered_namespace',
@@ -11,8 +11,8 @@
version=version,
author='Pierre V. Villeneuve',
author_email='[email protected]',
- description='An easy-to-use Python namespace class derived from
OrderedDict, including tab-completion',
+ description='An easy-to-use Python namespace class derived from
OrderedDict, includes tab-completion',
url='https://github.com/who8mylunch/OrderedNamespace',
license='MIT',
- keywords=['namespace', 'ordereddict', 'structure'],
+ keywords=['namespace', 'ordereddict', 'structure', 'dotdict',
'tab-completion'],
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ordered_namespace-2018.6.26/test/test.py
new/ordered_namespace-2019.6.8/test/test.py
--- old/ordered_namespace-2018.6.26/test/test.py 2018-06-27
01:42:15.000000000 +0200
+++ new/ordered_namespace-2019.6.8/test/test.py 2019-06-09 05:42:22.000000000
+0200
@@ -2,6 +2,8 @@
from __future__ import division, print_function, unicode_literals,
absolute_import
import unittest
+import pickle
+from collections import OrderedDict
try:
import context
@@ -100,20 +102,40 @@
self.assertTrue(keys_test_1 == keys_test_2[::-1])
- def test_nested_dict_converted(self):
+ def test_nested_flag_set(self):
+ info = ons.Struct(nested=True)
+ self.assertTrue(info.__dict__['_nested'])
+
+ def test_nested_flag_not_set(self):
+ info = ons.Struct(nested=False)
+ self.assertFalse(info.__dict__['_nested'])
+
+ def test_nested_flag_default_not_set(self):
info = ons.Struct()
+ self.assertFalse(info.__dict__['_nested'])
+
+ def test_nested_dict_converted(self):
+ info = ons.Struct(nested=True)
nuts = {'a': [1, 2], 'X': 'hello'}
corn = {'b': [6, 9], 'Y': 'bye'}
info.AA = nuts
- info.AA.BB = corn
-
self.assertTrue(type(info.AA) == ons.Struct)
+
+ info.AA.BB = corn
self.assertTrue(type(info.AA.BB) == ons.Struct)
+ def test_not_nested_dict_converted(self):
+ info = ons.Struct(nested=False)
+
+ nuts = {'a': [1, 2], 'X': 'hello'}
+
+ info.AA = nuts
+ self.assertTrue(type(info.AA) == dict)
+
def test_nested_dict_update(self):
- info = ons.Struct()
+ info = ons.Struct(nested=True)
nuts = {'a': [1, 2], 'X': 'hello'}
corn = {'b': [6, 9], 'Y': 'bye', 'm': nuts}
@@ -126,32 +148,29 @@
self.assertTrue(type(info.CC.n.m) == ons.Struct)
def test_nested_dict_define(self):
-
nuts = {'a': [1, 2], 'X': 'hello'}
corn = {'b': [6, 9], 'Y': 'bye', 'm': nuts}
yikes = {'c': [6, 9], 'Z': 'hello', 'n': corn}
- info = ons.Struct(yikes)
+ info = ons.Struct(yikes, nested=True)
- # print(yikes.n.m)
- # print(type(yikes.n.m))
+ self.assertTrue(type(info.n) == ons.Struct)
self.assertTrue(type(info.n.m) == ons.Struct)
def test_nested_dict_list(self):
-
nuts = {'a': [1, 2], 'X': 'hello'}
corn = {'b': [6, 9], 'Y': 'bye'}
yikes = {'c': [6, 9], 'Z': 'hello'}
stuff = [nuts, corn, yikes]
- info = ons.Struct()
+ info = ons.Struct(nested=True)
info.S = stuff
self.assertTrue(type(info.S[0]) == ons.Struct)
def test_as_dict(self):
- info = ons.Struct()
+ info = ons.Struct(nested=True)
nuts = {'a': [1, 2], 'X': 'hello'}
corn = {'b': [6, 9], 'Y': 'bye'}
@@ -161,10 +180,53 @@
info = info.asdict()
- self.assertTrue(type(info) == dict)
- self.assertTrue(type(info['AA']) == dict)
- self.assertTrue(type(info['AA']['BB']) == dict)
+ self.assertTrue(type(info) == OrderedDict)
+ self.assertTrue(type(info['AA']) == OrderedDict)
+ self.assertTrue(type(info['AA']['BB']) == OrderedDict)
+
+
+
+class TestFancy(unittest.TestCase):
+ # def setUp(self):
+ # pass
+
+ # def tearDown(self):
+ # pass
+
+ def test_does_it_pickle(self):
+ info = ons.Struct()
+ info.A = [1, 2, 3, 4, 'A']
+
+ z = pickle.dumps(info)
+
+ def test_does_it_unpickle(self):
+ info = ons.Struct()
+ info.A = [1, 2, 3, 4, 'WW']
+
+ z = pickle.dumps(info)
+ anfo = pickle.loads(z)
+
+ def test_pickle_unpickle_keys(self):
+ info = ons.Struct()
+ info.A = [1, 2, 3, 4, 'WW']
+
+ z = pickle.dumps(info)
+ anfo = pickle.loads(z)
+
+ for k, v in info.items():
+ self.assertTrue(k in anfo)
+
+ def test_pickle_unpickle_value(self):
+ info = ons.Struct()
+ info.A = [1, 2, 3, 4, 'WW']
+ info.SS = 4
+ info.WWW = {'d': [1,2,3]}
+
+ z = pickle.dumps(info)
+ anfo = pickle.loads(z)
+ for k, v in info.items():
+ self.assertTrue(v == anfo[k])
#------------------------------------------------