SPOC
SPOC helps you build your own framework. Under it: a component registry with a total naming grammar and a dependency-ordered lifecycle, for modular monolithic Python applications. It sits below your HTTP framework — FastAPI, Robyn, anything — managing internal resources and application objects, and registering every declared object in one flat registry under a canonical identifier:
kind:namespace.object_name e.g. models:blog.post
Surfaces are built on top by enumerating the registry. SPOC describes; it never executes.
Features
- App discovery — Django-style apps declared by dotted module path and
imported through the normal import system; SPOC never touches
sys.pathand never writes to disk - Dependency-ordered loading — modules initialize in topological order,
tear down in reverse; sync and async lifecycles (
start/astart), with coroutine hooks awaited and refused loudly by the sync path - Declarable modes — the
development→staging→productioncascade is the default, and[spoc.modes]extends it (test = ["test", "production"]) without restating the triple - One flat registry — typed records with
kind/namespace/namefacets; grouped views are derived, never stored - Conventional identity — PEP 8 class names derive their snake_case
identifier automatically; stated names are verbatim and validated against
^[a-z][a-z0-9_]*$, lookups are always exact, and re-registering an object under a different identity raises instead of substituting - A stated concurrency contract — registration is atomic, transitions are serialized with one winner, post-boot reads need no coordination
- Precise resolution — failures name the failing segment and the valid
candidates; a typo never falls through to
None - Zero runtime dependencies —
dependencies = []is an invariant - A shipped test harness —
spoc.testinggives every project an isolated framework scope, a declarative app-tree builder, and a mode override; with pytest installed the same pieces arrive as fixtures automatically, and the kernel never imports any of it - Pre-runtime diagnostics —
spoc checkdry-boots the project and reports config problems, unresolvable apps, cycles, collisions, and sync/async lifecycle mismatches before they reach runtime;spoc listandspoc explainread the registry from the command line
Structured-data loading ships in the box as the contained subpackage
spoc.formats (from spoc import formats) — the kernel never imports it,
importing spoc never loads it, and its optional codecs live behind extras
(pip install "spoc[full]").
Installation
Requires Python 3.12+
pip install spoc
Scaffolding a project needs no install at all — spoc init ships as a console script,
and SPOC has no dependencies to resolve:
uvx spoc init myproject # generate; installs nothing
The generated project imports spoc at runtime, so install it in the environment you
run the project from. Full detail in the
installation guide.
Quick Start
from pathlib import Path
import spoc
framework = spoc.Framework("models") # the closed kind set, declared once
model = framework.kind("models") # a ready-made decorator
@model
class Post: # apps/blog/models.py → models:blog.post
...
framework.start(Path(__file__).parent) # construction is inert; start boots
# async surfaces: await framework.astart(...) awaits coroutine hooks
record = framework.resolve("models:blog.post")
print(record.identifier, record.object)
# Project a surface — routes from registry records, nothing else:
routes = [
(f"/{c.namespace}/{c.object_name}", c.object)
for c in framework.registry.by_kind("models")
]
Documentation
For detailed documentation, tutorials, and examples:
Stability
SPOC is pre-1.0. Every name, command, and extra carries one of three tiers —
public, provisional, or internal. For an importable name the tier follows from
how it is exposed: exported from a package is public, saying so in its own docstring
makes it provisional, and reachable only through a submodule is internal. Both the
tiers and every change to them since the last release are checked on every CI run.
Until 1.0 a public element may still change in a minor release, so pin a minor if
that matters: spoc>=0.5,<0.6.
Stability & Versioning — the tiers, what they exclude, the deprecation lifecycle, and what has to be true before 1.0 is cut.
Links
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spoc-0.8.0.tar.gz.
File metadata
- Download URL: spoc-0.8.0.tar.gz
- Upload date:
- Size: 227.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
862fdfdb9b78f966f2762f20a4361a836829db2ddb2286c3f81b27205b68ccf8
|
|
| MD5 |
0efed5a18fa746238bc2e827d48f43cf
|
|
| BLAKE2b-256 |
416c6311a58547596f38a88d482879ea776cea60523dd564f9bf9e8a94ff1330
|
File details
Details for the file spoc-0.8.0-py3-none-any.whl.
File metadata
- Download URL: spoc-0.8.0-py3-none-any.whl
- Upload date:
- Size: 137.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
69dd87ea8bbb62014b06062adb2cb6a6c813d0893c3781279829bd1ad6f97e6c
|
|
| MD5 |
b76d4b273c4c332d1466d0b73e4abe49
|
|
| BLAKE2b-256 |
99c3bd8be291e3b6b77bf0f316e31ec9b7a1a7f971ae7840abae21a5b33cfdec
|