Skip to main content

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

for better runtime type checking:

pip install classy-decorators[typeguard]

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?

Metadata

Release files for classy-decorators 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for classy-decorators 1.2.0
File Size Uploaded Provenance Actions
classy-decorators-1.2.0.tar.gz 11.1 kB Without provenance Details for classy-decorators-1.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for classy-decorators 1.2.0
File Interpreter ABI Platform Actions
classy_decorators-1.2.0-py3-none-any.whl Python 3 none any Details for classy_decorators-1.2.0-py3-none-any.whl

Total release size: 33.3 kB

Release files / classy-decorators-1.2.0.tar.gz

Download URL classy-decorators-1.2.0.tar.gz
Size 11.1 kB
Tags Source
SHA-256 checksum
How to use checksums
dd9b76ec37ba39e10c94f350b33eaff84e22db734e6d4b07766368f06c40b328
BLAKE2b-256 checksum
How to use checksums
8da1bfbe06e36fbdc59966e95c6298df8cdab7e7a8fac5693eabcc983538ae5f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.53.0 CPython/3.8.6

Release files / classy_decorators-1.2.0-py3-none-any.whl

Download URL classy_decorators-1.2.0-py3-none-any.whl
Size 22.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e4aec507d797f235bebcb7647832b212f23f48dcb8cecddc3f06f013b4f13a05
BLAKE2b-256 checksum
How to use checksums
e127190d4734a767da0a1d77ffd991df612a9f12841c75ec80f7b8e21ad83fb8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.2.0 pkginfo/1.6.1 requests/2.25.0 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.53.0 CPython/3.8.6

Security for classy-decorators 1.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page