This release is a pre-release and may not be stable for production use.
Bustan
Bustan is a modular architecture engine for building scalable, testable ASGI applications. Inspired by NestJS, it gives Python projects explicit composition boundaries, constructor injection, lifecycle hooks, and a predictable request pipeline while still exposing the underlying platform directly.
Starlette is the default HTTP engine today. Bustan adds structure on top of it rather than replacing it.
Why Bustan
- Use modules as real composition boundaries instead of ad hoc import graphs.
- Keep controllers thin and move business logic into DI-managed providers.
- Apply guards, pipes, interceptors, and exception filters in a predictable order.
- Keep direct access to the underlying platform through the public
Applicationwrapper. - Test applications with focused module builders, route snapshots, and provider overrides.
Status
[!IMPORTANT] Versions
1.0.0and1.0.1were unintentionally released during CI/CD setup. Treat them as early alpha orphans. The first production-ready, non-alpha release target remains2.0.0.
bustanis currently in the early1.1.xalpha series.- The supported Python floor is currently
>=3.13. - Compatibility promises apply only to
bustan,bustan.errors, andbustan.testing. - Internal modules such as
bustan.kernel.*,bustan.app.*, andbustan.runtime.*are still implementation details. - The public PascalCase API is already being treated as the intended long-term contract, even though alpha behavior may still move.
Installation
Work On The Repository From Source
uv sync --group dev
That installs the framework, tests, linting, typing tools, and the local CLI entry point.
Start A New Application
uv init --package my-app
cd my-app
uv add 'bustan[starlette]'
uv add --dev pytest ruff ty
uv run bustan init
Install The Published Package
An application that serves HTTP over the shipped Starlette adapter installs the starlette extra:
uv add 'bustan[starlette]'
# or
pip install 'bustan[starlette]'
Plain bustan installs no web server. That is the install for using the framework as a library: modules, providers, and dependency injection resolved through create_app_context, with no HTTP served.
uv add bustan
# or
pip install bustan
Quickstart
The recommended quickstart uses the CLI scaffold instead of hand-writing the first package layout.
uv init --package my-app
cd my-app
uv add 'bustan[starlette]'
uv add --dev pytest ruff ty
uv run bustan init
That creates a package like this:
src/
my_app/
__init__.py
app_module.py
app_controller.py
app_service.py
tests/
my_app/
test_app_controller.py
test_app_module.py
test_app_service.py
The scaffold also adds start and dev script entries when pyproject.toml does not already define them. Run the generated app with:
uv run dev
Then call the root route:
curl http://127.0.0.1:3000/
Expected response:
{"message":"Hello from My App"}
For the full walkthrough, generated file contents, and first test, see docs/FIRST_APP.md.
What You Get Today
The current implementation already includes:
- module discovery, validation, and export-based provider visibility
- constructor injection for providers and controllers
- controller route compilation into Starlette
- inferred and explicit request binding with
Annotated[...]markers - response coercion for Starlette responses,
HttpResponse, dataclasses, iterators,Path, andNone - request-scoped providers plus request-scoped controllers
- guards, pipes, interceptors, and exception filters
- automatic Pydantic validation in
validation_mode="auto" - module and provider lifecycle hooks wired through the platform lifespan
ApplicationandApplicationContextbootstrapping- route snapshots, route diffs, and runtime discovery support
- config, OpenAPI, throttling, CORS, and testing helpers
- a CLI (
bustan init) for scaffolding new applications insideuvprojects
Supported Public API
The current compatibility boundary is intentionally small.
Stable import paths:
bustanbustan.errorsbustan.testing
Example supported imports:
from bustan import Application, Controller, Get, Injectable, Module, create_app, create_app_context
from bustan.errors import ProviderResolutionError
from bustan.testing import create_test_app, create_testing_module
The generated reference for those stable modules lives in docs/API_REFERENCE.md.
Guides
- docs/README.md
- docs/FIRST_APP.md
- docs/ROUTING.md
- docs/REQUEST_PIPELINE.md
- docs/REQUEST_SCOPED_PROVIDERS.md
- docs/LIFECYCLE.md
- docs/PLATFORM_INTEGRATION.md
- docs/STABILITY.md
- docs/VERSIONING.md
- docs/TROUBLESHOOTING.md
- docs/COMPARISONS.md
Open Source Project Docs
Examples
The repository includes focused examples beyond the starter app. Each example now mirrors the standalone mini-project layout used by .bustan/mini: its own README.md, pyproject.toml, src/, and tests/.
- examples/README.md
- examples/blog_api/README.md: reference-style blog API with feature modules and request-scoped actor state
- examples/multi_module_app/README.md: provider exports crossing module boundaries
- examples/graph_inspection/README.md: supported runtime inspection with
DiscoveryServiceand route snapshots - examples/request_scope_pipeline_app/README.md: request-local state shared across guards, interceptors, and a request-scoped controller
- examples/testing_overrides/README.md: test-time provider overrides with
bustan.testing - examples/dynamic_module_usage/README.md: configurable dynamic module registration
Run one with:
cd examples/blog_api
uv sync --group dev
uv run python -m blog_api.app
Testing Utilities
bustan.testing is the supported entry point for test-time application assembly.
Use create_test_app() to start an app with one or more providers replaced:
from bustan.testing import create_test_app
application = create_test_app(
AppModule,
provider_overrides={GreetingService: FakeGreetingService()},
)
Use create_testing_module() when you want the test to assemble and start the application itself:
from bustan.testing import create_testing_module
compiled = await (
create_testing_module(AppModule)
.override_provider(GreetingService)
.use_value(FakeGreetingService())
.compile()
)
with compiled.create_client() as client:
response = client.get("/greetings")
Both register the replacement before the application starts, which is the only point at which an override is honoured in full. An override does not stand beside the provider it replaces; it replaces it for the whole application, including the singletons already built from it. A running application therefore refuses one and says so, rather than swapping a dependency that everything already holding it would keep.
Use create_test_module() when you want a temporary module class for an isolated test instead of declaring one manually.
Support
Use GitHub Issues for questions, bug reports, feature requests, and adoption feedback:
Do not use public issues for sensitive security reports. Follow the private disclosure guidance in SECURITY.md.
Roadmap
Near-term priorities for the first production-ready release (2.0.0):
- stabilize the PascalCase public contract
- keep the scaffold, README, guides, and checked-in examples aligned
- widen runtime support beyond Python
3.13 - collect external adopter feedback before calling any release stable
- publish a fuller reference app or companion tutorial repository
Development
Install hooks once after cloning if you want local pre-commit and pre-push checks:
uv run lefthook install
For contributor expectations, see CONTRIBUTING.md.
Run the main checks with:
uv run python scripts/generate_api_reference.py --check
uv run python scripts/check_markdown_links.py
uv run ruff check .
uv run ty check src tests scripts
uv run pytest
uv run pytest --cov=bustan --cov-report=term-missing --cov-report=xml
If you change public docstrings in the stable modules, regenerate the API reference with:
uv run python scripts/generate_api_reference.py
Project Direction
Bustan is opinionated about application structure, not about hiding the underlying platform or competing on benchmark claims.
If you want a small ASGI core with explicit module boundaries, DI-managed services, lifecycle hooks, and a predictable request pipeline, that is the target use case for Bustan.
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 bustan-2.0.0rc3.tar.gz.
File metadata
- Download URL: bustan-2.0.0rc3.tar.gz
- Upload date:
- Size: 175.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
802cc9ff76348f24da61b62ca1f5d117bf7b12a6fc7385f082f1eacd9a43fde4
|
|
| MD5 |
8bf505d1044d5ffb6240deecaebb9cb1
|
|
| BLAKE2b-256 |
b328db8a41ccabcfd17e5afe17f6bc54be0f46eab6f00d96a313e01a5ae4b71b
|
Provenance
The following attestation bundles were made for bustan-2.0.0rc3.tar.gz:
Publisher:
publish.yml on bustanhq/bustan
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bustan-2.0.0rc3.tar.gz -
Subject digest:
802cc9ff76348f24da61b62ca1f5d117bf7b12a6fc7385f082f1eacd9a43fde4 - Sigstore transparency entry: 2752196144
- Sigstore integration time:
-
Permalink:
bustanhq/bustan@a0ade03cab07ef649cce8a4babc8361b0e757be2 -
Branch / Tag:
refs/tags/v2.0.0rc3 - Owner: https://github.com/bustanhq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a0ade03cab07ef649cce8a4babc8361b0e757be2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file bustan-2.0.0rc3-py3-none-any.whl.
File metadata
- Download URL: bustan-2.0.0rc3-py3-none-any.whl
- Upload date:
- Size: 236.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
687a116deb422b4b06aa8b9ef7c42cc35282ada23fce17b1c3b7c5947ee7a455
|
|
| MD5 |
51eb77c6945e032efbe81f86d18e3918
|
|
| BLAKE2b-256 |
9e842eafff42cb1c607551a8b07d94724d7a384619f874e70fe2c3f165ff730e
|
Provenance
The following attestation bundles were made for bustan-2.0.0rc3-py3-none-any.whl:
Publisher:
publish.yml on bustanhq/bustan
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bustan-2.0.0rc3-py3-none-any.whl -
Subject digest:
687a116deb422b4b06aa8b9ef7c42cc35282ada23fce17b1c3b7c5947ee7a455 - Sigstore transparency entry: 2752196550
- Sigstore integration time:
-
Permalink:
bustanhq/bustan@a0ade03cab07ef649cce8a4babc8361b0e757be2 -
Branch / Tag:
refs/tags/v2.0.0rc3 - Owner: https://github.com/bustanhq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a0ade03cab07ef649cce8a4babc8361b0e757be2 -
Trigger Event:
push
-
Statement type: