Hello community, here is the log from the commit of package python-tri.declarative for openSUSE:Factory checked in at 2020-04-18 00:32:33 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-tri.declarative (Old) and /work/SRC/openSUSE:Factory/.python-tri.declarative.new.2738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-tri.declarative" Sat Apr 18 00:32:33 2020 rev:3 rq:794885 version:5.3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-tri.declarative/python-tri.declarative.changes 2020-03-11 18:55:44.855685645 +0100 +++ /work/SRC/openSUSE:Factory/.python-tri.declarative.new.2738/python-tri.declarative.changes 2020-04-18 00:33:43.062460733 +0200 @@ -1,0 +2,7 @@ +Fri Apr 17 11:19:26 UTC 2020 - pgaj...@suse.com + +- version update to 5.3.0 + * Enable `@class_shortcut` to override baseclass shortcuts with the same name. + * Fix `@with_meta` failing on method declarations with `@staticmethod` declaration + +------------------------------------------------------------------- Old: ---- tri.declarative-5.2.0.tar.gz New: ---- tri.declarative-5.3.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-tri.declarative.spec ++++++ --- /var/tmp/diff_new_pack.bN72qq/_old 2020-04-18 00:33:43.846462356 +0200 +++ /var/tmp/diff_new_pack.bN72qq/_new 2020-04-18 00:33:43.850462365 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-tri.declarative -Version: 5.2.0 +Version: 5.3.0 Release: 0 Summary: Python class decorators in the style of Django model classes License: BSD-3-Clause ++++++ tri.declarative-5.2.0.tar.gz -> tri.declarative-5.3.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tri.declarative-5.2.0/HISTORY.rst new/tri.declarative-5.3.0/HISTORY.rst --- old/tri.declarative-5.2.0/HISTORY.rst 2020-02-28 08:37:57.000000000 +0100 +++ new/tri.declarative-5.3.0/HISTORY.rst 2020-04-01 14:58:16.000000000 +0200 @@ -1,6 +1,14 @@ Changelog --------- +5.3.0 (2020-04-01) +------------------ + +* Enable `@class_shortcut` to override baseclass shortcuts with the same name. + +* Fix `@with_meta` failing on method declarations with `@staticmethod` declaration + + 5.2.0 (2020-02-28) ------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tri.declarative-5.2.0/Makefile new/tri.declarative-5.3.0/Makefile --- old/tri.declarative-5.2.0/Makefile 2020-02-28 08:37:57.000000000 +0100 +++ new/tri.declarative-5.3.0/Makefile 2020-04-01 14:58:16.000000000 +0200 @@ -1,5 +1,7 @@ .PHONY: clean-pyc clean-build docs clean lint test coverage docs dist tag release-check +PYTHON ?= python + help: @echo "clean-build - remove build artifacts" @echo "clean-pyc - remove Python file artifacts" @@ -41,12 +43,12 @@ tox -e docs dist: clean - python setup.py sdist - python setup.py bdist_wheel + $(PYTHON) setup.py sdist bdist_wheel ls -l dist tag: - python setup.py tag + $(PYTHON) setup.py tag release-check: - python setup.py release_check + $(PYTHON) setup.py release_check + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tri.declarative-5.2.0/lib/tri_declarative/__init__.py new/tri.declarative-5.3.0/lib/tri_declarative/__init__.py --- old/tri.declarative-5.2.0/lib/tri_declarative/__init__.py 2020-02-28 08:37:57.000000000 +0100 +++ new/tri.declarative-5.3.0/lib/tri_declarative/__init__.py 2020-04-01 14:58:16.000000000 +0200 @@ -10,7 +10,7 @@ Struct, ) -__version__ = '5.2.0' +__version__ = '5.3.0' def with_meta(class_to_decorate=None, add_init_kwargs=True): @@ -48,8 +48,9 @@ merged_attributes = Namespace() for class_ in reversed(cls.mro()): if hasattr(class_, 'Meta'): - for key, value in class_.Meta.__dict__.items(): + for key in class_.Meta.__dict__: if not key.startswith('__'): + value = getattr(class_.Meta, key) merged_attributes.setitem_path(key, value) return merged_attributes @@ -398,6 +399,7 @@ class Namespace(Struct): + # noinspection PyMissingConstructor def __init__(self, *dicts, **kwargs): if dicts or kwargs: for mappings in list(dicts) + [kwargs]: @@ -494,23 +496,38 @@ def class_shortcut(*args, **defaults): def decorator(__target__): + @functools.wraps(__target__) @shortcut @dispatch( **defaults ) def class_shortcut_wrapper(cls, *args, **kwargs): call_target = kwargs.pop('call_target', None) + cls = kwargs.pop('_target_cls', cls) if call_target is None: setdefaults_path( kwargs, call_target__call_target__cls=cls, ) else: - setdefaults_path( - kwargs, - call_target__call_target=call_target, - call_target__call_target__cls=cls, - ) + if ( + isinstance(call_target, Namespace) + and __target__.__name__ == call_target.get('attribute', None) + ): + # Next call is to the same attribute name, but on the base class. + # We need to retain the cls value for later use. + setdefaults_path( + kwargs, + _target_cls=cls, + call_target__call_target=call_target, + call_target__call_target__cls=cls.__bases__[0] + ) + else: + setdefaults_path( + kwargs, + call_target__call_target=call_target, + call_target__call_target__cls=cls, + ) result = __target__(cls, *args, **kwargs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tri.declarative-5.2.0/tests/test_class_meta.py new/tri.declarative-5.3.0/tests/test_class_meta.py --- old/tri.declarative-5.2.0/tests/test_class_meta.py 2020-02-28 08:37:57.000000000 +0100 +++ new/tri.declarative-5.3.0/tests/test_class_meta.py 2020-04-01 14:58:16.000000000 +0200 @@ -26,6 +26,7 @@ def __init__(self, foo): assert foo == 'bar' + # noinspection PyArgumentList Test() @@ -52,6 +53,7 @@ def __init__(self, foo): assert foo == 'bar' + # noinspection PyArgumentList TestSubclass() @@ -65,6 +67,7 @@ class Meta: foo = 'bar' + # noinspection PyArgumentList TestSubclass() @@ -82,6 +85,7 @@ def __init__(self, foo): assert foo == 'baz' + # noinspection PyArgumentList TestSubclass() @@ -98,6 +102,7 @@ assert gapa == 'gapa' assert 'bar' in kwargs + # noinspection PyArgumentList Test('apa', gapa='gapa') @@ -110,6 +115,7 @@ def __init__(self, foo): assert foo == 'foo' + # noinspection PyArgumentList Test() @@ -160,6 +166,7 @@ pass with pytest.raises(TypeError) as e: + # noinspection PyArgumentList Test('foo', 'bar') assert 'Too many positional arguments' == str(e.value) @@ -175,6 +182,7 @@ def __init__(self, foo): assert 'bar' == foo + # noinspection PyArgumentList Test() @@ -220,3 +228,17 @@ foo__bar=17, foo__baz=42, ) + + +def test_meta_staticmethod(): + @with_meta + class Foo: + class Meta: + @staticmethod + def foo(bar): + return bar + + def __init__(self, **_): + pass + + assert Foo().get_meta().foo(17) == 17 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tri.declarative-5.2.0/tests/test_misc.py new/tri.declarative-5.3.0/tests/test_misc.py --- old/tri.declarative-5.2.0/tests/test_misc.py 2020-02-28 08:37:57.000000000 +0100 +++ new/tri.declarative-5.3.0/tests/test_misc.py 2020-04-01 14:58:16.000000000 +0200 @@ -792,6 +792,66 @@ assert Foo.shortcut2().kwargs == {'x': 17, 'y': 42} +def test_shortcut_to_superclass(): + class Foo: + def __init__(self, **kwargs): + self.kwargs = kwargs + + @classmethod + @class_shortcut( + x=17 + ) + def baz(cls, call_target, **kwargs): + return call_target(**kwargs) + + class Bar(Foo): + @classmethod + @class_shortcut( + call_target__attribute='baz', + y=42 + ) + def baz(cls, call_target, **kwargs): + return call_target(**kwargs) + + result = Bar.baz() + assert result.kwargs == dict(x=17, y=42) + assert isinstance(result, Bar) + + +def test_shortcut_to_superclass_two_calls(): + class Foo: + def __init__(self, **kwargs): + self.kwargs = kwargs + + @classmethod + @class_shortcut( + z=4711 + ) + def buzz(cls, call_target, **kwargs): + return call_target(**kwargs) + + @classmethod + @class_shortcut( + call_target__attribute='buzz', + x=17 + ) + def baz(cls, call_target, **kwargs): + return call_target(**kwargs) + + class Bar(Foo): + @classmethod + @class_shortcut( + call_target__attribute='baz', + y=42 + ) + def baz(cls, call_target, **kwargs): + return call_target(**kwargs) + + result = Bar.baz() + assert result.kwargs == dict(x=17, y=42, z=4711) + assert isinstance(result, Bar) + + def test_namespace_call(): def bar(arg): return arg @@ -817,6 +877,21 @@ assert f() == 'arg' +def test_namespace_class_call_override_default(): + class Foo: + @staticmethod + def bar(arg): + return arg + + f = Namespace( + call_target__call_target=lambda arg: "not arg", + call_target__cls=Foo, + call_target__attribute='bar', + arg='arg' + ) + assert f() == 'not arg' + + def test_namespace_call_attribute_missing(): class Foo: def __init__(self, arg):