Skip to main content

Buddhist concepts as load-bearing Python infrastructure: reactive dependency graphs, retention profiling, decay containers, side-effect ledger, structural identity tools, runtime introspection, and a project-quality checker.

Project description

buddhist-python

A Python package providing a reactive dependency graph, a retention profiler, decay containers, a side-effect ledger, structural identity tools, runtime three-marks introspection, and a project-quality checker — dependency-free, in roughly 2,000 lines of Python.

from buddhism import Conditioned, cell, derived

class Invoice(Conditioned):
    quantity   = cell(1)
    unit_price = cell(10.0)
    tax_rate   = cell(0.20)

    @derived
    def total(self):
        return self.quantity * self.unit_price * (1 + self.tax_rate)

inv = Invoice()
inv.total          # 12.0
inv.quantity = 5
inv.total          # 60.0  ← arose anew from the new conditions

No manual recompute. No invalidation flags. No publish/subscribe ceremony. The values arise from their conditions and re-arise when the conditions change.

The doctrinal labels (Buddhist concepts) are how the package's pieces are named — they map one-to-one to the engineering primitives. The mapping is load-bearing, not decorative. See § Doctrinal mapping below if you'd like to read the design as philosophy. The rest of this README reads it as engineering.


Install

pip install buddhist-python

Python 3.9+. No runtime dependencies.


What's in the box

Module What it does
pratitya Reactive dependency graph (descriptors + auto-tracking + weakref).
dukkha Retention profiler (gc + weakref + Tarjan SCC).
anitya DecayDict, @impermanent, MemoryPressureRegistry.
anatta StructuralEq, without_self, diff.
karma @karmic traces globals/IO/arg-mutations; KarmicViolation.
examine examine(obj) — three orthogonal views of any Python object.
buddhism.path CLI: 8 quality checks against a target package.
koans Seven runnable lessons pairing each module with a Python internal.

1. pratitya — reactive dependency graph

Two surfaces.

Standalone signals:

from buddhism import Cell, derive

a = Cell(1)
b = Cell(2)
c = derive(lambda: a() + b())     # auto-tracks dependence on a, b
c()                                # 3
a.set(10);  c()                    # 12

Class-attribute descriptors (the spreadsheet form):

from buddhism import Conditioned, cell, derived, on_change, batch

class Triangle(Conditioned):
    base   = cell(3.0)
    height = cell(4.0)

    @derived
    def area(self):
        return 0.5 * self.base * self.height

t = Triangle()
t.area                # 6.0
t.base = 6
t.area                # 12.0

The deep features:

  • Auto-tracking via ContextVar records edges as a function reads its inputs; the dependency set is rebuilt on each recomputation, so conditional branches don't accumulate dead edges.
  • Pull-based evaluation with eager subscribers (on_change) only if you ask for them.
  • Non-clinging by construction: edges from Cell to its dependents live in a WeakSet — a Derived becoming unreachable is collected and silently disappears from the graph.
  • with batch(): coalesces multiple writes; each subscriber fires at most once, with the correct before and after values, after the cascade completes.
  • SamsaraError on circular dependencies (A → B → A has no still point at which to assign a value).
  • equality_check parameter lets you opt into identity-only comparison for objects with expensive or side-effectful __eq__.
  • __slots__-only classes are supported (declare __buddhism_nodes__ in __slots__); a class that is not weak-referenceable must explicitly opt into strong-ref mode via __buddhism_strong_refs__ = True.

2. dukkha — retention profiler

In Python, clinging is the technical name for: reference cycles you didn't mean to create, caches that keep growing, closures that capture more than they should, and listeners that outlive their listened-to. The garbage collector is willing to let go; we are the ones holding on.

from buddhism import observe, let_go, find_cycles, retention_path

# observe() — diff live objects across a block
with observe() as report:
    do_some_work()
print(report.text_report())

# @let_go — assert a function does not retain its inputs (transitive
# retention through the *return value* is fine; named arguments can
# be allow-listed for constructors that legitimately keep inputs)
@let_go(allow={"config"})
def __init__(self, config, *, debug=False):
    self.config = config

# find_cycles — strongly-connected components in your candidate set
cycles = find_cycles([a, b, c])

# retention_path — one path of clinging, root → object
path = retention_path(att.get())
print(path.format())

The cross-module bridge: RetentionReport.pratitya_breakdown() summarises reactive-graph nodes among the retained objects, so a leaking dependency graph reports its shape, not just its count.


3. anitya — decay containers and validity windows

