Skip to main content

Try to enforece various types of function purity in Python

Project description

Latest Version Python Versions Build Status Documentation Status

pure-function-decorators

Decorators to try to enforce various types of function purity in Python

Mostly vibe-coded, though I hope to whittle down any issues

Super-quick Start

Requires: Python 3.10 to 3.13

Install through pip:

pip install pure-function-decorators
from pure_function_decorators import (
    enforce_deterministic,
    forbid_globals,
    forbid_side_effects,
    immutable_arguments,
)


@forbid_globals()
def bad(x):
    return x + CONST

CONST = 10
bad(1)   # Raises NameError

Documentation

The complete documentation can be found at the pure-function-decorators home page

Features

Existing decorators

  • immutable_arguments deep-copies inputs before invoking the wrapped callable so callers never observe in-place mutations. By default the decorator raises when a mutation is detected, and it can instead log warnings with warn_only=True.
  • enforce_deterministic reruns a function and compares its results so you can gate functions that rely on deterministic behavior.
  • forbid_globals prevents a function from reading or mutating module-level state by sandboxing its globals. Pass check_names=True to also fail decoration when bytecode references globals outside the allow-list, or set sandbox=False to keep only the bytecode-based validation.
  • forbid_side_effects instruments builtin operations that commonly mutate process state (e.g. file writes, subprocess launches) to surface accidental side effects.

Future purity checks to explore

The current decorators focus on globals, determinism, and structural immutability. Additional checks that build on the same inspection hooks could include:

  • Non-deterministic source guards — wrap time-, randomness-, and UUID-related modules (time, datetime, random, uuid, secrets) to ensure a supposedly pure function does not sample entropy or wall-clock timestamps.
  • Environment isolation — raise when a function touches environment variables, current working directory, or other process-wide configuration through os.environ, os.chdir, or similar APIs.
  • I/O safelists — expand the forbid_side_effects strategy with dedicated helpers that specifically deny file, socket, or HTTP operations unless a pure-safe allowlist is provided.
  • Mutable default detection — detect functions whose default arguments or closed-over state are mutable so callers do not accidentally share state across invocations.
  • Dependency purity enforcement — verify that functions only call other decorated or safelisted pure functions by walking the bytecode or AST.

These ideas could live alongside the existing decorators as optional opt-in guards so projects can combine them to match their definition of purity.

Frequently asked questions

Can these decorators be enabled globally, like perl's strict pragma?

No. Python does not provide a hook that automatically wraps every function that is imported or defined after a module loads. The decorators in this project operate by returning a new callable, so each target function (or method) has to be wrapped explicitly. You can build your own helpers that iterate over a module or class and decorate selected callables, but the library cannot apply itself universally without the caller opting in on a per-function basis.

What about leaning on the descriptor protocol to auto-wrap methods?

Descriptors only help when attribute access goes through a class that you control, and Python already turns functions defined on a class into descriptors that bind methods at lookup time. Swapping in a custom descriptor still requires you to opt in for each attribute you expose, and it cannot cover free functions or methods defined on classes outside your control. You could build a metaclass or __setattr__ hook that decorates attributes as they are assigned, but that still imposes an explicit opt-in boundary (the metaclass or base class) rather than letting a library blanket the entire interpreter.

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

pure_function_decorators-0.1.0.tar.gz (58.8 kB view details)

Uploaded Source

Built Distribution

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

pure_function_decorators-0.1.0-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

File details

Details for the file pure_function_decorators-0.1.0.tar.gz.

File metadata

File hashes

Hashes for pure_function_decorators-0.1.0.tar.gz
Algorithm Hash digest
SHA256 70018ccfab11bdea02ffb7bb5536135bd1d093c049879f939edef8e1ad7ea238
MD5 d40988f2f75ce6f12d0cb73a4f4764c1
BLAKE2b-256 4ad1af02e2ac5563ab5394207f76d66cf36244e5dd8d1e199c104b5935661249

See more details on using hashes here.

File details

Details for the file pure_function_decorators-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pure_function_decorators-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5e0da5c8b7123ab729cbbfbb542f5c0031d9cdebe90a4a52f050aa1d148c13d5
MD5 226554f2c7fe565fa26d41de1b08267d
BLAKE2b-256 d142e0ddc9650c3e8071726a5f0a4e6f60f4eb59592c402aabccbbc5523a7716

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