Skip to main content

Hassle-free creation of decorators for functions and methods, OO-style.

Project description

Classy Decorators

PyPI version

Hassle-free creation of decorators for functions and methods, OO-style.

Features

  • One decorator to rule them all; it works on functions, methods, classmethods and staticmethods.
  • Easily define parameters with a dataclass-like annotated attribute syntax.
  • Runtime type-checking of decorator paremeters.
  • For decorators with all-default or no parameters, parentheses are optional: @spam() == @spam
  • Inheritance is supported.
  • Any decorator parameters and instance attributes are accessible (as copies) in bound methods as well; no need to worry about those pesky descriptors.
  • MyPy compatible and 100% test coverage.

Dependencies

Python 3.8 or 3.9.

Install

pip install classy-decorators

Usage

The following code can also be found in the examples.

Create a decorator by subclassing classy_decorators.Decorator. You can override the the decorated function or method using the __call_inner__ method (__call__ is meant for internal use only and should not be used for this).

Simple decorator

from classy_decorators import Decorator

class Double(Decorator):
    def __call_inner__(self, *args, **kwargs) -> float:
        return super().__call_inner__(*args, **kwargs) * 2

To see it in action, let's decorate a function:

@Double
def add(a, b):
    return a + b

assert add(7, 14) == 42

You can also decorate methods and classmethods:

class AddConstant:
    default_constant = 319

    def __init__(self, constant=default_constant):
        self.constant = constant

    @Double
    def add_to(self, value):
        return value + self.constant

    @Double
    @classmethod
    def add_default(cls, value):
        return value + cls.default_constant

assert AddConstant(7).add_to(14) == 42
assert AddConstant.add_default(14) == 666

Decorator parameters

Our Double decorator is pretty nice, but we can do better! So let's create a decorator that is able to multiply results by any number instead of only by 2:

class Multiply(Decorator):
    factor: int

    def __call_inner__(self, *args, **kwargs) -> float:
        return super().__call_inner__(*args, **kwargs) * self.factor

By simply setting the type-annotated factor attribute, we can use it as decorator parameter. If you are familiar with dataclasses, you can see that this is very similar to defining dataclass fields.

@Multiply(2)
def add_and_double(a, b):
    return a + b

@Multiply(factor=3)
def add_and_triple(a, b):
    return a + b

assert add_and_double(8, 15) == 46
assert add_and_triple(8, 15) == 69

Default parameters and inheritance

It's classy to be DRY, so let's combine our Double and Multiply decorators into one that multiplies by 2, unless specified otherwise:

class DoubleOrMultiply(Multiply):
    factor = 2

@DoubleOrMultiply
def add_and_double(a, b):
    return a + b

@DoubleOrMultiply(factor=3)
def add_and_triple(a, b):
    return a + b

assert add_and_double(7, 14) == 42
assert add_and_triple(8, 15) == 69

Advanced dataclass methods

The Decorator base class provided, aside from __call_inner__, two other interface methods you can override:

  • Decorator.__decorate__(self, **params), which is called just after a function method is decorated, with all decorator parameter values or defaults as keyword arguments, i.e. DoubleOrMultiply.__decorate__(self, factor: int = 2).
  • Decorator.__bind__(self, instance_or_class), which is called when a method (not for functions), is bound to an instance, or when a class/static method is bound to a class.

Additionally, these properties can be used for figuring out what's been decorated:

  • is_function
  • is_method; either an instance, class- or static method
  • is_instancemethod
  • is_classmethod
  • is_staticmethod

And for methods, is_bound and is_unbound are provided.

If you're looking for the original wrapped function, you can find it at __func__.


Classy, eh?

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

classy-decorators-1.1.0.tar.gz (10.3 kB view details)

Uploaded Source

Built Distribution

classy_decorators-1.1.0-py3-none-any.whl (22.5 kB view details)

Uploaded Python 3

File details

Details for the file classy-decorators-1.1.0.tar.gz.

File metadata

  • Download URL: classy-decorators-1.1.0.tar.gz
  • Upload date:
  • Size: 10.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.22.0 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.52.0 CPython/3.8.5

File hashes

Hashes for classy-decorators-1.1.0.tar.gz
Algorithm Hash digest
SHA256 1cb7fa43ff6434220a102352d07b269cfeceebc8c4eee9084797e600ff1ea097
MD5 a358fde841a3657a2bc8f6f68f0c8975
BLAKE2b-256 48cba68234891ed40d1632f92e8c3c71abb74a17e76645a715d0186db1a804d4

See more details on using hashes here.

File details

Details for the file classy_decorators-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: classy_decorators-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 22.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.22.0 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.52.0 CPython/3.8.5

File hashes

Hashes for classy_decorators-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 91e62cc5a2eaf6238416c834f20c46bf21f7fce4601494952486e555c7a9faa1
MD5 6033d30ad2480ac5672c35de772a4906
BLAKE2b-256 675c0743f2cf39e0e842fc5887fe9ecd67a627f459ae4c82155030726b4bfc41

See more details on using hashes here.

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