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 <tchva...@suse.com> + +- 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: pierre.villene...@gmail.com 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: pierre.villene...@gmail.com 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='pierre.villene...@gmail.com', - 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]) #------------------------------------------------