Time as a first-class primitive. Three tools.

DecayDict / DecaySetstaleness as a continuous gradient, not a binary alive/dead flag:

from buddhism import DecayDict

cache: DecayDict[str, dict] = DecayDict(half_life=60.0)
cache.set("user:42", {"name": "Alice"})
value, confidence = cache.get("user:42")
# After 60s, confidence == 0.5; after 120s, 0.25; eventually evicted.

@impermanent(validity) — declare a function whose return value has a validity window. Past the window, you get back a Stale[T] that demands an explicit decision:

from buddhism import impermanent, Stale, StalenessError

@impermanent(validity=30.0)
def fetch_rate() -> float:
    return external_api.get_rate()

result = fetch_rate()
# Inside 30s: returns float directly.
# After 30s:
match result:
    case Stale(): result = result.refresh()   # re-call
    # or:
    # result = result.accept_stale()           # explicit acknowledgement
    # or just bare access — that raises StalenessError, by design.

MemoryPressureRegistry — drop-on-load registry built on weakref.finalize, releasing in priority order under memory pressure.


4. anatta — structural identity tools

from buddhism import StructuralEq, without_self, diff

# Value semantics on demand
class Point(StructuralEq):
    def __init__(self, x, y):
        self.x = x; self.y = y

Point(1, 2) == Point(1, 2)        # True (same configuration)
Point(1, 2) is Point(1, 2)        # False (distinct objects)
{Point(1, 2), Point(1, 2)}        # set of size 1

# Methods as pure functions over an explicit state
class Counter:
    def step(self, k): return self.n + k

pure_step = without_self(Counter.step)
pure_step({"n": 10}, 5)           # 15 — no instance needed

# A diff that distinguishes "mutated" from "replaced"
d = diff(a, b)
d.same_identity        # a is b
d.same_configuration   # public attrs equal
d.field_changes        # {name: (a_value, b_value)}
d.summary()            # 'mutated: same object, 2 field(s) changed'

5. karma — side-effect ledger

from buddhism import karmic, KarmicViolation

@karmic
def update_record(record, value):
    record["v"] = value
    return record["v"]

result, ledger = update_record({"v": 0}, 7)
ledger.arg_mutations   # {0: ({'v': 0}, {'v': 7})}
ledger.is_pure()       # False

The ledger names every observed side effect: globals read, globals written, I/O events (file open / socket connect / subprocess), arguments mutated by reference. Read-tracking is best-effort (CPython 3.11+ inline-caches LOAD_GLOBAL); write-tracking is reliable.

Strict mode turns the ledger into a contract:

@karmic(allow={"global:cache"})
def lookup(key):
    if key in cache: return cache[key]   # OK
    cache[key] = fetch(key)               # OK (allow-listed)
    return cache[key]

@karmic(allow=set())
def vow_of_purity(x):
    return x * 2          # OK
    # any global write or I/O event raises KarmicViolation

Debt lets test suites assert maximum unacknowledged side-effect budgets across a suite of calls.


6. examine — Three Marks introspection

A single function that returns three orthogonal views of any object:

from buddhism import examine

class Sheet(Conditioned):
    a = cell(1)

    @derived
    def b(self): return self.a * 2

s = Sheet()
print(examine(s).text_report())
# examine(<__main__.Sheet object at 0x…>)
#
#   Anitya — change over time:
#     (no time-relevant decoration found)
#
#   Dukkha — what is clinging:
#     alive:                 True
#     direct referrers:      1
#     referrer types:        dict
#     reactive subscribers:  0
#
#   Anatta — configuration of conditions:
#     type:                  Sheet
#     public attrs (3):      ['a', 'b', '__buddhism_nodes__']
#     reactive dependencies: ['a', 'b']
#     pure form:             available via without_self()

The output is progressively richer as the object adopts more of the package's primitives.


7. buddhism.path — project-quality checker

A CLI that audits a target package against eight checks:

$ python -m buddhism.path
buddhism path examined .../src/buddhism

   Right View            type coverage 92% (threshold 80%)
   Right Intention       81/81 public functions documented
   Right Speech          no print() calls in library code
   Right Action          no unmarked argument mutations
   Right Livelihood      pure modules touched no I/O
   Right Effort          test-file ratio 50% (8 tests / 16 src; threshold 50%)
   Right Mindfulness     30/30 module-level public functions decorated
   Right Concentration   max complexity 25

  8/8 path factors satisfied. The path is complete.

Each check is concretely engineering:

