Skip to main content

🎴 The decorator-decorator 🎴

Project description

🗃 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 1: a simple decorator with dek

TASK: write a decorator before that prints a function's name and its arguments before it executes.

With dek, it's a few lines:

import dek

@dek
def before(pfunc):
    print(pfunc)
    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:
#
# functools.partial(<function phone at 0x7fafa8072b00>, 32, four=3)
# Calling 64 9

pfunc is a functools.partial, which represents the function call that dek intercepted. Your code can call pfunc as often as you like, or add or change parameters.

Example 2: same, without dek

import functools

def before(func):
    @functools.wraps(func)
    def wrapped(*args, **kwargs):
        print(func, args, kwargs)
        return func(*args, **kwargs)

    return wrapped

With dek it's a bit less work, but the real advantage comes when you have a decorator with a parameter.

Example 3: a decorator with a single optional parameter

Write a decorator before that prints a function's name, arguments and a label before it executes.

With dek, it's a trivial change from the previous solution.

import dek

@dek
def before(pfunc, label='dull'):
    print(label, pfunc.func, *pfunc.args)
    return pfunc()

@before
def add(x, y):
    return x + y

@before(label='Exciting!')
def times(x, y):
    return x * y

print('Result', add(2, times(2, 3)))

# Prints:
#   Exciting! times 2 3
#   dull add 2 6
#   Result 8

Example 4: same, without dek

Without dek it's actual work that's easy to get wrong.

import functools

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

        return wrapped

    return functools.partial(before, label=label)

Example 5: Deferred mode

For finer control over function signatures there is deferred mode, which lets you select what sort of signature you want to expose with a wrapped function that you create.

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

    return wrapped

Example 6: Decorating a class

If you need to decorate methods on a class, there's a methods parameter to select which methods get decorated.

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 desires, 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 Documentation

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.5.0.tar.gz (3.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dek-1.5.0-py3-none-any.whl (5.7 kB view details)

Uploaded Python 3

File details

Details for the file dek-1.5.0.tar.gz.

File metadata

  • Download URL: dek-1.5.0.tar.gz
  • Upload date:
  • Size: 3.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for dek-1.5.0.tar.gz
Algorithm Hash digest
SHA256 e6bb54a9cd57f5d6676aa41e6e23a3877f95ccda91b21ad6d498dad2a508905d
MD5 367dd451ab57505493038f478c4bb474
BLAKE2b-256 8b07fc3f63620cc90a994d8e58bd12db984d8382ada6e95b2130f6fac35ebc66

See more details on using hashes here.

File details

Details for the file dek-1.5.0-py3-none-any.whl.

File metadata

  • Download URL: dek-1.5.0-py3-none-any.whl
  • Upload date:
  • Size: 5.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for dek-1.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c6303fdd730fcc98f67430672a30b6d80ca27de2bf36f62df0608bcbafc72363
MD5 9efb7b9d2f9fffb5ca56f5e94d7947b6
BLAKE2b-256 bbeb10c83662ee3a2af4c5423adc86663e428283c2c3c996cd249296a43dcb87

See more details on using hashes here.

Supported by

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