Metadata-Version: 2.1
Name: dek
Version: 1.0.2
Summary: 🎴 dek: the decorator-decorator 🎴
License: MIT
Author: Tom Ritchford
Author-email: tom@swirly.com
Requires-Python: >=3.7,<4.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Requires-Dist: xmod (>=1.3.2,<2.0.0)
Description-Content-Type: text/x-rst

🗃 dek - the decorator-decorator 🗃
======================================================

``dek`` decorates your decorators to diminish defects and drudgery.

Writing a Python decorator which takes no parameters isn't hard.

But writing a decorator with parameters is less easy - and more work
if you want to decorate classes, like ``unittest.mock.patch`` does.

``dek`` is a decorator for decorators that does this deftly with a
single tiny function.

EXAMPLE
---------

Write a decorator ``before`` that prints a function's arguments with a
label before it executes.

With ``dek``, it's a few lines:

.. code-block:: python

    import dek

    @dek
    def before(pfunc, label='hey:'):
        print(label, pfunc.func.__name__)
        return pfunc()

    # Done! To use your new decorator:

    @before
    def phone(two, four=4):
        print('Calling', two + two, four * four)

    one(32, four=3)

    # That prints something like:
    #
    # hey: functools.partial(<function phone at 0x7fafa8072b00>, 32, four=3)
    # Calling 64 9

``pfunc`` is a ``functools.partial`` that represents the call the decorator
decorator intercepted.

Without ``dek`` it's actual work:

.. code-block:: python

    import functools

    def before(func=None, label='label'):
        if func:
            @functools.wraps(func)
            def wrapped(*args, **kwargs):
                print(label, args, kwargs)
                return func(*args, **kwargs)

            return wrapped

        return functools.partial(before, label=label)


For finer control over function signatures there is deferred mode:

.. code-block:: python

    @dek(defer=True)
    def before(func, label='debug'):
        def wrapped(foo, bar):
            print(label, foo, bar)
            return func(foo, bar)

        return wrapped

And there's a ``methods`` setting that lets your decorator work well
on classes, much like ``unittest.mock.patch`` does.

.. code-block:: python

    import dek

    @dek(methods='test')
    def before(pfunc):
        print('HERE', *pfunc.args)
        return pfunc()

    @before
    class Class:
        def test_one(self):
            return 1

        def test_two(self):
            return 2

        def three(self):  # This won't get decorated
            return 1


    # Test at the command line:
    >>> cl = Class()
    >>> cl.test_one(), cl.test_two(), cl.three()
    HERE 1
    HERE 2
    (1, 2, 3)

NOTES:

`This article <https://medium.com/p/1277a9ed34dc/>`_ talks more about
decorators that take parameters and about ``dek`` in general.

For your advanced decorator problems, the PyPi module
`decorator <https://github.com/micheles/decorator/blob/master/docs/documentation.md>`_ does not duplicate duties that ``dek`` does, but does
pretty anything else you could conceive of in a decorator library.

API
---

``dek()``
~~~~~~~~~

.. code-block:: python

  dek(
       decorator,
       defer=False,
       methods=None,
  )

(`dek.py, 126-267 <https://github.com/rec/dek/blob/master/dek.py#L126-L267>`_)

Decorate a decorator so it works with or without parameters and
can decorate all the members of a class.

ARGUMENTS
  decorator
    The function being decorated

  defer
    Switch between "simple" and "defer" modes

  methods
    What to do with class methods when wrapping a class

dek has two modes, simple and deferred.  Simple mode, the default,
is less work but offers less control.

In **simple mode** the trivial decorator, the decorator that does nothing,
is trivial to write:

.. code-block:: python

   @dek
   def trivial(pfunc):
       return pfunc()

In this mode, ``decorator``'s first argument is ``pfunc``,
a ``functools.partial()`` which bundles the original function called
together with its arguments.

Decorators with parameters aren't much harder:

.. code-block:: python

   @dek
   def before(pfunc, label='debug'):
       print(label, pfunc)
       return pfunc()

   @before
   def do_stuff(a, b='default'):
      # do stuff

   do_stuff(1)
   # also prints 'debug do_stuff 1'

----------------

In **deferred mode**, ``decorator`` is a function that returns a function
that does the work.  This is more code but more flexible.

.. code-block:: python

   @dek(defer=True)
   def trivial(func):
       def wrapper(*args, **kwargs):
           return func(*args, **kwargs)

       return wrapper

   @dek(defer=True)
   def before(func, label='label'):
       def wrapper(foo, bar):
           print(label, foo, bar)
           return func(foo, bar)

       return wrapper

--------

The ``methods`` parameter describe how classes are decorated.

If ``methods`` is ``None`` then classes are decorated like any callable.

If ``methods`` is _not_ ``None``, then class methods are decorated
instead of the class itself:

* If ``methods`` is a string, then only methods whose names start
  with that string are decorated (which means that if ``methods`` is
  the empty string, then all methods are decorated).

* If ``methods`` is a callable, then only methods that return true when
  passed to the callable are decorated.

* If ``methods`` is ``True``, then only public, non-magic methods - methods
  whose names do *not* start with ``_`` - are decorated.

* If ``methods`` is ``False``, then methods are not decorated (and neither
  are classes).

(automatically generated by `doks <https://github.com/rec/doks/>`_ on 2022-11-24T17:33:06.304331)

