From 04bb6454ac4f7560759ec1a3e15756a5485067ac Mon Sep 17 00:00:00 2001 From: Michele Simionato Date: Sun, 4 Apr 2021 07:05:15 +0200 Subject: Restored old semantic and added kwsyntax flag --- src/tests/documentation.py | 117 +++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 56 deletions(-) (limited to 'src/tests/documentation.py') diff --git a/src/tests/documentation.py b/src/tests/documentation.py index 889f97f..ad8818c 100644 --- a/src/tests/documentation.py +++ b/src/tests/documentation.py @@ -36,16 +36,15 @@ versions back to 2.6; versions 3.X are able to support even Python 2.5 and What's New in version 5 ----------------------- -There are no new features in version 5 of the decorator module, -except a simplification of the code base made possible by dropping -support for Python releases older than 3.5 (from that version -the Signature object works well enough that it is possible to fix the -signature of a decorated function without resorting to "exec" tricks). -The simplification gives a very neat advantage: in case of exceptions -raised in decorated functions the traceback is nicer than it used to be. -That counts as a new feature in my book ;-) -There is also a change of logic that breaks some decorators, see the section -about caveats and limitations. +Version 5 of the decorator module features a major simplification of +the code base made possible by dropping support for Python releases +older than 3.5. From that version the Signature object works well +enough that it is possible to fix the signature of a decorated +function without resorting to "exec" tricks. The simplification +has a very neat advantage: in case of exceptions raised in decorated +functions the traceback is nicer than it used to be. Moreover, it is +now possible to mimic the behavior of decorators defined with +``functool.wraps``: see the section about the ``kw_syntax`` flag below. What's New in version 4 ----------------------- @@ -374,6 +373,52 @@ calling func with args (), {} ``` +Mimicking the behavior of functools.wrap +---------------------------------------- + +Often people are confused by the decorator module since, contrarily +to ``functools.wraps`` in the standard library, it tries very hard +to keep the semantic of the arguments: in particular, positional arguments stay +positional even if they are called with the keyword argument syntax. +An example will make the issue clear: + +$$chatty + +$$printsum + +In this example ``x`` and ``y`` are positional arguments (with defaults). +It does not matter if the user calls them as named arguments, they will +stay inside the ``args`` tuple and not inside the ``kwargs`` dictionary +inside the caller: + +```python +>>> printsum(y=2, x=1) +(1, 2) {} +3 + +``` + +This is quite different from the behavior of ``functools.wraps``; if you +define the decorator as follows + +$$chattywrapper + +you will see that calling ``printsum`` with named arguments will pass +such arguments to ``kwargs``, while ``args`` will be the empty tuple. +Since version 5 of the decorator module it is possible to mimic that +behavior by using the ``kwsyntax`` flag: + +$$printsum2 + +Here is how it works: + +```python +>>> printsum2(y=2, x=1) +() {'y': 2, 'x': 1} +3 + +``` + Decorator factories ------------------------------------------- @@ -1105,50 +1150,6 @@ not use any cache, whereas the ``singledispatch`` implementation does. Caveats and limitations ------------------------------------------- -Version 5.X breaks compatibility with the past, by making decorators -more similar to the ones that can be defined with ``functools.wraps``. -An example will make the issue clear: - -$$chatty - -$$printsum - -In this example ``x`` and ``y`` are positional arguments with defaults. -In previous versions of the decorator module -(< 5) a call to ``printsum()`` would have passed ``args==(1, 2)`` to -the caller, with an empty ``kwargs`` dictionary. In version 5.X instead -even ``args`` is empty: - -```python ->>> printsum() -() {} -3 - -``` -``args`` become non-empty only if you pass the arguments as positional - -```python ->>> printsum(1) -(1,) {} -3 - -``` -and not if you pass them as keyword arguments: - -```python ->>> printsum(x=1) -() {'x': 1} -3 - -``` -This can be pretty confusing since non-keyword arguments are passed as -keywork arguments, but it the way it works with ``functools.wraps`` and -the way many people expect it to work. You can play with - -$$chattywrapper - -and see that we are consistent indeed. - In the present implementation, decorators generated by ``decorator`` can only be used on user-defined Python functions, methods or coroutines. I have no interest in decorating generic callable objects. If you want to @@ -1799,17 +1800,21 @@ def operation2(): time.sleep(.1) -@decorator def chatty(func, *args, **kwargs): print(args, kwargs) return func(*args, **kwargs) -@chatty +@decorator(chatty) def printsum(x=1, y=2): print(x + y) +@decorator(chatty, kwsyntax=True) +def printsum2(x=1, y=2): + print(x + y) + + def chattywrapper(func): @functools.wraps(func) def wrapper(*args, **kwargs): -- cgit v1.2.1