Step Check
Right View type-annotation density above threshold
Right Intention every public function carries a docstring
Right Speech no print() in library code
Right Action no unmarked argument mutation
Right Livelihood no I/O in modules declaring __pure__ = True
Right Effort test coverage threshold
Right Mindfulness every public function tagged with an effect-decorator
Right Concentration cyclomatic complexity below threshold

Configurable via [tool.buddhism.path] in pyproject.toml. Output in JSON via --json for CI. The package eats its own dog food.


8. koans — guided tutorial

Seven runnable lessons pairing each Buddhist concept with one deep Python feature:

python -m buddhism.koans
# ✓ k01_impermanence       mutation, aliasing, default-arg trap
# ✓ k02_dependent_origination  descriptors + reactive graph
# ✓ k03_non_self            identity, equality, __dict__
# ✓ k04_clinging            weakref, gc, retention
# ✓ k05_emptiness           None, sentinels, falsy values
# ✓ k06_karma               globals tracking, I/O patches, snapshots
# ✓ k07_three_marks         examine() across all primitives
#
# All koans completed.

Passing by default — they're a guided tour. To turn them into self-tests, replace any literal answer with __ (imported from buddhism.koans) and re-run; the runner stops at the first failure with the koan's hint.


Examples

python examples/reactive_spreadsheet.py     # cascading recompute
python examples/reactive_config.py          # config whose derivations re-arise
python examples/leak_detection.py           # observe(), @let_go, find_cycles

Doctrinal mapping (the design philosophy)

Doctrine Engineering primitive Module
Pratītyasamutpāda (dependent origination) reactive dependency graph pratitya
Dukkha (clinging) retention profiler dukkha
Anitya (impermanence) decay containers, validity windows anitya
Anatta (non-self) structural identity, pure-form transformation anatta
Karma side-effect ledger karma
Three Marks runtime introspection across all three examine
Eightfold Path project-quality discipline buddhism.path

Each row is a one-to-one mapping. No module is a renamed standard utility; each one uses Python's deepest leverage points (descriptors, gc, weakref, ContextVar, AST analysis, runtime patching). If you couldn't justify the entry as engineering, it didn't ship.

The point of the package is that the labels are the most economical way of naming the design, not a layer of paint. Two thousand five hundred years ago, four contemplatives looked carefully at how things actually work, and most of what they noticed has direct, useful Python analogues. This package takes those analogues seriously enough to write them down.


Design principles

  1. Doctrinal, not decorative. Every Buddhist term in the public API maps to a real Python primitive. If we couldn't justify it as engineering, we didn't ship it.
  2. Non-clinging by default. The library uses WeakSet and weakref throughout so its own data structures don't become a source of dukkha.
  3. Pure-Python, no dependencies. Same behaviour on CPython 3.9+ on every platform.
  4. Eats its own dog food. python -m buddhism.path returns 8/8 on buddhism itself.

Contributing

PRs welcome. Especially:

  • additional koans (one new Buddhist concept paired with one deep Python feature)
  • corner-case tests for the reactive graph (cycles, threading, asyncio)
  • visualisation of retention graphs in dukkha
  • a real coverage integration in buddhism.path's Right Effort check

License

MIT — see LICENSE.


"Whatever has the nature of arising, all that has the nature of cessation." — Aññāsi-Koṇḍañña, on the first sermon

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

buddhist_python-0.2.0.tar.gz (77.2 kB view details)

Uploaded Source

Built Distribution

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

buddhist_python-0.2.0-py3-none-any.whl (67.0 kB view details)

Uploaded Python 3

File details

Details for the file buddhist_python-0.2.0.tar.gz.

File metadata

  • Download URL: buddhist_python-0.2.0.tar.gz
  • Upload date:
  • Size: 77.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.4

File hashes

Hashes for buddhist_python-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f9847df196a16781ff4868eebd1e8a509fb4c761ca0a8a545ff103b72c7a1123
MD5 64033cb0693582efac67a842eefaecd9
BLAKE2b-256 24e5fa308bc7d16f6235d48d9fbcc9adac2151b20fd77556812f80732ad5c381

See more details on using hashes here.

File details

Details for the file buddhist_python-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for buddhist_python-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 89c089a1b73ae44f907a9024d17b2cb178849bff6c5b8f87e60bf64f64205dfb
MD5 65bdaf63a86be83b2c0f8b6d1b53b400
BLAKE2b-256 d67b1b0f3f5307dcb685f58f34837ec4aa836ef6183edf0b369977fb3cbe6458

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