Skip to main content

artdeco

artdeco is a tiny, zero-dependency Python library that makes writing decorator factories effortless: works with plain functions and instance methods, for both synchronous and asynchronous code, and for stacking multiple decorators in any combination.

You write one function. artdeco turns it into a fully-featured, stackable decorator factory.

Why artdeco?

Writing a production-quality decorator factory from scratch is surprisingly tedious:

  • You need a descriptor (__get__) to keep self working on methods.
  • You need functools.wraps to preserve __name__, __doc__, etc.
  • Handling async def requires extra work, since iscoroutinefunction stops working once you wrap an async function without explicitly marking the wrapper.
  • You need to guard against accidentally mixing sync/async.
  • You want to stack multiple decorators on the same function.

artdeco handles all of that for you.

Features

  • Works on methods: decorators preserve descriptor binding so self is always correct.
  • Sync and async: one API covers both; write async def to get an async decorator factory.
  • Stackable: apply as many decorators as you like; ordering is preserved.
  • Inspect call internals: call is a plain functools.partial, giving you access to call.func, call.args, and call.keywords at decoration time.
  • Misuse detection: applying a sync decorator to an async def (or vice versa) raises a clear DecorationError.
  • Fully typed: ships with py.typed; works with Pyright and mypy.
  • Zero dependencies: pure Python 3.12+, uses only the standard library.

Installation

pip install py-artdeco

Quick Start

Synchronous decorator factory

from artdeco import decorator


@decorator()
def log(call, prefix: str):
    print(prefix, "calling")
    return call()


@log("DEBUG:")
def add(a: int, b: int) -> int:
    return a + b


assert add(1, 2) == 3  # prints "DEBUG: calling"

Async decorator factory

from artdeco import decorator


@decorator()
async def traced(call, prefix: str):
    print(prefix, "before")
    result = await call()
    print(prefix, "after")
    return result


@traced("ASYNC")
async def work(x: int) -> int:
    return x * 2

Works seamlessly on instance methods

from artdeco import decorator


@decorator()
def retry(call, times: int):
    for _ in range(times):
        try:
            return call()
        except Exception:
            pass
    raise RuntimeError("all retries failed")


class Client:
    @retry(times=3)
    def fetch(self) -> str:        # self is bound correctly
        ...

Stack multiple decorators

from artdeco import decorator


@decorator()
def log(call, label: str):
    print(f"[{label}] calling {call.func.__name__}")
    return call()


@decorator()
def validate(call):
    result = call()
    assert result is not None
    return result


@log("INFO")
@validate()
def compute(x: int) -> int:
    return x * 2

Inspect the current invocation via call

call is a functools.partial, so the current call's arguments are always available without any extra machinery:

from artdeco import decorator


@decorator()
def audit(call, label: str):
    print(
        f"{label} | {call.func.__name__}"
        f"  args={call.args}  kwargs={call.keywords}"
    )
    return call()


@audit("AUDIT")
def transfer(amount: float, *, currency: str = "USD") -> bool:
    return True


transfer(100.0, currency="EUR")
# AUDIT | transfer  args=(100.0,)  kwargs={'currency': 'EUR'}

Development

This project uses uv for environment and dependency management.

Install tools and dependencies:

uv sync --group dev

Run checks:

uv run ruff check .
uv run pytest
uv run pyright src

Run typing tests:

uv run pyright src tests/typing

Build and validate distribution metadata:

uv build
uv run twine check dist/*

License

MIT, see LICENSE.

Metadata

Release files for py-artdeco 0.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 py-artdeco 0.2.0
File Size Uploaded
py_artdeco-0.2.0.tar.gz 32.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for py-artdeco 0.2.0
File Interpreter ABI Platform
py_artdeco-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.7 kB

Release files / py_artdeco-0.2.0.tar.gz

Download URL py_artdeco-0.2.0.tar.gz
Size 32.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f02af1c876dd4353ff4db85501ee40fecd849762ffbb3e14717fa5f38691b00f
BLAKE2b-256 checksum
How to use checksums
83ef914bd8d498c70d66ad9dfc4198950015ce425095d1e6502aa260d702655e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 5, 2026.

Transparency log

Release files / py_artdeco-0.2.0-py3-none-any.whl

Download URL py_artdeco-0.2.0-py3-none-any.whl
Size 6.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
740bc7e422e0c1d8fe156f6598ce91e166a018b74dbb7b56bc2c512bb6e30509
BLAKE2b-256 checksum
How to use checksums
a78a1a3f05314000ee3a471fed137807b318cf9d15ed8e5b1160f901dacaceba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

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