Spring-inspired bootstrap package for Python
Project description
alt-python-boot-lib
Application bootstrap for the alt-python framework. Provides the one-call
Boot.boot() entry point, the startup banner, and the MiddlewarePipeline
used by all HTTP and serverless adapters.
Inspired by Spring Boot's
SpringApplication.run() auto-configuration and application context lifecycle.
Part of the alt-python/boot monorepo.
Install
uv add alt-python-boot-lib # or: pip install alt-python-boot-lib
Requires Python 3.12+, alt-python-config, alt-python-logger, and
alt-python-cdi.
Quick Start
from boot import Boot
from cdi import Context, Singleton
class GreetingService:
def __init__(self):
self.config = None # CDI-autowired
def greet(self, name: str) -> str:
return f"Hello, {name}!"
class Application:
def __init__(self):
self.greeting_service = None # CDI-autowired
def run(self):
print(self.greeting_service.greet("world"))
Boot.boot({
'contexts': [
Context([Singleton(GreetingService), Singleton(Application)])
]
})
Boot.boot() resolves config from the current directory, prints the startup
banner, and calls application.run() on the Application bean.
API
from boot import Boot, MiddlewarePipeline, RequestLoggerMiddleware, ErrorHandlerMiddleware, NotFoundMiddleware
Boot
Boot.boot(options=None)
Bootstrap the application. Loads config, wires the CDI container, prints the
banner, and calls run() on the Application bean.
Boot.boot({
'contexts': [Context([Singleton(MyService), Singleton(Application)])]
})
Options:
| Key | Type | Description |
|---|---|---|
contexts |
list[Context] |
CDI contexts to wire |
config |
config-like | Config source (default: auto-discovered via ConfigFactory) |
Returns the ApplicationContext after start() completes.
Boot.test(options=None)
Test bootstrap. Suppresses the startup banner and captures log output
in-memory. Accepts the same options as Boot.boot().
def test_my_service():
ctx = Boot.test({
'contexts': [Context([Singleton(MyService)])]
})
svc = ctx.get('my_service')
assert svc.greet("world") == "Hello, world!"
Boot.root(name, default=None)
Read a value from the global boot context.
config = Boot.root('config')
logger_factory = Boot.root('logger_factory')
MiddlewarePipeline
The CDI middleware pipeline — the Python equivalent of Spring Security's filter chain, applied uniformly across all HTTP and serverless adapters.
MiddlewarePipeline.compose(middlewares, final_handler)
Composes an ordered list of middleware instances and a final handler into a single async callable.
pipeline = MiddlewarePipeline.compose(middlewares, dispatch)
response = await pipeline(request)
compose() is called once per request. Middleware run in order (lowest order
value first). Each middleware calls await next_fn(request) to pass control
down the chain; returning without calling next_fn short-circuits the pipeline.
MiddlewarePipeline.collect(ctx)
Collects all CDI components that declare __middleware__ = {"order": N} from
an ApplicationContext, filters out uninstantiated entries, and returns them
sorted by order.
middlewares = MiddlewarePipeline.collect(app_ctx)
Writing Middleware
A middleware component is a plain CDI class with __middleware__ = {"order": N}
as a class attribute and an async def handle(self, request, next_fn) method.
Lower order values run first (outermost).
class AuthMiddleware:
__middleware__ = {"order": 5}
def __init__(self):
self.logger = None # CDI-autowired
async def handle(self, request, next_fn):
token = request.get("headers", {}).get("authorization", "").removeprefix("Bearer ")
if not token:
return {"statusCode": 401, "body": {"error": "Unauthorized"}}
return await next_fn({**request, "user": {"token": token}})
Register it in the CDI context — no extra wiring needed:
from boot_aws_lambda import lambda_starter
from cdi import Context, Singleton
context = Context([
*lambda_starter(),
Singleton(AuthMiddleware), # auto-detected via __middleware__
Singleton(TodoController),
])
Normalised Request Shape
All adapters present the same request dict to middleware:
{
"method": "GET",
"path": "/todos/42",
"params": {"id": "42"},
"query": {"page": "1"},
"headers": {...},
"body": {...},
"ctx": application_context,
}
Middleware written against this shape works identically across Lambda, Azure Functions, GCP Cloud Functions, FastAPI, and Flask adapters.
Built-in Middleware
Every *_starter() function registers these three middleware components:
| Class | Order | Behaviour |
|---|---|---|
RequestLoggerMiddleware |
10 | Logs METHOD /path → status (Xms) at verbose level |
ErrorHandlerMiddleware |
20 | Converts unhandled exceptions to JSON error responses |
NotFoundMiddleware |
30 | Returns 404 when no route matches |
print_banner(config=None, logger=None)
Prints the startup banner to stdout. Called automatically by Boot.boot().
Pass config with boot.banner-mode: off to suppress:
from boot import print_banner
print_banner() # prints the banner
print_banner(config) # suppressed if boot.banner-mode == "off"
Testing
Use Boot.test() to suppress the banner and capture logs during tests:
from boot import Boot
from cdi import Context, Singleton
def test_greet():
ctx = Boot.test({
'contexts': [Context([Singleton(GreetingService)])]
})
assert ctx.get('greeting_service').greet("world") == "Hello, world!"
Boot.test() wraps the config in a PropertySourceChain with
boot.banner-mode: off prepended, and uses CachingLoggerFactory so log
output is captured in-memory rather than printed.
Spring Attribution
The Boot lifecycle maps to Spring Boot's SpringApplication.run():
| Spring | alt-python-boot |
|---|---|
SpringApplication.run() |
Boot.boot() |
ApplicationContext.refresh() + start() |
ApplicationContext.start() |
@SpringBootApplication banner |
print_banner() |
Spring Security FilterChain |
MiddlewarePipeline |
Filter.doFilter(req, res, chain) |
handle(request, next_fn) |
License
MIT
Project details
Release history Release notifications | RSS feed
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 alt_python_boot_lib-1.1.1.tar.gz.
File metadata
- Download URL: alt_python_boot_lib-1.1.1.tar.gz
- Upload date:
- Size: 6.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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 |
d2204b43ce2dba35d0b578ee36d01a4c9cc3ab75151b8cb4e99ab991b6c325b1
|
|
| MD5 |
9c5d1b302d26e232e562f66cc322497a
|
|
| BLAKE2b-256 |
2d4af05663acdb8f93add863a0219cce2b7b955e3e7eb1f9d918220ebca9d050
|
File details
Details for the file alt_python_boot_lib-1.1.1-py3-none-any.whl.
File metadata
- Download URL: alt_python_boot_lib-1.1.1-py3-none-any.whl
- Upload date:
- Size: 8.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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 |
5e852201c14370622e290507f75b7eb2c071258427dbca11ef4f9ee5eba5f988
|
|
| MD5 |
7ed16017ba16ce3de2ecdffee833b4d1
|
|
| BLAKE2b-256 |
c395c99b02a9f64b06637a49868fa402c1888c67dc70a406885e6ffe3184d0b2
|