Skip to main content

Try to enforce 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

This is obviously mostly vibe-coded and perhaps better suited to static analysis anyhow. I'm using it as an exercise and any actual utility is just a bonus

Super-quick Start

Requires: Python >= 3.12

The implementation adopts modern standard-library typing helpers such as typing.override and typing.Self, so earlier interpreters are not supported.

Install through pip:

pip install pure-function-decorators
from pure_function_decorators import forbid_globals


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


CONST = 10
bad(1)  # Raises NameError
import datetime

from pure_function_decorators import enforce_deterministic


@enforce_deterministic
def bad():
    return datetime.datetime.now().microsecond


print(bad())
print(bad())  # raises ValueError

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 see in-place mutations.
    • By default, the decorator raises when a mutation is detected.
    • Use warn_only=True or strict=False to log warnings instead of raising, or enabled=False to bypass checks.
  • enforce_deterministic ensures that the decorated function consistently returns the same result for the same parameters.
    • Set strict=False to emit warnings when nondeterministic behaviour is observed or enabled=False to skip wrapping.
  • forbid_globals prevents a function from reading or mutating module-level state by sandboxing its globals.
    • 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.
    • Configure strict=False to log name-check violations instead of raising or enabled=False to leave the function unchanged.
  • forbid_side_effects instruments builtin operations that commonly mutate process state (e.g. file writes, subprocess launches) to surface accidental side effects.
    • Pass strict=False to warn and allow the attempted side effect or enabled=False to skip patching entirely.

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:

  • 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 allowlisted 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.

Side Effects

A side effect is any interaction with outside state other than computing and returning a value.

Canonical side effects and impurity sources:

State mutation: modifying globals, nonlocals, class/static attributes, singletons, caches, or the objects passed in as arguments (in-place changes).

I/O: printing/logging, reading/writing files, networking, databases, stdin/stdout/stderr, GUI operations.

Process/system effects: spawning threads/processes, signals, timers, sleeping, exiting the process.

Nondeterministic sources: reading clocks (now, time), random/URNGs (random, secrets, uuid4, os.urandom), environment variables, current working directory, locale.

Hidden global dependencies: reading mutable module state or configuration not provided as explicit parameters.

Observable control effects: raising exceptions or relying on exceptions for normal control can be considered effects in stricter definitions; total purity disallows them, weaker purity allows deterministic exceptions for invalid inputs.

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.4.tar.gz (65.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.4-py3-none-any.whl (16.5 kB view details)

Uploaded Python 3

File details

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

File metadata

File hashes

Hashes for pure_function_decorators-0.1.4.tar.gz
Algorithm Hash digest
SHA256 67ba2d60168c905d92bc7f816db70904a487418ff5600d134328d16307b3079a
MD5 7dd9262bd223235a35504f6466074744
BLAKE2b-256 318d0b9ddfd219f96c7d332fd8743584def09f8512ea9260d0bf3d00a79d8099

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pure_function_decorators-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 c397e1de7e5c7d3abadd95fa8e1111fe284fc527b64cb6c6d7b48316123b9331
MD5 ab88b6756514553409863d2ae9e6e62d
BLAKE2b-256 78811b254f5e8e790fe7d680cf51dd733309579798ad439cbf63e7d029ca4d82

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