Skip to main content

Bustan

Bustan is a modular architecture engine for building scalable, testable ASGI applications. Inspired by NestJS, it provides a structured alternative to assembling micro-frameworks by hand.

It brings modules, controllers, providers, constructor injection, lifecycle hooks, and a request pipeline to the Python ecosystem, while maintaining direct access to the underlying platform (Starlette by default).

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.
  • Decoupled from HTTP engines via the Adapter pattern (supporting Starlette, with Litestar planned).
  • Test applications with focused module builders and provider overrides.

Status

[!IMPORTANT] Versions 1.0.0 and 1.0.1 were unintentionally released to PyPI and GitHub during CI/CD pipeline setup. These should be treated as early alpha orphans. The first real production-ready, non-alpha release will be 2.0.0.

  • bustan is currently in an early alpha stage (v1.0.1).
  • The first intended production-ready target is 2.0.0.
  • Package metadata currently targets Python >=3.13.
  • The Python floor is intentionally narrow while the public surface, packaging, and release automation are still settling.
  • Compatibility is currently promised only for the public surface of bustan, bustan.errors, and bustan.testing.
  • Internal modules such as bustan.core.ioc, bustan.platform.http.routing, and bustan.metadata are still implementation details.
  • Alpha stability means behavior may still change, but the project is already treating the PascalCase public API as the intended long-term contract.
  • No benchmark suite or benchmark claims are published yet.

Installation

Use from source today

This repository is ready to use directly in a local development environment:

uv sync --group dev

That installs the framework, test dependencies, linting, typing, and the local CLI entry point.

Use the CLI from a source checkout

uv init --package my-app
cd my-app
uv add bustan
uv add --dev ty ruff
uv run bustan init

Use as a published package

Once the PyPI distribution name is confirmed and published, the intended install path is:

uv add bustan
# or
pip install bustan

The distribution name bustan still needs to be confirmed at publish time. The current repository is prepared for that name, but the final PyPI availability check should happen immediately before the first release.

Five-Minute Quickstart

Create an application module, one provider, and one controller:

from bustan import Controller, Get, Injectable, Module, create_app


@Injectable
class GreetingService:
	def greet(self) -> dict[str, str]:
		return {"message": "hello from bustan"}


@Controller("/hello")
class GreetingController:
	def __init__(self, greeting_service: GreetingService) -> None:
		self.greeting_service = greeting_service

	@Get("/")
	def read_greeting(self) -> dict[str, str]:
		return self.greeting_service.greet()


@Module(
	controllers=[GreetingController],
	providers=[GreetingService],
	exports=[GreetingService],
)
class AppModule:
	pass


app = create_app(AppModule)

Run it locally:

uv run dev

Call the route:

curl http://127.0.0.1:3000/hello

Expected response:

{"message":"hello from bustan"}

What You Get Today

The current implementation already includes:

  • module discovery and validation
  • export-based provider visibility across modules
  • constructor injection for providers and controllers
  • controller route compilation into Starlette
  • response coercion for Response, dict, list, dataclass instances, and None
  • request binding for Request, path params, query params, and JSON body input
  • request-scoped providers with per-request caching
  • guards, pipes, interceptors, and exception filters
  • module and application lifecycle hooks wired through Starlette lifespan
  • test helpers for temporary modules, test apps, and provider overrides
  • a CLI (bustan init) for scaffolding new applications into existing uv projects

Supported Public API

The first compatibility boundary is intentionally small.

Stable import paths:

  • bustan
  • bustan.errors
  • bustan.testing

Example supported imports:

from bustan import __version__, Controller, Get, Injectable, Module, create_app
from bustan.errors import ProviderResolutionError
from bustan.testing import create_test_app, override_provider

The generated API reference for the stable surface lives in docs/API_REFERENCE.md.

Guides

Open Source Project Docs

Examples

The repository includes focused examples beyond the minimal quickstart:

  • examples/blog_api/app.py: a small reference-style blog API with request context and module exports
  • examples/multi_module_app/app.py: feature modules with exported providers
  • examples/graph_inspection/app.py: print the discovered module graph
  • examples/request_scope_pipeline_app/app.py: request-scoped providers shared across guards, interceptors, and controllers
  • examples/testing_overrides/app.py: test-time provider overrides with bustan.testing

Run them with:

uv run python examples/blog_api/app.py
uv run python examples/graph_inspection/app.py
uv run python examples/request_scope_pipeline_app/app.py
uv run python examples/testing_overrides/app.py

Testing Utilities

bustan.testing is the intended 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 override_provider() when you want a scoped override that is restored automatically:

from bustan.testing import override_provider


with override_provider(application, GreetingService, FakeGreetingService()):
	...

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
  • 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
  • move to a dedicated docs site if the docs set outgrow README-driven discovery

Development

Install hooks once after cloning if you want local pre-commit and pre-push checks:

uv run lefthook install

For full 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 examples scripts
uv run pytest
uv run pytest --cov=bustan --cov-report=term-missing --cov-report=xml

Project Direction

Bustan is trying to be opinionated about application structure, not to hide the underlying platform or compete on benchmark claims.

If you want a small ASGI core with explicit module boundaries, DI-managed services, 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

bustan-1.1.1.tar.gz (59.0 kB view details)

Uploaded Source

Built Distribution

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

bustan-1.1.1-py3-none-any.whl (89.8 kB view details)

Uploaded Python 3

File details

Details for the file bustan-1.1.1.tar.gz.

File metadata

  • Download URL: bustan-1.1.1.tar.gz
  • Upload date:
  • Size: 59.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bustan-1.1.1.tar.gz
Algorithm Hash digest
SHA256 6262c566f35b63f2649226ae04a9df40714c9d617b5fefafa954a81abfd9f0b6
MD5 a6c945d98a9300e2b5abb939810f5ce3
BLAKE2b-256 2ea85ca88c3d219c83224d3dd92168c1c530896e7218ad5785514f2dfd64a459

See more details on using hashes here.

Provenance

The following attestation bundles were made for bustan-1.1.1.tar.gz:

Publisher: release-please.yml on bustanhq/bustan

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bustan-1.1.1-py3-none-any.whl.

File metadata

  • Download URL: bustan-1.1.1-py3-none-any.whl
  • Upload date:
  • Size: 89.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bustan-1.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 36810cc9bd6e1b0c0d4652742fda57cabc0149831d94a3dfc2e1bfc5892b3c48
MD5 947834c3e1d8fa96ac4c75cba3d501ae
BLAKE2b-256 8ca09171c694778f3444565ae4fa9968e9f61173278778efc1f2b5ddbf27a3e5

See more details on using hashes here.

Provenance

The following attestation bundles were made for bustan-1.1.1-py3-none-any.whl:

Publisher: release-please.yml on bustanhq/bustan

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

1.1.1 This release

2 files

1.1.0

2 files

1.0.1

2 files

1.0.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