Skip to main content

🎴 dek: the decorator-decorator 🎴

Project description

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:

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:

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:

@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.

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 talks more about decorators that take parameters and about dek in general.

For your advanced decorator problems, the PyPi module decorator does not duplicate duties that dek does, but does pretty anything else you could conceive of in a decorator library.

API

dek()

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

(dek.py, 126-267)

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:

@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:

@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.

@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 on 2022-11-24T17:33:06.304331)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dek-1.0.2.tar.gz (5.3 kB view hashes)

Uploaded Source

Built Distribution

dek-1.0.2-py3-none-any.whl (6.2 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page