Skip to main content

SPOC

title-image

License: MIT Language GitHub PyPI Downloads

Build a framework in 30 lines

Say what kinds of things your app has:

import spoc

framework = spoc.Framework("models", "commands", "views")

model = framework.kind("models")
command = framework.kind("commands")
view = framework.kind("views")

Tag your code with them, anywhere in the project:

from framework import model


@model
class Post:
    """Registers as models:blog.post."""
from framework import command


@command
def publish(title: str = "Hello, SPOC") -> str:
    """Registers as commands:blog.publish."""
    return f"published {title!r}"
from framework import view


@view
def posts_api() -> list[str]:
    """Registers as views:blog.posts_api."""
    return []
[spoc.apps]
development = ["apps.blog"]
from pathlib import Path

from framework import framework

framework.start(Path(__file__).resolve().parent)

That's it — no registry to wire up, no list to keep in sync. Ask SPOC what it found:

spoc check
spoc list
spoc stubs
OK: /path/to/blog checks out clean
commands:blog.publish
models:blog.post
views:blog.posts_api
wrote framework.pyi (3 identifiers)

SPOC turns your application's declarations into one typed, inspectable registry.

check dry-boots your project and reports what's wrong before anything runs. list reads the shelf. stubs writes real autocomplete for every name you just typed — so framework.objects.models.blog.post completes in your editor before you've written a single test. Add a fourth decorated function tomorrow; all three commands see it with no edit to any of these files.

See it work without writing a file

pip install spoc
spoc init myproject --template starter
cd myproject && python main.py --help
usage: myproject [-h] {core.add,core.items} ...

positional arguments:
  {core.add,core.items}
    core.add            Add an item to the store.
    core.items          List the items in the store.

options:
  -h, --help            show this help message and exit

Nobody wrote that command list. It was derived from what the generated app registered — the same trick as above, scaffolded for you. uvx spoc init myproject works with nothing installed at all.

What you get

  • One name per component, always. Class names derive their own. Ask for a name that isn't there and the error says which segment was wrong and what would have matched — never a silent None.
  • Autocomplete, with no code changes. spoc stubs writes a type stub beside your entry point: names complete as you type, components come back as their real types, typos become editor errors. spoc projection emits the same registry as JSON for tools in any language.
  • A lifecycle you can reason about. Modules start in dependency order and stop in reverse, sync or async.
  • Problems found before runtime. spoc check dry-boots and reports config errors, cycles, collisions, and sync/async mismatches. spoc list and spoc explain read the registry from your terminal.
  • Tests in the box. spoc.testing gives isolated framework scopes and an app-tree builder, arriving as ready-made pytest fixtures.
  • Zero dependencies. dependencies = [], enforced. Optional data-format codecs live behind extras (pip install "spoc[full]").

SPOC never runs your components. FastAPI still serves your HTTP, Typer still parses your argv, Celery still runs your jobs. SPOC only answers what does this app contain, and under what name — how architecture, names, and lifecycle work underneath is in the docs.

Should you use it?

Yes, if…

  • one codebase feeds several surfaces — HTTP and CLI and workers — and each re-discovers the same components its own way.
  • you are shipping a framework other people write apps against.
  • things must start in dependency order and stop in reverse.
  • a mistyped component name should be an editor error, not a None at 3am.

No, if…

  • it's one app, one surface, a handful of modules. Imports are cheaper. SPOC pays off above a complexity threshold, not below it.
  • you are already on Django. Its app registry is a structural model.
  • you want something that runs your components. SPOC only names and orders them.

Weighing it against imports, entry points, pluggy, or a DI container specifically? Why not just…? has the one-line answer for each.

Install

Python 3.12+

pip install spoc

The generated project imports spoc at runtime, so install it where you run the project from — installation guide.

Documentation

Read the docs — tutorials, how-to guides, and the full API reference.

A good path in: your first projectnames & the registrybuild a framework.

Stability

SPOC is 1.0. A public name changes incompatibly only in a major release, and only after a completed deprecation cycle — so spoc>=1.0,<2 is the pin that matters. Every name, command, and extra carries a tier (public, provisional, internal), and both the tiers and every change to them are checked on each CI run.

Stability & Versioning — the tiers, the deprecation lifecycle, and the criteria 1.0 was cut against.

Links

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spoc-0.9.0.tar.gz (275.2 kB view details)

Uploaded Source

Built Distribution

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

spoc-0.9.0-py3-none-any.whl (157.0 kB view details)

Uploaded Python 3

File details

Details for the file spoc-0.9.0.tar.gz.

File metadata

  • Download URL: spoc-0.9.0.tar.gz
  • Upload date:
  • Size: 275.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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

Hashes for spoc-0.9.0.tar.gz
Algorithm Hash digest
SHA256 f24ac1e513182c3c77aaef6adc096658b4903e344bf56306c8e9ad8c2ec4dbd1
MD5 4582321b9b90c76f37cc7aa571da1f72
BLAKE2b-256 b01519741fd56732a4e0a6700051272d98f5ec17a81eeeb9f76c3d212ff747cf

See more details on using hashes here.

File details

Details for the file spoc-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: spoc-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 157.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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

Hashes for spoc-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fed26f53a78b6a634803074a75673007d58d398c99a86fa2e1c03dc531f3b1a0
MD5 dd02a2a70e54e32ded0a4cfe2748305e
BLAKE2b-256 978515147d96fb35cf12562382c93f49cf0203b23719e0f0d3362b7288719ce9

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.9.0 This release

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.3.9

2 files

0.3.8

2 files

0.3.7

2 files

0.3.6

2 files

0.3.5

2 files

0.3.4

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.3

2 files

0.2.2

2 files

0.1.35

2 files

0.1.34

2 files

0.1.33

2 files

0.1.32

2 files

0.1.31

2 files

0.1.21

2 files

0.1.15

2 files

0.1.14

2 files

0.1.13

2 files

0.1.12

2 files

0.1.11

2 files

0.1.10

2 files

0.1.9

2 files

0.1.8

2 files

0.1.7

2 files

0.1.6

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 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