Hello community, here is the log from the commit of package python-decorator for openSUSE:Factory checked in at 2018-04-23 15:24:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-decorator (Old) and /work/SRC/openSUSE:Factory/.python-decorator.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-decorator" Mon Apr 23 15:24:50 2018 rev:17 rq:597436 version:4.3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-decorator/python-decorator.changes 2018-01-19 11:47:23.212118022 +0100 +++ /work/SRC/openSUSE:Factory/.python-decorator.new/python-decorator.changes 2018-04-23 15:24:51.796724049 +0200 @@ -1,0 +2,15 @@ +Tue Apr 17 11:05:41 UTC 2018 - jeng...@inai.de + +- Ensure neutrality of description. + +------------------------------------------------------------------- +Tue Apr 17 01:52:09 UTC 2018 - a...@gmx.de + +- update to version 4.3.0: + * Extended the decorator family facility to work with positional + arguments and updated the documentation. Removed + decorator.getargspec and provided decorator.getfullargspec + instead. This is convenient for users of Python 2.6/2.7, the + others can just use inspect.getfullargspec. + +------------------------------------------------------------------- Old: ---- decorator-4.2.1.tar.gz New: ---- decorator-4.3.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-decorator.spec ++++++ --- /var/tmp/diff_new_pack.PXav5r/_old 2018-04-23 15:24:52.524697607 +0200 +++ /var/tmp/diff_new_pack.PXav5r/_new 2018-04-23 15:24:52.524697607 +0200 @@ -18,35 +18,29 @@ # Please submit bugfixes or comments via http://bugs.opensuse.org/ # - %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-decorator -Version: 4.2.1 +Version: 4.3.0 Release: 0 -Url: http://pypi.python.org/pypi/decorator -Summary: Better living through Python with decorators +Summary: Non-nested signature-retaining Python decorators License: BSD-2-Clause Group: Development/Languages/Python +URL: http://pypi.python.org/pypi/decorator Source: https://files.pythonhosted.org/packages/source/d/decorator/decorator-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: %{python_module devel} BuildRequires: %{python_module setuptools} BuildRequires: python-rpm-macros BuildArch: noarch - %python_subpackages %description -As of now, writing custom decorators correctly requires some experience and it -is not as easy as it could be. For instance, typical implementations of -decorators involve nested functions, and we all know that flat is better than -nested. Moreover, typical implementations of decorators do not preserve the -signature of decorated functions, thus confusing both documentation tools and -developers. - -The aim of the decorator module it to simplify the usage of decorators for the -average programmer, and to popularize decorators usage giving examples of -useful decorators, such as memoize, tracing, redirecting_stdout, locked, etc. +Typical implementations of Python decorators involve nested +functions, and do not preserve the signature of decorated functions, +thus can be confusing to both developers and documentation tools. + +This module changes the usage of decorators for the average +programmer so as to make decorators such as memoize, tracing, +redirecting_stdout, locked, etc. more accessible. %prep %setup -q -n decorator-%{version} @@ -59,8 +53,8 @@ %python_install %files %{python_files} -%defattr(-,root,root,-) -%doc CHANGES.md LICENSE.txt docs/README.rst +%license LICENSE.txt +%doc CHANGES.md docs/README.rst %{python_sitelib}/decorator.py* %pycache_only %{python_sitelib}/__pycache__/decorator.*.py* %{python_sitelib}/decorator-%{version}-py*.egg-info ++++++ decorator-4.2.1.tar.gz -> decorator-4.3.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-4.2.1/CHANGES.md new/decorator-4.3.0/CHANGES.md --- old/decorator-4.2.1/CHANGES.md 2018-01-14 11:01:55.000000000 +0100 +++ new/decorator-4.3.0/CHANGES.md 2018-04-15 14:45:04.000000000 +0200 @@ -3,9 +3,17 @@ ## Unreleased +## 4.3.0 (2018-04-15) + +Extended the decorator family facility to work with positional +arguments and updated the documentation. Removed +`decorator.getargspec` and provided `decorator.getfullargspec` +instead. This is convenient for users of Python 2.6/2.7, the others +can just use `inspect.getfullargspec`. + ## 4.2.1 (2018-01-14) -Fixed a regression breaking IPython and discovered by https://github.com/spapini +Fixed a regression breaking IPython reported by https://github.com/spapini . ## 4.2.0 (2018-01-14) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-4.2.1/PKG-INFO new/decorator-4.3.0/PKG-INFO --- old/decorator-4.2.1/PKG-INFO 2018-01-14 11:12:16.000000000 +0100 +++ new/decorator-4.3.0/PKG-INFO 2018-04-15 14:50:29.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: decorator -Version: 4.2.1 +Version: 4.3.0 Summary: Better living through Python with decorators Home-page: https://github.com/micheles/decorator Author: Michele Simionato diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-4.2.1/README.md new/decorator-4.3.0/README.md --- old/decorator-4.2.1/README.md 1970-01-01 01:00:00.000000000 +0100 +++ new/decorator-4.3.0/README.md 2015-07-28 05:49:22.000000000 +0200 @@ -0,0 +1,3 @@ +[See the real README](docs/README.rst) + +[![Build Status](https://secure.travis-ci.org/micheles/decorator.png?branch=master)](https://travis-ci.org/micheles/decorator) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-4.2.1/setup.cfg new/decorator-4.3.0/setup.cfg --- old/decorator-4.2.1/setup.cfg 2018-01-14 11:12:16.000000000 +0100 +++ new/decorator-4.3.0/setup.cfg 2018-04-15 14:50:29.000000000 +0200 @@ -7,5 +7,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-4.2.1/src/decorator.egg-info/PKG-INFO new/decorator-4.3.0/src/decorator.egg-info/PKG-INFO --- old/decorator-4.2.1/src/decorator.egg-info/PKG-INFO 2018-01-14 11:12:16.000000000 +0100 +++ new/decorator-4.3.0/src/decorator.egg-info/PKG-INFO 2018-04-15 14:50:28.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: decorator -Version: 4.2.1 +Version: 4.3.0 Summary: Better living through Python with decorators Home-page: https://github.com/micheles/decorator Author: Michele Simionato diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-4.2.1/src/decorator.egg-info/SOURCES.txt new/decorator-4.3.0/src/decorator.egg-info/SOURCES.txt --- old/decorator-4.2.1/src/decorator.egg-info/SOURCES.txt 2018-01-14 11:12:16.000000000 +0100 +++ new/decorator-4.3.0/src/decorator.egg-info/SOURCES.txt 2018-04-15 14:50:29.000000000 +0200 @@ -1,6 +1,7 @@ CHANGES.md LICENSE.txt MANIFEST.in +README.md performance.sh setup.cfg setup.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-4.2.1/src/decorator.py new/decorator-4.3.0/src/decorator.py --- old/decorator-4.2.1/src/decorator.py 2018-01-14 11:00:21.000000000 +0100 +++ new/decorator-4.3.0/src/decorator.py 2018-04-15 14:45:04.000000000 +0200 @@ -40,7 +40,7 @@ import itertools import collections -__version__ = '4.2.1' +__version__ = '4.3.0' if sys.version >= '3': from inspect import getfullargspec @@ -50,11 +50,11 @@ else: FullArgSpec = collections.namedtuple( 'FullArgSpec', 'args varargs varkw defaults ' - 'kwonlyargs kwonlydefaults') + 'kwonlyargs kwonlydefaults annotations') def getfullargspec(f): "A quick and dirty replacement for getfullargspec for Python 2.X" - return FullArgSpec._make(inspect.getargspec(f) + ([], None)) + return FullArgSpec._make(inspect.getargspec(f) + ([], None, {})) def get_init(cls): return cls.__init__.__func__ @@ -66,16 +66,6 @@ def iscoroutinefunction(f): return False -# getargspec has been deprecated in Python 3.5 -ArgSpec = collections.namedtuple( - 'ArgSpec', 'args varargs varkw defaults') - - -def getargspec(f): - """A replacement for inspect.getargspec""" - spec = getfullargspec(f) - return ArgSpec(spec.args, spec.varargs, spec.varkw, spec.defaults) - DEF = re.compile(r'\s*def\s*([_\w][_\w\d]*)\s*\(') @@ -187,7 +177,7 @@ try: code = compile(src, filename, 'single') exec(code, evaldict) - except: + except Exception: print('Error in generated code:', file=sys.stderr) print(src, file=sys.stderr) raise @@ -271,14 +261,15 @@ doc = caller.__call__.__doc__ evaldict = dict(_call=caller, _decorate_=decorate) dec = FunctionMaker.create( - '%s(func, %s)' % (name, defaultargs), + '%s(%s func)' % (name, defaultargs), 'if func is None: return lambda func: _decorate_(func, _call, (%s))\n' 'return _decorate_(func, _call, (%s))' % (defaultargs, defaultargs), evaldict, doc=doc, module=caller.__module__, __wrapped__=caller) if defaults: - dec.__defaults__ = (None,) + defaults + dec.__defaults__ = defaults + (None,) return dec + # ####################### contextmanager ####################### # try: # Python >= 3.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-4.2.1/src/tests/documentation.py new/decorator-4.3.0/src/tests/documentation.py --- old/decorator-4.2.1/src/tests/documentation.py 2018-01-14 10:38:21.000000000 +0100 +++ new/decorator-4.3.0/src/tests/documentation.py 2018-04-15 14:48:08.000000000 +0200 @@ -185,9 +185,9 @@ .. code-block:: python - >>> from decorator import getargspec # akin to inspect.getargspec - >>> print(getargspec(f1)) - ArgSpec(args=[], varargs='args', varkw='kw', defaults=None) + >>> from decorator import getfullargspec + >>> print(getfullargspec(f1)) + FullArgSpec(args=[], varargs='args', varkw='kw', defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) This means that introspection tools (like ``pydoc``) will give false information about the signature of ``f1`` -- unless you are using @@ -202,10 +202,9 @@ ... TypeError: f1() takes exactly 1 positional argument (2 given) -Notice that ``inspect.getargspec`` and ``inspect.getfullargspec`` -will give the wrong signature. This even occurs in Python 3.5, -although both functions were deprecated in that release. - +Notice that ``inspect.getfullargspec`` +will give the wrong signature, even in the latest Python, i.e. version 3.6 +at the time of writing. The solution ----------------------------------------- @@ -259,8 +258,8 @@ .. code-block:: python - >>> print(getargspec(heavy_computation)) - ArgSpec(args=[], varargs=None, varkw=None, defaults=None) + >>> print(getfullargspec(heavy_computation)) + FullArgSpec(args=[], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) A ``trace`` decorator ------------------------------------------------------ @@ -291,8 +290,8 @@ .. code-block:: python - >>> print(getargspec(f1)) - ArgSpec(args=['x'], varargs=None, varkw=None, defaults=None) + >>> print(getfullargspec(f1)) + FullArgSpec(args=['x'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) The decorator works with functions of any signature: @@ -305,8 +304,8 @@ >>> f(0, 3) calling f with args (0, 3, 2), {} - >>> print(getargspec(f)) - ArgSpec(args=['x', 'y', 'z'], varargs='args', varkw='kw', defaults=(1, 2)) + >>> print(getfullargspec(f)) + FullArgSpec(args=['x', 'y', 'z'], varargs='args', varkw='kw', defaults=(1, 2), kwonlyargs=[], kwonlydefaults=None, annotations={}) $FUNCTION_ANNOTATIONS @@ -396,7 +395,7 @@ The example below will show how it works in practice. -``blocking`` +Decorator factories ------------------------------------------- Sometimes one has to deal with blocking resources, such as ``stdin``. @@ -413,7 +412,7 @@ .. code-block:: python - >>> @blocking(msg="Please wait ...") + >>> @blocking("Please wait ...") ... def read_data(): ... time.sleep(3) # simulate a blocking resource ... return "some data" @@ -433,6 +432,26 @@ >>> print(read_data()) some data +Decorator factories are most useful to framework builders. Here is an example +that gives an idea of how you could manage permissions in a framework: + +$$Action + +where ``restricted`` is a decorator factory defined as follows + +$$restricted + +In general a decorator factory has a signature + +.. code-block:: python + + def decfactory(func, par1=default1, .., parN=defaultN, *a, **k): + ... + +Each parameter must have a default, so that ``decfactory`` can work +as an alias for ``decfactory()``, i.e. the decorator in which all parameters +have the default value. + ``decorator(cls)`` -------------------------------------------- @@ -609,7 +628,7 @@ an instance of ``FunctionMaker`` is created with the attributes ``args``, ``varargs``, ``keywords``, and ``defaults``. (These mirror the return values of the standard library's - ``inspect.getargspec``.) + ``inspect.getfullargspec``.) - For each item in ``args`` (a list of strings of the names of all required arguments), an attribute ``arg0``, ``arg1``, ..., ``argN`` is also generated. @@ -625,8 +644,8 @@ >>> f1 = FunctionMaker.create( ... 'f1(a, b)', 'f(a, b)', dict(f=f), addsource=True, defaults=(None,)) - >>> print(getargspec(f1)) - ArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(None,)) + >>> print(getfullargspec(f1)) + FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={}) Getting the source code @@ -1322,7 +1341,7 @@ In order to introspect functions with annotations, one needs the utility ``inspect.getfullargspec`` (introduced in Python 3, then -deprecated in Python 3.5, in favor of ``inspect.signature``): +deprecated in Python 3.5, then undeprecated in Python 3.6): .. code-block:: python @@ -1496,47 +1515,42 @@ "Will be able to delete pages too" -def get_userclass(): - return User - - class PermissionError(Exception): - pass - - -def restricted(user_class): - def restricted(func, *args, **kw): - "Restrict access to a given class of users" - userclass = get_userclass() - if issubclass(userclass, user_class): - return func(*args, **kw) - else: - raise PermissionError( - '%s does not have the permission to run %s!' - % (userclass.__name__, func.__name__)) - return decorator(restricted) - - -class Action(object): """ >>> a = Action() + >>> a.user = User() >>> a.view() # ok >>> a.insert() # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... PermissionError: User does not have the permission to run insert! """ + + +@decorator +def restricted(func, user_class=User, *args, **kw): + "Restrict access to a given class of users" + self = args[0] + if isinstance(self.user, user_class): + return func(*args, **kw) + else: + raise PermissionError( + '%s does not have the permission to run %s!' + % (self.user, func.__name__)) + + +class Action(object): @restricted(User) def view(self): - pass + "Any user can view objects" @restricted(PowerUser) def insert(self): - pass + "Only power users can insert objects" @restricted(Admin) def delete(self): - pass + "Only the admin can delete objects" class TailRecursive(object): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/decorator-4.2.1/src/tests/test.py new/decorator-4.3.0/src/tests/test.py --- old/decorator-4.2.1/src/tests/test.py 2018-01-14 10:52:32.000000000 +0100 +++ new/decorator-4.3.0/src/tests/test.py 2018-04-15 14:45:04.000000000 +0200 @@ -126,6 +126,17 @@ return method(app) catch_config_error(lambda app: None) + def test_add1(self): + # similar to what IPython is doing in traitlets.config.application + @decorator + def add(func, const=1, *args, **kwargs): + return const + func(*args, **kwargs) + + def f(x): + return x + self.assertEqual(add(2, f)(0), 2) + + # ################### test dispatch_on ############################# # # adapted from test_functools in Python 3.5 singledispatch = dispatch_on('obj')