Python API reference¶
Generated from docstrings with Sphinx autodoc. Public modules:
FluxLit public API.
FluxLit unifies FastAPI and Streamlit behind one ASGI gateway: use
FluxLit for routes and pages, ApiClient
from Streamlit for server-side HTTP to your API, and FluxLitTestClient
in tests (with apptest_select_page() and
assert_no_streamlit_exception helpers).
The fluxlit console script (see fluxlit.cli) runs the combined dev/prod stack.
Stable surface: symbols in __all__ below are the primary supported imports for
applications and tests; treat other submodules as internal unless documented in
Support matrix or API reference.
Optional auth ergonomics (after pip install "fluxlit[auth]"):
fluxlit.app.FluxLit.make_jwt_bearer(),
fluxlit.app.FluxLit.attach_oidc_login(), and
fluxlit.auth.prepare_streamlit_api_client() reduce boilerplate when using
FLUXLIT_JWT_* and OIDC BFF env vars.
- class fluxlit.Cookie(name)[source]¶
Bases:
objectInject a cookie value by name.
Values come from overrides,
set_page_cookie_context(), orst.context.cookies.
- class fluxlit.Depends(dependency=None, *, use_cache=True)[source]¶
Bases:
objectDeclare a page dependency callable
( -> T)resolved before the handler runs.
- class fluxlit.FluxLitPublicUrls(fluxlit)[source]¶
Bases:
objectBuild browser-visible URLs for the Streamlit shell vs the mounted FastAPI API.
App base — origin plus the public mount (
FLUXLIT_ROOT_PATH/streamlit_public_path). This is where Streamlit pages live (outside the API prefix).API base — app base plus
api_mount_path(default/api). Liveness, readiness, OpenAPI, and Swagger live under this prefix on the public gateway.When
FLUXLIT_PUBLIC_BASE_URLis set to an absolute URL, it is preferred for the origin (and, if it includes a path, as the app base when that path matches the configured public mount). Otherwise the current request’s host/scheme is used (includingX-Forwarded-*when Uvicorn proxy headers are enabled).- api_base(request)[source]¶
Return the browser-visible base URL for the FastAPI app (includes
api_mount_path).- Return type:
- app_base(request)[source]¶
Return the browser-visible base URL for Streamlit (no
api_mount_path).- Return type:
- for_page(request, path, *, query=None)[source]¶
Return a browser URL for a Streamlit page path (under
app_base(), not/api).pathis a URL path such as"/"or"/reports".queryvalues are percent-encoded; use this for deep links to Streamlit pages.- Return type:
- page_url(request, path, *, query=None)[source]¶
Alias for
for_page()(invite links, password reset, and other deep links).Prefer this name in app code and docs when the intent is a shareable page URL rather than an internal path join.
- Return type:
- class fluxlit.Header(name)[source]¶
Bases:
objectInject a header value by name (from
set_page_header_context()or overrides).
- class fluxlit.InMemorySessionStore(*, max_entries=5000, default_ttl_seconds=86400.0)[source]¶
Bases:
objectProcess-local
SessionStore(dev / single replica).Not safe across multiple Uvicorn workers or horizontal replicas without a shared backend.
- set(session_id, data, *, ttl_seconds=None)[source]¶
Persist data for session_id; optional time-to-live in seconds.
TTL semantics:
ttl_secondsisNone→ usedefault_ttl_seconds(which may itself beNonefor no expiry). A positive value sets a monotonic deadline.ttl_secondsof0does not mean “expire immediately”; it is treated like “no TTL window” for this write (same as a negative value would be if passed, though callers should useNonefor no expiry).- Return type:
Bases:
objectOrder registered pages by URL path (values not registered are ignored).
Paths are compared after
strip();"/"slugifies to"home"in the Streamlit entrypoint the same way asfluxlit.deep_links.match_nav_page().
- class fluxlit.PageMeta(**data)[source]¶
Bases:
BaseModelOptional metadata returned from a page handler or passed to
fluxlit.app.FluxLit.page().Fields mirror
streamlit.set_page_config()where applicable. Values returned after the handler runs cannot always update the browser title or layout (Streamlit only allowsset_page_configas the first command); usefluxlit.app.FluxLit.page()page_meta=for static per-page config applied at the start of each run. Returned instances still drive sidebar breadcrumbs and the page manifest.- model_config: ClassVar[ConfigDict] = {'extra': 'ignore'}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class fluxlit.Query(*, description='')[source]¶
Bases:
objectOptional metadata for a query-shaped parameter (manifest / docs).
- class fluxlit.SessionModel(st, *, extra='ignore')[source]¶
Bases:
objectRead/write a Pydantic model to Streamlit session state keys matching field names.
- class fluxlit.SessionStore(*args, **kwargs)[source]¶
Bases:
ProtocolServer-side persistence for URL-bound session blobs (JSON-serializable dicts).
- fluxlit.apptest_assert_no_errors(at)[source]¶
Raise
AssertionErrorifAppTestcapturedst.exceptionorst.error.Use after
FluxLitTestClient.streamlit()(or anyAppTestrun) to fail fast when the script surfaced an error to users.- Return type:
- fluxlit.apptest_select_page(at, client, *, target, page, internal_api_base=None, extra_sys_path=None, page_key='page', page_overrides=None)[source]¶
Set
pagequery key andrun()with the sameFLUXLIT_*patch asstreamlit.AppTest.rundoes not automatically keepFLUXLIT_*variables from the firstFluxLitTestClient.streamlit()call; this helper re-applies the same patchFluxLitTestClient.streamlit()uses so the entrypoint can resolvetargetagain after you changeat.query_params.- Return type:
- fluxlit.assert_no_streamlit_exception(at)[source]¶
Alias for
apptest_assert_no_errors()(StreamlitAppTestnaming).- Return type:
- fluxlit.ensure_url_session(st, store, *, param=None, initial=None, ttl_seconds=None)[source]¶
Ensure
st.query_params[param]exists; mint id, seed store, set query param.Returns the session id (existing or new). If the query param cannot be set (read-only
query_params), still returns a new id and persists initial so callers can surface a warning or use client-side navigation.- Return type:
- fluxlit.hydrate_url_session(st, store, *, param=None, merge=True, blob=None)[source]¶
If
st.query_params[param]is set, load the store payload intost.session_state.merge (default):
session_state.setdefault(k, v)for each key in the blob so in-flight widget state wins over stale store keys on first paint.If the param is missing, returns
Noneand does nothing.If the param is present but the store has no entry, returns the session id without mutating
session_state(caller may seed withSessionStore.set()).
Returns the session id string when the query param is present, else
None.
- fluxlit.hydrate_url_session_typed(st, store, model, *, param=None, merge=True, strict=False)[source]¶
Like
hydrate_url_session(), then validate the store payload as model.Validates the store blob before merging into
st.session_stateso invalid payloads do not partially hydrate the UI session.Returns
(session_id_or_none, validated_model_or_none). On validation failure, when strict is false, returns(sid, None); when strict is true, raisespydantic.ValidationError.
- fluxlit.new_session_id()[source]¶
Return a new URL-safe opaque session identifier (≥128 bits).
- Return type:
- fluxlit.parse_query_params(st, model, *, strict=False)[source]¶
Build model from
st.query_params.For multi-value keys, Streamlit may expose a list: a single-element list is coerced to that element; multiple values are passed through as a list.
On
pydantic.ValidationError, callsst.errorwith a short message unless strict is true, in which case the exception is re-raised.
- fluxlit.persist_url_session(st, store, *, param=None, ttl_seconds=None)[source]¶
Write current
st.session_state(shallow dict copy) to the store forparamid.Returns the session id if the param is present, else
None.Values are copied best-effort; remote stores should JSON-encode—non-JSON-safe values may need app-side filtering before
SessionStore.set().If snapshotting
session_statefails, the store is not updated but the session id is still returned; a warning is logged (with traceback whenFLUXLIT_DEBUG=1).
- fluxlit.reset_trace_hook(token)[source]¶
Reset the tracing hook installed by
set_trace_hook().- Return type:
- fluxlit.set_trace_hook(hook)[source]¶
Install a tracing hook for the current context and return a reset token.
- fluxlit.streamlit_main_path()[source]¶
Return FluxLit’s supported Streamlit entry script for
AppTest.from_file.Use this instead of constructing a path from
fluxlit.__file__; the helper is part of FluxLit’s testing API and can keep working if the internal package layout changes.- Return type:
- fluxlit.trace_span(name, attributes)[source]¶
Return a context manager for an optional span.
If no hook is installed, this is a no-op. Hook exceptions intentionally bubble up so integrations fail loudly during development instead of hiding broken instrumentation.
- Return type:
The FluxLit application object: FastAPI (.api) plus Streamlit pages.
- class fluxlit.app.FluxLit(*, title=None, settings=None, import_target=None, fastapi_kwargs=None, streamlit_run_args=None, streamlit_page_config=None, session_store=None)[source]¶
Bases:
Generic[SettingsT]Combine a FastAPI application and registered Streamlit pages in one object.
Use
apifor HTTP routes, dependencies, and OpenAPI (mounted underapi_mount_pathon the public gateway). Useurlsfor browser-visible links (app root vs API prefix, health, docs). Usepage()ordiscover_pages()to register Streamlit UI; the runtime buildsst.navigationfrom registered pages.Security (optional):
make_jwt_bearer()readsFLUXLIT_JWT_*fromsettings;attach_oidc_login()registers OIDC BFF routes (call at most once per instance) usingFLUXLIT_PUBLIC_BASE_URLandFLUXLIT_OIDC_BFF_SECRETwhen you do not pass secrets explicitly.GET /healthz(liveness) andGET /readyz(readiness vs Streamlit) are registered onapi(hidden from OpenAPI).- Parameters:
title (
str|None) – If set, overridesFluxlitSettings.titlefor this instance.settings (
FluxlitSettings|None) – Explicit settings; default isFluxlitSettingsloaded from env /.env.import_target (
str|None) – Optionalmodule:attrstring for this instance (same asFLUXLIT_APP/fluxlit.tomltarget). Use when the module name is notapp(e.g.main:app) souvicornand the Streamlit child import the right object. If unset, resolution follows env and project file; seefluxlit.runtime.resolve_import_target_for_unified().fastapi_kwargs (
dict[str,Any] |None) – Extra keyword arguments forwarded tofastapi.FastAPI(lifespan,dependencies,openapi_url,docs_url, etc.).titleandroot_pathalways come fromFluxlitSettingsso the API stays aligned with the gateway and Streamlit public path.streamlit_run_args (
Sequence[str] |None) – Optional extrastreamlit runCLI tokens; appended tostreamlit_run_cli_argsonsettings.streamlit_page_config (
dict[str,TypeAliasType] |None) – Optional keys merged intostreamlit_page_configforstreamlit.set_page_config()in the Streamlit process.session_store (
SessionStore|None) – OptionalSessionStoreforSessionStore-annotated page parameters.
- attach_oidc_login(oidc, *, first_party_secret=None, **bff_overrides)[source]¶
Register OIDC login / callback / token-exchange routes on
api.Uses
public_base_urlfor redirects unless you passpublic_base_url=...inbff_overrides. The first-party JWT signing secret comes fromfirst_party_secretoroidc_bff_secret(FLUXLIT_OIDC_BFF_SECRET).Returns the
fastapi.APIRouterthat was included (same asfluxlit.oidc.register_oidc_bff_routes()).- Raises:
ValueError – If this method is called more than once on the same
FluxLitinstance (duplicate auth routes).- Return type:
- build_page_manifest(*, version=1)[source]¶
JSON page manifest; see
fluxlit.pages.manifest.build_page_manifest().
- discover_pages(directory, *, package)[source]¶
Load Streamlit page modules and call
register(self)on each.Imports the subpackage
{package}.{directory}, then every submodule (skipping packages and names starting with_). If a module definesregister(app: FluxLit) -> None, it is invoked; implementations typically attach handlers withpage()insideregister.Registered pages are sorted by
(path, title)for stable navigation order.- Parameters:
- Return type:
Self- Returns:
selffor chaining.- Raises:
TypeError – If
packageis not a package.ImportError – If
{package}.{directory}cannot be imported.
Note
If a page module’s
register(app)raises after earlier modules ran, pages from those modules remain registered (best-effort; no rollback).
- get_client()[source]¶
Return an
ApiClientfor server-side API calls.Uses
FLUXLIT_INTERNAL_API_BASEwhen set (as in the managed runtime). Whendebugis true, the client forwardsX-Request-IDto the API for log correlation with the gateway.- Return type:
- make_jwt_bearer()[source]¶
JWT
JWTBearerfromsettings(FLUXLIT_JWT_*).Requires
jwt_issuer,jwt_audience, and eitherjwt_hs256_secretorjwt_jwks_url. RaisesValueErrorwith env-oriented hints if misconfigured.- Return type:
Set optional sidebar ordering for registered pages (by URL path).
- Return type:
Self
- page(path, *, title=None, icon=None, tags=None, page_meta=None)[source]¶
Decorator registering a Streamlit page at a URL path.
The decorated callable should accept
(st, client)wherestis the Streamlit module andclientis anApiClientfor your mounted API. Additional parameters may be injected (seedocs/streamlit-pages-typing.md).- Parameters:
path (
str) – URL path segment for Streamlit (e.g."/","/reports").title (
str|None) – Sidebar / navigation title; defaults from the function name.icon (
str|None) – Optional icon forstreamlit.navigation/st.Page.tags (
Sequence[str] |None) – Optional tags for manifests and tooling.page_meta (
PageMeta|None) – StaticPageMetamerged intost.Pagewhere Streamlit supports it (e.g.page_iconas icon).
- Return type:
- Returns:
Decorator that registers the function and returns it unchanged.
- property pages: list[tuple[str, str, Callable[[...], Any]]]¶
(path, title, handler)tuples (backward compatible).
- property urls: FluxLitPublicUrls¶
Browser-visible URL helpers for this app (app root vs
api_mount_path).
HTTP client for calling the FastAPI app from Streamlit (server-side, same process host).
Typing mirrors httpx.Client via httpx._types / httpx._client (see
tests/test_httpx_import_contract.py); re-run tests after httpx upgrades.
- class fluxlit.client.ApiClient(base_url=None, *, timeout=30.0, default_headers=None, auth_header_factory=None, propagate_request_id=False)[source]¶
Bases:
objectSync HTTPX client scoped to your gateway-mounted API.
Paths are relative to the API base (including the
/apiprefix in the base URL). For example useclient.get("/users"), notclient.get("/api/users"). Paths must not be absolute URLs (http://...) or scheme-relative (//...); those are rejected withValueErrorso user-controlled strings cannot bypassbase_urlto another host.Use
for_fluxlit()orwith_bearer()when routes requireAuthorization.The runtime sets
FLUXLIT_INTERNAL_API_BASE(e.g.http://127.0.0.1:8000/api) for Streamlit subprocesses so defaults work without passingbase_url.- delete(path, *, params=None, headers=None, cookies=None, auth=<httpx._client.UseClientDefault object>, follow_redirects=<httpx._client.UseClientDefault object>, timeout=<httpx._client.UseClientDefault object>, extensions=None)[source]¶
DELETErequest.- Return type:
httpx.Response
- classmethod for_fluxlit(*, bearer_token=None, auth_header_factory=None, base_url=None, timeout=30.0, default_headers=None, propagate_request_id=False)[source]¶
Convenience constructor with static bearer token or factory (mutually exclusive).
- Return type:
- get(path, *, params=None, headers=None, cookies=None, auth=<httpx._client.UseClientDefault object>, follow_redirects=<httpx._client.UseClientDefault object>, timeout=<httpx._client.UseClientDefault object>, extensions=None)[source]¶
GETrequest.- Return type:
httpx.Response
- get_model(path, model, *, params=None, headers=None, cookies=None, auth=<httpx._client.UseClientDefault object>, follow_redirects=<httpx._client.UseClientDefault object>, timeout=<httpx._client.UseClientDefault object>, extensions=None)[source]¶
GETand parse JSON into a Pydantic model (raises on 4xx/5xx or validation).- Parameters:
path (str) – Relative API path.
model (type[T]) – Pydantic model type for the response body.
kwargs (Remaining) – forwarded to
get().
- Return type:
T
- post(path, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth=<httpx._client.UseClientDefault object>, follow_redirects=<httpx._client.UseClientDefault object>, timeout=<httpx._client.UseClientDefault object>, extensions=None)[source]¶
POSTrequest.- Return type:
httpx.Response
- post_model(path, response_model, *, body=None, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth=<httpx._client.UseClientDefault object>, follow_redirects=<httpx._client.UseClientDefault object>, timeout=<httpx._client.UseClientDefault object>, extensions=None)[source]¶
POSTJSON body and parse the response asresponse_model.- Parameters:
- Return type:
T
- put(path, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth=<httpx._client.UseClientDefault object>, follow_redirects=<httpx._client.UseClientDefault object>, timeout=<httpx._client.UseClientDefault object>, extensions=None)[source]¶
PUTrequest.- Return type:
httpx.Response
- request(method, path, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth=<httpx._client.UseClientDefault object>, follow_redirects=<httpx._client.UseClientDefault object>, timeout=<httpx._client.UseClientDefault object>, extensions=None)[source]¶
Send a request;
pathmay omit a leading slash.- Raises:
ValueError – If
pathis an absolute or scheme-relative URL (see class doc).- Return type:
httpx.Response
- with_bearer(bearer_token)[source]¶
Return a new client with the same base URL and options plus
Authorization: Bearer.Use on the injected page client (no auth by default) when you already have a token in
st.session_stateand want the sameApiClientsurface without callingfor_fluxlit(). If this client already has anauth_header_factory, the new factory merges those headers first, then setsAuthorizationto this bearer (call-time headers still win on key clash).The returned client owns a separate
httpxconnection pool; close it when done or use awithblock.- Return type:
Configuration: settings, project file defaults, and JSON value typing.
- class fluxlit.config.FluxlitSettings(**data)[source]¶
Bases:
BaseSettingsRuntime configuration for FluxLit, CLI defaults, and FastAPI construction.
Values are read from environment variables prefixed with
FLUXLIT_and from a.envfile in the working directory if present. Unknown env keys are ignored.CLI commands such as
fluxlit devmerge these withfluxlit.toml/pyproject[tool.fluxlit]and explicit flags; seefluxlit.config.projectfor precedence.Key fields:
title— FastAPI / UX title.gateway_host/gateway_port— default bind address for Uvicorn.api_mount_path— public URL prefix for the API (default/api).root_path— ASGI root when behind a reverse proxy.enable_request_logging— per-request INFO logs on the FastAPI app.enable_gateway_access_log— per-request INFO logs on the gateway (structured extras).trust_proxy/forwarded_allow_ips— Uvicorn proxy trust (e.g. Posit Connect).streamlit_public_path— optional subpath whenroot_pathis unset.streamlit_run_cli_args— extrastreamlit runCLI tokens (JSON list in env).streamlit_page_config— keys forwarded tost.set_page_config(JSON object in env).cors_middleware_kwargs— extra kwargs forCORSMiddlewarewhen CORS is enabled.experimental_yield_pages/async_page_depends— experimental; semantics and promotion criteria are indocs/support-matrix(ExperimentalFluxlitSettings).
- model_config: ClassVar[SettingsConfigDict] = {'arbitrary_types_allowed': True, 'case_sensitive': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_exit_on_error': True, 'cli_flag_prefix_char': '-', 'cli_hide_none_type': False, 'cli_ignore_unknown_args': False, 'cli_implicit_flags': False, 'cli_kebab_case': False, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_prefix': '', 'cli_prog_name': None, 'cli_shortcuts': None, 'cli_use_class_docs_for_groups': False, 'enable_decoding': True, 'env_file': '.env', 'env_file_encoding': 'utf-8', 'env_ignore_empty': False, 'env_nested_delimiter': None, 'env_nested_max_split': None, 'env_parse_enums': None, 'env_parse_none_str': None, 'env_prefix': 'FLUXLIT_', 'env_prefix_target': 'variable', 'extra': 'ignore', 'json_file': None, 'json_file_encoding': None, 'nested_model_default_partial_update': False, 'protected_namespaces': ('model_validate', 'model_dump', 'settings_customise_sources'), 'secrets_dir': None, 'toml_file': None, 'validate_default': True, 'yaml_config_section': None, 'yaml_file': None, 'yaml_file_encoding': None}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_post_init(context, /)¶
This function is meant to behave like a BaseModel method to initialize private attributes.
It takes context as an argument since that’s what pydantic-core passes when calling it.
- type fluxlit.config.JsonValue = _AllowAnyJson]¶
- class fluxlit.config.ProjectConfig(target=None, gateway_host=None, gateway_port=None, log_level=None, api_mount_path=None, root_path=None)[source]¶
Bases:
objectStructured defaults read from a project file (not environment).
Populated from top-level keys in
fluxlit.tomlor from[tool.fluxlit]inpyproject.toml. Only known keys are stored; others are ignored.Fields mirror CLI-related settings:
target(e.g.app:app), bind defaults,log_level, and optionalapi_mount_path/root_path.
- fluxlit.config.load_project_config(cwd=None)[source]¶
Parse
fluxlit.tomlor[tool.fluxlit]inpyproject.toml.If both files exist,
fluxlit.tomltakes precedence. ReturnsNoneif neither file exists, the relevant section is missing, the file is not valid TOML, or the top-level value is not a table (dict).
- fluxlit.config.resolve_binding(*, cli_host, cli_port, cli_log_level, pc, settings_gateway_host, settings_gateway_port, settings_log_level)[source]¶
Resolve host, port, and log level: CLI > project file >
FluxlitSettings.settings_*arguments should come from the loadedFluxLitinstance (already merged with environment).
- fluxlit.config.resolve_target(cli_target, pc)[source]¶
Pick the app import target: CLI argument, then project file, then
app:app.- Return type:
Load optional project defaults from fluxlit.toml or pyproject.toml.
- class fluxlit.config.project.ProjectConfig(target=None, gateway_host=None, gateway_port=None, log_level=None, api_mount_path=None, root_path=None)[source]¶
Bases:
objectStructured defaults read from a project file (not environment).
Populated from top-level keys in
fluxlit.tomlor from[tool.fluxlit]inpyproject.toml. Only known keys are stored; others are ignored.Fields mirror CLI-related settings:
target(e.g.app:app), bind defaults,log_level, and optionalapi_mount_path/root_path.
- fluxlit.config.project.load_project_config(cwd=None)[source]¶
Parse
fluxlit.tomlor[tool.fluxlit]inpyproject.toml.If both files exist,
fluxlit.tomltakes precedence. ReturnsNoneif neither file exists, the relevant section is missing, the file is not valid TOML, or the top-level value is not a table (dict).
- fluxlit.config.project.resolve_binding(*, cli_host, cli_port, cli_log_level, pc, settings_gateway_host, settings_gateway_port, settings_log_level)[source]¶
Resolve host, port, and log level: CLI > project file >
FluxlitSettings.settings_*arguments should come from the loadedFluxLitinstance (already merged with environment).
- fluxlit.config.project.resolve_target(cli_target, pc)[source]¶
Pick the app import target: CLI argument, then project file, then
app:app.- Return type:
Logging helpers: request IDs, JSON formatters, redaction for safe access logs.
- class fluxlit.logging.JsonLogFormatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)[source]¶
Bases:
FormatterEmit one JSON object per log line, including merged
extrafields.- format(record)[source]¶
Format the specified record as text.
The record’s attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message.
- Return type:
- fluxlit.logging.new_request_id()[source]¶
Generate a new opaque request ID (UUID4 string).
- Return type:
- fluxlit.logging.redact_authorization(value)[source]¶
Return a placeholder for an
Authorizationheader value.- Return type:
- fluxlit.logging.redact_query_string(query_string, *, sensitive_keys=None)[source]¶
Return query_string with listed keys’ values replaced by
<redacted>.query_string is the raw
key=value&...portion (no leading?). Unknown or malformed segments are returned unchanged when parsing fails.- Return type:
- fluxlit.logging.reset_request_id(token)[source]¶
Restore the previous context after
set_request_id()(typically infinally).- Return type:
- fluxlit.logging.sanitize_headers(headers)[source]¶
Copy headers with
AuthorizationandCookievalues redacted.
- fluxlit.logging.set_request_id(value)[source]¶
Bind
valueintorequest_id_ctx; returns a token forreset_request_id().
ASGI gateway: dispatch api_prefix to FastAPI, proxy everything else to Streamlit.
HTTP requests and WebSockets are forwarded to an upstream base URL (the Streamlit
server). The client’s Host header is preserved on the upstream request so
Streamlit sees the public gateway host/port (e.g. 127.0.0.1:8777), matching
the browser’s Origin; otherwise WebSocket same-origin checks fail and the UI
stays blank/black.
Request IDs are taken from X-Request-ID or generated, stored in
fluxlit.logging for the duration of each request, and re-sent to
Streamlit on proxied HTTP and WebSocket hops as authoritative X-Request-ID (the
gateway wins over any client-supplied value on that upstream leg).
Top-level /docs, /redoc, and /openapi.json redirect to the same paths under
api_prefix so Swagger is not accidentally proxied to Streamlit (which would look
like a blank page).
- class fluxlit.gateway.GatewayProxyOptions(connect_timeout=30.0, read_timeout=120.0, max_proxy_body_bytes=0, max_concurrent_upstream_http=0, httpx_max_connections=0, httpx_max_keepalive_connections=0, ws_open_timeout_s=30.0, ws_ping_interval_s=None, ws_ping_timeout_s=None, ws_close_timeout_s=None, ws_max_message_bytes=None, forward_client_headers_http=frozenset({}))[source]¶
Bases:
objectUpstream HTTP/WebSocket tuning for
fluxlit.gateway.build_gateway().Mirrors
FluxlitSettingsgateway fields.
- fluxlit.gateway.build_gateway(api_app, upstream_base, *, upstream_resolver=None, access_log=False, api_prefix='/api', root_mount='', proxy_settings=None)[source]¶
Build the composite ASGI application used as Uvicorn’s entrypoint.
Routes whose path equals
api_prefixor starts withapi_prefix/are forwarded toapi_appwith that prefix stripped frompathandraw_path. All other HTTP traffic and WebSockets are reverse-proxied toupstream_base(typically the internal Streamlit origin), or to the URL returned byupstream_resolverwhen that is provided (evaluated per request).Lifespan events are delegated only to
api_app.- Parameters:
api_app (
Callable[[MutableMapping[str,Any],Callable[[],Awaitable[MutableMapping[str,Any]]],Callable[[MutableMapping[str,Any]],Awaitable[None]]],Awaitable[None]]) – Inner FastAPI / Starlette app (mount path not included in its routes).upstream_base (
str) – Base URL for Streamlit whenupstream_resolveris unset.upstream_resolver (
Callable[[],str] |None) – If set, called for each proxied request to get the current upstream base (e.g. after Streamlit restarts on a new port).upstream_baseis ignored for proxying when this is set.access_log (
bool) – If True, emit one INFO log per request with structuredextrafields.api_prefix (
str) – Public URL prefix for the API (default/api).root_mount (
str) – Optional browser-visible path prefix when the app is published under a subpath (e.g. Posit Connect / Workbench). Must matchroot_pathand Streamlitserver.baseUrlPath. When the proxy forwards the full path, this strip is applied before dispatch; Streamlit still receives paths that include the prefix.proxy_settings (
FluxlitSettings|None) – OptionalFluxlitSettingsfor upstream timeouts, body limits, concurrency, and WebSocket tuning (defaults match historical hardcoded gateway behavior when omitted).
- Return type:
Callable[[MutableMapping[str,Any],Callable[[],Awaitable[MutableMapping[str,Any]]],Callable[[MutableMapping[str,Any]],Awaitable[None]]],Awaitable[None]]- Returns:
A callable ASGI3 application.
- fluxlit.gateway.normalize_api_mount_path(api_mount_path)[source]¶
Normalize the public API URL prefix for gateway dispatch and URL helpers.
Ensures a single leading
/and no trailing slash (except the root"/"). Empty or whitespace-only values fall back to"/api".- Return type:
- fluxlit.gateway.normalize_root_mount(raw)[source]¶
Normalize a public URL prefix (e.g. Posit Connect content path) for routing.
Returns
""when unset, otherwise a path starting with/and no trailing slash (except root"/"is not used — empty means no mount).- Return type:
- fluxlit.gateway.split_gateway_paths(path, root_mount)[source]¶
Split the ASGI path for dispatch vs Streamlit upstream.
Some reverse proxies forward the full public path (
/content/123/api/...). Others strip the mount and only forward the suffix (/api/...) while setting ASGIroot_path.normalize_root_mount()should match the browser-visible prefix configured for Streamlitserver.baseUrlPath.
Readiness probes for the unified runtime (Streamlit sidecar).
- async fluxlit.health.probe_streamlit_ready(*, timeout_s=0.5, upstream=None, settings=None)[source]¶
Return
(ok, detail)for whether the Streamlit upstream accepts HTTP traffic.When
FLUXLIT_STREAMLIT_UPSTREAM/ file state is unset (typical in bare FastAPI tests), returns(True, "not_configured").When configured, readiness requires an HTTP 2xx response from
GETon at least one candidate URL (see_streamlit_readiness_urls()). Other status codes are treated as not ready. When multiple URLs are probed and all fail,detailaggregates path and status (for exampleupstream_http_failed /:404;/myapp/:503).
Helpers to redact secrets from header dicts before logging or tracing.
- fluxlit.logging.redact.redact_authorization(value)[source]¶
Return a placeholder for an
Authorizationheader value.- Return type:
- fluxlit.logging.redact.redact_query_string(query_string, *, sensitive_keys=None)[source]¶
Return query_string with listed keys’ values replaced by
<redacted>.query_string is the raw
key=value&...portion (no leading?). Unknown or malformed segments are returned unchanged when parsing fails.- Return type:
- fluxlit.logging.redact.sanitize_headers(headers)[source]¶
Copy headers with
AuthorizationandCookievalues redacted.
Process orchestration: load FluxLit by import path, spawn Streamlit, run Uvicorn.
- fluxlit.runtime.asgi_from_fluxlit(fl, import_target)[source]¶
Build unified ASGI (gateway + Streamlit) for an existing
FluxLit.Use when you already hold the instance (e.g.
uvicorn main:app). import_target must be themodule:attrthe Streamlit subprocess imports; usefluxlit.runtime.resolve_import_target_for_unified()or setimport_target/fluxlit.toml/FLUXLIT_APP.Behavior matches
create_unified_app()(lifespan, sidecar, inner FastAPI hooks).
- fluxlit.runtime.create_gateway_app()[source]¶
ASGI factory for Uvicorn
--factoryreload mode.Reads
FLUXLIT_APP(import target), Streamlit upstream fromFLUXLIT_STREAMLIT_UPSTREAM_FILEorFLUXLIT_STREAMLIT_UPSTREAM, andFLUXLIT_API_PREFIXfrom the environment, then returnsfluxlit.gateway.build_gateway()over the loaded FastAPI app.- Return type:
Callable[[MutableMapping[str,Any],Callable[[],Awaitable[MutableMapping[str,Any]]],Callable[[MutableMapping[str,Any]],Awaitable[None]]],Awaitable[None]]- Returns:
An ASGI3 callable (same contract as
build_gateway()).- Raises:
RuntimeError – If
FLUXLIT_APPis unset or the upstream URL cannot be resolved.
- fluxlit.runtime.create_unified_app()[source]¶
ASGI factory for Uvicorn
--factory(same stack asfluxlit.app.FluxLit.__call__()).Requires
FLUXLIT_APP=module:attr. Preferuvicorn main:appwhenappis aFluxLitinstance so you do not need this factory or env indirection.
- fluxlit.runtime.default_pidfile_path(explicit=None)[source]¶
Path for
fluxlit dev|runPID file (current directory unless overridden).- Return type:
- fluxlit.runtime.find_free_port()[source]¶
Bind to
127.0.0.1:0and return the assigned ephemeral port.- Return type:
- fluxlit.runtime.internal_api_base_url(*, bind_host, port, api_mount_path)[source]¶
Build
FLUXLIT_INTERNAL_API_BASEfor the Streamlit child (same machine as gateway).bind_hostis the Uvicorn bind address; the URL uses a loopback-safe host when needed soApiClientcan connect from the sidecar process.- Return type:
- fluxlit.runtime.load_fluxlit(target)[source]¶
Import
module:attributeand ensure the object is aFluxLit.- Raises:
ValueError – If
targetis not amodule:attrstring.ModuleNotFoundError – If
modulecannot be imported (message includes a short hint).AttributeError – If
modulehas no such attribute.
- Return type:
- fluxlit.runtime.read_streamlit_upstream_url()[source]¶
Current Streamlit base URL from
write_streamlit_upstream_state()or plain env.- Return type:
- fluxlit.runtime.resolve_import_target_for_unified(fl)[source]¶
Resolve
module:attrfor the Streamlit child and import stability.Order:
import_target,FLUXLIT_APP, then project file (fluxlit.toml/pyproject.toml), thenapp:app.- Return type:
- fluxlit.runtime.run_unified(target, *, host='127.0.0.1', port=8000, reload=False, reload_scope='gateway', log_level='info', proxy_headers=False, forwarded_allow_ips=None, pidfile=None, write_pidfile=True, workbench_mode=False)[source]¶
Start Streamlit on a free localhost port and Uvicorn on
host:port.Sets process environment so
create_gateway_app/ Streamlit entry can resolve the app and internal API base (loopback-safe URL derived fromhost,port, andapi_mount_path). If Streamlit exits, the gateway is stopped. On shutdown, the Streamlit child receives SIGINT / terminate / kill (platform-dependent).- Parameters:
target (
str) –module:fluxlit_instanceimport path.host (
str) – Uvicorn bind host.port (
int) – Uvicorn bind port (public).reload (
bool) – If True, use Uvicorn reload withcreate_gateway_app().reload_scope (
str) –gateway(default) orfull.fullalso restarts Streamlit when watched files change (requireswatchfiles); see CLI--reload-scope.log_level (
str) – Uvicorn log level.proxy_headers (
bool) – Forwarded touvicorn.Config.forwarded_allow_ips (
str|None) – Forwarded touvicorn.Config.pidfile (
Path|None) – Optional explicit path for the PID file (seedefault_pidfile_path()).write_pidfile (
bool) – If False, do not create a PID file (also skipped whenFLUXLIT_NO_PIDFILEis1/true/yes).workbench_mode (
bool) – If True, print a Workbench/Connect-oriented startup banner and forceproxy_headerson for Uvicorn (still mergeforwarded_allow_ips).
- Return type:
- fluxlit.runtime.shutdown_unified_process(pidfile=None, *, force=False, wait_s=5.0)[source]¶
Stop a stack started by
fluxlit.runtime.run_unified()using its PID file.Sends
SIGTERMto the recorded PID (the process running Uvicorn + supervision). On Windows, usestaskkill /T(and/Fwhen force is True) instead ofos.kill, which does not reliably terminate arbitrary processes.If
forceis True on POSIX, sendsSIGKILLafter wait_s if still running.
- fluxlit.runtime.update_streamlit_upstream_file(path, url)[source]¶
Replace the on-disk upstream URL (e.g. after restarting Streamlit on a new port).
- Return type:
- fluxlit.runtime.write_streamlit_upstream_state(url)[source]¶
Write url to a temp file and set env for the gateway resolver and subprocesses.
- Return type:
Test helpers: gateway-scoped HTTP client and Streamlit AppTest integration.
- class fluxlit.testing.FluxLitTestClient(app, api_prefix='/api', root_mount='')[source]¶
Bases:
objectTest harness that mirrors production routing (API prefix + gateway).
API —
apiis a StarletteTestClientwired throughfluxlit.gateway.build_gateway(), so paths include the configuredapi_prefixand/healthzbehaves like production.Public mount — Set
root_mount(orwith_root_path()) to simulate Workbench / Posit-style URLs where the browser path is{mount}{api_prefix}/…. Useapi_get()/api_post()so URLs are built correctly; optionalroot_path=on a single call builds a matching gateway for that request only.Streamlit —
streamlit()runsAppTestagainstfluxlit.streamlit.mainwith the same environment variables the runtime sets.AppTest multipage —
assert_no_streamlit_exception()fails onst.error/st.exception.select_page()sets?page=and reruns; the entrypoint honorsfluxlit.deep_links.match_nav_page()beforestreamlit.navigation(). Module-levelapptest_assert_no_errors(),assert_no_streamlit_exception(), andapptest_select_page()mirror the same behavior.- property api: TestClient¶
HTTP test client; non-API routes hit a dummy upstream (unused for
/apitests).
- api_get(path, *, root_path=None, **kwargs)[source]¶
GETrelative toapi_prefix(leading slash optional onpath).When
root_pathis set, the request uses that public mount for this call only (a separate gateway instance). Omit it to useroot_mounton this client.- Return type:
Response
- api_post(path, *, root_path=None, **kwargs)[source]¶
POSTrelative toapi_prefix(optional per-callroot_path).- Return type:
Response
- assert_docs_available(*, root_path=None)[source]¶
Assert OpenAPI JSON and Swagger UI are reachable through the gateway.
- Raises:
AssertionError – If OpenAPI is missing/invalid or
GET …/docsis not available (including when FastAPIdocs_urlis disabled).- Return type:
- assert_no_streamlit_exception(at)[source]¶
Fail if at collected
st.exceptionorst.errorblocks.- Return type:
- select_page(at, page, *, target, internal_api_base=None, extra_sys_path=None, page_key='page', page_overrides=None)[source]¶
Set query key and
run()again withtargetenv (same patch asstreamlit).- Return type:
- streamlit(*, target, internal_api_base=None, extra_sys_path=None, query_params=None, page_overrides=None)[source]¶
Execute Streamlit’s
AppTestagainstfluxlit.streamlit.main.Requires Streamlit >= 1.30 for
AppTest. PatchesFLUXLIT_APP,FLUXLIT_INTERNAL_API_BASE,FLUXLIT_API_PREFIX, andFLUXLIT_TESTSfor the duration of the run.- Parameters:
target (
str) – Import pathmodule:FluxLit(same as CLI).internal_api_base (
str|None) – Override internal API URL; default is a placeholder with the correctapi_prefixsuffix.extra_sys_path (
str|Path|None) – Optional directory prepended tosys.path(e.g. project root).query_params (
dict[str,str] |None) – Optional initial query string values (same as assigning toAppTest.query_paramsbefore the firstrun()).page_overrides (
dict[str,Any] |None) – Optional JSON-serializable map merged into handler dependency injection (viaFLUXLIT_TEST_PAGE_OVERRIDES) forHeader/ test doubles.
- Return type:
- Returns:
The result of
AppTest.from_file(...).run()(Streamlit type).
- fluxlit.testing.apptest_assert_no_errors(at)[source]¶
Raise
AssertionErrorifAppTestcapturedst.exceptionorst.error.Use after
FluxLitTestClient.streamlit()(or anyAppTestrun) to fail fast when the script surfaced an error to users.- Return type:
- fluxlit.testing.apptest_select_page(at, client, *, target, page, internal_api_base=None, extra_sys_path=None, page_key='page', page_overrides=None)[source]¶
Set
pagequery key andrun()with the sameFLUXLIT_*patch asstreamlit.AppTest.rundoes not automatically keepFLUXLIT_*variables from the firstFluxLitTestClient.streamlit()call; this helper re-applies the same patchFluxLitTestClient.streamlit()uses so the entrypoint can resolvetargetagain after you changeat.query_params.- Return type:
- fluxlit.testing.assert_no_streamlit_exception(at)[source]¶
Alias for
apptest_assert_no_errors()(StreamlitAppTestnaming).- Return type:
- fluxlit.testing.streamlit_main_path()[source]¶
Return FluxLit’s supported Streamlit entry script for
AppTest.from_file.Use this instead of constructing a path from
fluxlit.__file__; the helper is part of FluxLit’s testing API and can keep working if the internal package layout changes.- Return type:
Optional no-dependency tracing hooks for FluxLit internals.
The core package does not depend on OpenTelemetry. Integrations can register a small context-manager factory and translate FluxLit spans into any tracing backend.
- fluxlit.tracing.reset_trace_hook(token)[source]¶
Reset the tracing hook installed by
set_trace_hook().- Return type:
- fluxlit.tracing.set_trace_hook(hook)[source]¶
Install a tracing hook for the current context and return a reset token.
- fluxlit.tracing.trace_span(name, attributes)[source]¶
Return a context manager for an optional span.
If no hook is installed, this is a no-op. Hook exceptions intentionally bubble up so integrations fail loudly during development instead of hiding broken instrumentation.
- Return type:
Small utilities for declaring fastapi.APIRouter instances.
- fluxlit.api.router(*, prefix='', tags=None)[source]¶
Create an
APIRouterwith optional prefix and OpenAPI tags.Exists to normalize
tagstyping (list[str]vs enum tags) for strict callers.
Authentication helpers (JWT, OIDC BFF, Streamlit-side helpers, trusted proxy headers).
- class fluxlit.auth.GenericOIDCClient(config)[source]¶
Bases:
objectOIDC provider using
/.well-known/openid-configuration(Authorization Code + PKCE).
- class fluxlit.auth.GenericOIDCClientConfig(issuer, client_id, client_secret, http_timeout=30.0)[source]¶
Bases:
object
- class fluxlit.auth.InMemoryOIDCBFFTokenStore(_pkce=<factory>, _exchange=<factory>, _lock=<factory>, state_ttl_seconds=600.0, otc_ttl_seconds=120.0)[source]¶
Bases:
objectProcess-local PKCE and exchange storage (default for
OIDCBFFConfig).
- class fluxlit.auth.JWTAuthConfig(issuer, audience, algorithms=<factory>, jwks_url=None, hs256_secret=None, leeway_seconds=0)[source]¶
Bases:
objectConfiguration for
JWTBearer.
- class fluxlit.auth.JWTBearer(config)[source]¶
Bases:
objectFastAPI dependency: validate
Authorization: Bearerand returnStandardClaims.- classmethod from_fluxlit_settings(settings)[source]¶
Build a bearer dependency from settings /
FLUXLIT_JWT_*.Uses
FluxlitSettings. Provide eitherjwt_hs256_secret(development) orjwt_jwks_url(RS256 / JWKS), plusjwt_issuerandjwt_audience. Error messages name the env vars.- Return type:
- class fluxlit.auth.OIDCBFFConfig(oidc, first_party_secret, token_issuer='fluxlit-bff', token_audience='fluxlit-app', access_token_ttl_seconds=3600, public_base_url='', login_path='/auth/login', callback_path='/auth/callback', exchange_path='/auth/exchange', scope='openid profile email', streamlit_redirect_path='/', state_ttl_seconds=600, otc_ttl_seconds=120, id_token_audience='', id_token_leeway_seconds=0, allow_unverified_id_token_for_custom_oidc=False, bff_token_store=None)[source]¶
Bases:
objectSettings for
register_oidc_bff_routes().- allow_unverified_id_token_for_custom_oidc: bool = False¶
If True, allow non-
GenericOIDCClientproviders to use parse-onlysub.Default
False: customOIDCProvidercallbacks reject minting tokens fromid_tokenwithout JWKS verification. SetTrueonly when the provider verifies tokens before returning them, or for tests.
- bff_token_store: OIDCBFFTokenStore | None = None¶
Optional shared storage for PKCE
stateand one-timeauth_codevalues.When
None,register_oidc_bff_routes()usesInMemoryOIDCBFFTokenStorewithstate_ttl_secondsandotc_ttl_seconds(single replica).
- id_token_audience: str = ''¶
Expected
audforid_tokenvalidation.If empty,
client_idfromGenericOIDCClientis used.
- oidc: OIDCProvider¶
- class fluxlit.auth.OIDCBFFTokenStore(*args, **kwargs)[source]¶
Bases:
ProtocolStorage for OIDC BFF PKCE
stateand one-timeauth_codeexchange payloads.Defaults to
InMemoryOIDCBFFTokenStore(process memory). Multi-replica API deployments should inject a shared implementation (for example Redis with TTL).
- class fluxlit.auth.OIDCProvider(*args, **kwargs)[source]¶
Bases:
ProtocolMinimal OIDC surface for discovery and token exchange.
- class fluxlit.auth.RequireRoles(bearer, *roles, roles_claim='roles')[source]¶
Bases:
objectDependency factory: require at least one role from a claim (string or list).
- class fluxlit.auth.RequireScopes(bearer, *scopes, scope_claim='scope')[source]¶
Bases:
objectDependency factory: require OAuth2-style scopes (space-delimited or list claim).
- class fluxlit.auth.StandardClaims(**data)[source]¶
Bases:
BaseModelCommon JWT claims plus extra keys from the token payload.
- model_config: ClassVar[ConfigDict] = {'extra': 'allow'}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class fluxlit.auth.TrustedProxyUser(config=None)[source]¶
Bases:
objectFastAPI dependency: trusted gateway user header with optional safety checks.
Use only when a network path guarantees that clients cannot spoof the header (for example, the app listens only on loopback and nginx strips inbound identity headers from untrusted clients).
- class fluxlit.auth.TrustedProxyUserConfig(header_name='X-Remote-User', require_https=False, trusted_client_hosts=None, require_non_empty_user=True)[source]¶
Bases:
objectPolicy for
TrustedProxyUser.
- fluxlit.auth.bearer_headers_from_session(st_module, *, session_key='fluxlit_access_token')[source]¶
Build
Authorizationheaders fromst.session_state(no logging of secrets).
- fluxlit.auth.exchange_auth_code_from_query(st_module, client, *, exchange_path='/auth/exchange', query_key='auth_code', session_key='fluxlit_access_token')[source]¶
If
query_keyis present, exchange it for an access token and store in session.Returns the access token when exchanged; otherwise
None. On HTTP errors from the exchange endpoint, raiseshttpx.HTTPStatusError.
- fluxlit.auth.issue_hs256_access_token(*, subject, issuer, audience, secret, ttl_seconds, extra_claims=None)[source]¶
Mint a short-lived HS256 JWT (BFF / dev only — keep
secretserver-side).- Return type:
- fluxlit.auth.prepare_streamlit_api_client(st_module, *, exchange_path='/auth/exchange', session_key='fluxlit_access_token', **client_options)[source]¶
One-step Streamlit helper: exchange
auth_code(if present), return anApiClient.If a bearer token exists in
session_keyafter the exchange (or was already there), returnsApiClient.for_fluxlit()so protected routes work. Otherwise returns an unauthenticated client.- Return type:
- fluxlit.auth.proxy_user_header(header_name='X-Remote-User')[source]¶
Build a dependency that reads a trusted user id from an HTTP header.
Intended for deployments where an upstream proxy (SSO, API gateway) authenticates the user and forwards identity via a header. This does not validate signatures or sessions; it only exposes the header value to route handlers.
For stricter control (HTTPS, client IP allowlists), use
TrustedProxyUser.
- fluxlit.auth.register_oidc_bff_routes(app, config, *, router_prefix='')[source]¶
Attach login, OAuth callback, and Streamlit-friendly token exchange routes.
- Return type:
JWT bearer validation for FastAPI (requires pip install 'fluxlit[auth]').
Uses PyJWT with optional jwt.PyJWKClient for JWKS (RS256/ES256) or HS256 for
development.
- class fluxlit.auth.jwt.JWTAuthConfig(issuer, audience, algorithms=<factory>, jwks_url=None, hs256_secret=None, leeway_seconds=0)[source]¶
Bases:
objectConfiguration for
JWTBearer.
- class fluxlit.auth.jwt.JWTBearer(config)[source]¶
Bases:
objectFastAPI dependency: validate
Authorization: Bearerand returnStandardClaims.- classmethod from_fluxlit_settings(settings)[source]¶
Build a bearer dependency from settings /
FLUXLIT_JWT_*.Uses
FluxlitSettings. Provide eitherjwt_hs256_secret(development) orjwt_jwks_url(RS256 / JWKS), plusjwt_issuerandjwt_audience. Error messages name the env vars.- Return type:
- class fluxlit.auth.jwt.RequireRoles(bearer, *roles, roles_claim='roles')[source]¶
Bases:
objectDependency factory: require at least one role from a claim (string or list).
- class fluxlit.auth.jwt.RequireScopes(bearer, *scopes, scope_claim='scope')[source]¶
Bases:
objectDependency factory: require OAuth2-style scopes (space-delimited or list claim).
- class fluxlit.auth.jwt.StandardClaims(**data)[source]¶
Bases:
BaseModelCommon JWT claims plus extra keys from the token payload.
- model_config: ClassVar[ConfigDict] = {'extra': 'allow'}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- fluxlit.auth.jwt.issue_hs256_access_token(*, subject, issuer, audience, secret, ttl_seconds, extra_claims=None)[source]¶
Mint a short-lived HS256 JWT (BFF / dev only — keep
secretserver-side).- Return type:
Generic OIDC client and BFF-style auth routes.
Install fluxlit[auth] for JWT signing used by the BFF exchange.
- class fluxlit.auth.oidc.GenericOIDCClient(config)[source]¶
Bases:
objectOIDC provider using
/.well-known/openid-configuration(Authorization Code + PKCE).
- class fluxlit.auth.oidc.GenericOIDCClientConfig(issuer, client_id, client_secret, http_timeout=30.0)[source]¶
Bases:
object
- class fluxlit.auth.oidc.InMemoryOIDCBFFTokenStore(_pkce=<factory>, _exchange=<factory>, _lock=<factory>, state_ttl_seconds=600.0, otc_ttl_seconds=120.0)[source]¶
Bases:
objectProcess-local PKCE and exchange storage (default for
OIDCBFFConfig).
- class fluxlit.auth.oidc.OIDCBFFConfig(oidc, first_party_secret, token_issuer='fluxlit-bff', token_audience='fluxlit-app', access_token_ttl_seconds=3600, public_base_url='', login_path='/auth/login', callback_path='/auth/callback', exchange_path='/auth/exchange', scope='openid profile email', streamlit_redirect_path='/', state_ttl_seconds=600, otc_ttl_seconds=120, id_token_audience='', id_token_leeway_seconds=0, allow_unverified_id_token_for_custom_oidc=False, bff_token_store=None)[source]¶
Bases:
objectSettings for
register_oidc_bff_routes().- allow_unverified_id_token_for_custom_oidc: bool = False¶
If True, allow non-
GenericOIDCClientproviders to use parse-onlysub.Default
False: customOIDCProvidercallbacks reject minting tokens fromid_tokenwithout JWKS verification. SetTrueonly when the provider verifies tokens before returning them, or for tests.
- bff_token_store: OIDCBFFTokenStore | None = None¶
Optional shared storage for PKCE
stateand one-timeauth_codevalues.When
None,register_oidc_bff_routes()usesInMemoryOIDCBFFTokenStorewithstate_ttl_secondsandotc_ttl_seconds(single replica).
- id_token_audience: str = ''¶
Expected
audforid_tokenvalidation.If empty,
client_idfromGenericOIDCClientis used.
- oidc: OIDCProvider¶
- class fluxlit.auth.oidc.OIDCBFFTokenStore(*args, **kwargs)[source]¶
Bases:
ProtocolStorage for OIDC BFF PKCE
stateand one-timeauth_codeexchange payloads.Defaults to
InMemoryOIDCBFFTokenStore(process memory). Multi-replica API deployments should inject a shared implementation (for example Redis with TTL).
- class fluxlit.auth.oidc.OIDCProvider(*args, **kwargs)[source]¶
Bases:
ProtocolMinimal OIDC surface for discovery and token exchange.
- fluxlit.auth.oidc.register_oidc_bff_routes(app, config, *, router_prefix='')[source]¶
Attach login, OAuth callback, and Streamlit-friendly token exchange routes.
- Return type:
Streamlit helpers for FluxLit BFF auth (query-param auth code exchange).
- fluxlit.auth.streamlit.bearer_headers_from_session(st_module, *, session_key='fluxlit_access_token')[source]¶
Build
Authorizationheaders fromst.session_state(no logging of secrets).
- fluxlit.auth.streamlit.exchange_auth_code_from_query(st_module, client, *, exchange_path='/auth/exchange', query_key='auth_code', session_key='fluxlit_access_token')[source]¶
If
query_keyis present, exchange it for an access token and store in session.Returns the access token when exchanged; otherwise
None. On HTTP errors from the exchange endpoint, raiseshttpx.HTTPStatusError.
- fluxlit.auth.streamlit.prepare_streamlit_api_client(st_module, *, exchange_path='/auth/exchange', session_key='fluxlit_access_token', **client_options)[source]¶
One-step Streamlit helper: exchange
auth_code(if present), return anApiClient.If a bearer token exists in
session_keyafter the exchange (or was already there), returnsApiClient.for_fluxlit()so protected routes work. Otherwise returns an unauthenticated client.- Return type:
URL-bound server session continuity (Phase 2 follow-on — no HTTP cookies).
Use an opaque query parameter (default fluxlit_sid) plus a SessionStore
implementation to survive full browser reloads without relying on the browser
cookie jar. The gateway already forwards path + query to Streamlit.
Production: replace InMemorySessionStore with a shared store (Redis, etc.)
that implements the same protocol. In-memory is single-process only (typical
fluxlit dev / one replica).
See the URL session continuity user guide for security (HTTPS, link leakage, TTL) and multipage patterns.
- class fluxlit.url_session.InMemorySessionStore(*, max_entries=5000, default_ttl_seconds=86400.0)[source]¶
Bases:
objectProcess-local
SessionStore(dev / single replica).Not safe across multiple Uvicorn workers or horizontal replicas without a shared backend.
- set(session_id, data, *, ttl_seconds=None)[source]¶
Persist data for session_id; optional time-to-live in seconds.
TTL semantics:
ttl_secondsisNone→ usedefault_ttl_seconds(which may itself beNonefor no expiry). A positive value sets a monotonic deadline.ttl_secondsof0does not mean “expire immediately”; it is treated like “no TTL window” for this write (same as a negative value would be if passed, though callers should useNonefor no expiry).- Return type:
- class fluxlit.url_session.SessionStore(*args, **kwargs)[source]¶
Bases:
ProtocolServer-side persistence for URL-bound session blobs (JSON-serializable dicts).
- fluxlit.url_session.ensure_url_session(st, store, *, param=None, initial=None, ttl_seconds=None)[source]¶
Ensure
st.query_params[param]exists; mint id, seed store, set query param.Returns the session id (existing or new). If the query param cannot be set (read-only
query_params), still returns a new id and persists initial so callers can surface a warning or use client-side navigation.- Return type:
- fluxlit.url_session.hydrate_url_session(st, store, *, param=None, merge=True, blob=None)[source]¶
If
st.query_params[param]is set, load the store payload intost.session_state.merge (default):
session_state.setdefault(k, v)for each key in the blob so in-flight widget state wins over stale store keys on first paint.If the param is missing, returns
Noneand does nothing.If the param is present but the store has no entry, returns the session id without mutating
session_state(caller may seed withSessionStore.set()).
Returns the session id string when the query param is present, else
None.
- fluxlit.url_session.hydrate_url_session_typed(st, store, model, *, param=None, merge=True, strict=False)[source]¶
Like
hydrate_url_session(), then validate the store payload as model.Validates the store blob before merging into
st.session_stateso invalid payloads do not partially hydrate the UI session.Returns
(session_id_or_none, validated_model_or_none). On validation failure, when strict is false, returns(sid, None); when strict is true, raisespydantic.ValidationError.
- fluxlit.url_session.new_session_id()[source]¶
Return a new URL-safe opaque session identifier (≥128 bits).
- Return type:
- fluxlit.url_session.persist_url_session(st, store, *, param=None, ttl_seconds=None)[source]¶
Write current
st.session_state(shallow dict copy) to the store forparamid.Returns the session id if the param is present, else
None.Values are copied best-effort; remote stores should JSON-encode—non-JSON-safe values may need app-side filtering before
SessionStore.set().If snapshotting
session_statefails, the store is not updated but the session id is still returned; a warning is logged (with traceback whenFLUXLIT_DEBUG=1).
Deep links to Streamlit pages: normalized query params and optional ?page= routing.
Resolve
(path, title)from apage-style query key and registered pages.Compares the
page_keyvalue (default"page") to each page title, path, and Streamlit-style slug ("/"→"home"; otherwise the path without slashes). The first match in pages wins (order matchespages).Returns
Nonewhen the key is missing, empty, or unmatched.
- fluxlit.deep_links.query_params(st)[source]¶
Return the current URL query as plain
strvalues (first value if a list).Streamlit (and
AppTest) may exposest.query_paramsvalues as strings or lists when multiple values share a key. This helper normalizes to a singlestrper key so page logic and email-link prefill stay simple.Missing or unreadable
query_paramsyields an empty dict.
Security middleware and helpers.
- class fluxlit.security.SecurityHeadersMiddleware(app, dispatch=None)[source]¶
Bases:
BaseHTTPMiddlewareAdd baseline security headers (opt-in via
FluxlitSettings).
Typing helpers for Streamlit page callables.
- class fluxlit.streamlit.page.PageFn(*args, **kwargs)[source]¶
Bases:
ProtocolProtocol for functions registered with
fluxlit.app.FluxLit.page().Streamlit passes the
streamlitmodule asstand anApiClientbound to the internal API base. Handlers may returnPageMetafor post-run metadata (breadcrumbs, etc.).
The Typer CLI module (fluxlit.cli) is primarily used via the fluxlit console script; its objects are listed below for completeness.
Typer CLI: fluxlit dev, run, workbench, shutdown, doctor, config,
build, new.
The fluxlit setuptools entrypoint calls main(). Commands resolve defaults from
fluxlit.config.load_project_config() and FluxlitSettings.
- fluxlit.cli.build(output=None, target=<typer.models.ArgumentInfo object>, force=<typer.models.OptionInfo object>)[source]¶
Emit a minimal
Dockerfileand.dockerignorefor container deployment.Refuses to overwrite existing files unless
--force. Adjust generated files for your layout (dependencies, non-root user, etc.).- Return type:
- fluxlit.cli.config(target=<typer.models.ArgumentInfo object>, json_output=<typer.models.OptionInfo object>, strict=<typer.models.OptionInfo object>)[source]¶
Print effective FluxLit configuration after precedence rules (env, project file, app).
Shows resolved bind defaults, redacted settings, derived internal API base, and warnings with documentation links. Does not start the server.
- Return type:
- fluxlit.cli.dev(target=<typer.models.ArgumentInfo object>, host=<typer.models.OptionInfo object>, port=<typer.models.OptionInfo object>, log_level=<typer.models.OptionInfo object>, proxy_headers=<typer.models.OptionInfo object>, forwarded_allow_ips=<typer.models.OptionInfo object>, reload=<typer.models.OptionInfo object>, reload_scope=<typer.models.OptionInfo object>, pidfile=None, no_pidfile=<typer.models.OptionInfo object>, workbench=<typer.models.OptionInfo object>, debug=<typer.models.OptionInfo object>)[source]¶
Run the unified stack for local development (Streamlit subprocess + Uvicorn gateway).
Resolves
target, bind address, port, and log level from CLI, project file, andFluxlitSettings. Seefluxlit.runtime.run_unified().- Return type:
- fluxlit.cli.doctor(target=<typer.models.ArgumentInfo object>, warnings_only=<typer.models.OptionInfo object>, json_output=<typer.models.OptionInfo object>, verbose=<typer.models.OptionInfo object>, check_pages=<typer.models.OptionInfo object>, strict=<typer.models.OptionInfo object>)[source]¶
Print PASS/WARN/FAIL diagnostics (imports, deps, bind, env).
Exits with code
1if any check fails, unless--warnings-onlyis set.- Return type:
- fluxlit.cli.main()[source]¶
Invoke the root Typer application (console script entrypoint).
- Return type:
- fluxlit.cli.new(name=<typer.models.ArgumentInfo object>, profile=<typer.models.OptionInfo object>)[source]¶
Create
<name>/app.pywith a sample API route and Streamlit home page.- Return type:
- fluxlit.cli.pages_manifest(target=<typer.models.OptionInfo object>)[source]¶
Print a JSON page manifest for the resolved FluxLit app (
manifest_version1, stable).- Return type:
- fluxlit.cli.pages_validate(target=<typer.models.OptionInfo object>, strict=<typer.models.OptionInfo object>)[source]¶
Validate page handlers and manifest JSON-serializability (exit 1 on errors).
- Return type:
- fluxlit.cli.run_cmd(target=<typer.models.ArgumentInfo object>, host=<typer.models.OptionInfo object>, port=<typer.models.OptionInfo object>, log_level=<typer.models.OptionInfo object>, proxy_headers=<typer.models.OptionInfo object>, forwarded_allow_ips=<typer.models.OptionInfo object>, pidfile=None, no_pidfile=<typer.models.OptionInfo object>, workbench=<typer.models.OptionInfo object>, debug=<typer.models.OptionInfo object>)[source]¶
Run the unified stack for production-style use (no Uvicorn reload).
Same resolution rules as
dev(); always callsfluxlit.runtime.run_unified()withreload=False.- Return type:
- fluxlit.cli.shutdown(pidfile=None, force=<typer.models.OptionInfo object>, wait_s=<typer.models.OptionInfo object>)[source]¶
Stop
fluxlit devorfluxlit runusing the PID file they write.Run this from the same working directory (or pass
--pidfile/ setFLUXLIT_PIDFILE) as the server process. Normal exit removes the PID file; this command also deletes it when the process is already gone.- Return type:
- fluxlit.cli.workbench_cmd(target=<typer.models.ArgumentInfo object>, host=<typer.models.OptionInfo object>, port=<typer.models.OptionInfo object>, log_level=<typer.models.OptionInfo object>, forwarded_allow_ips=<typer.models.OptionInfo object>, pidfile=None, no_pidfile=<typer.models.OptionInfo object>, debug=<typer.models.OptionInfo object>)[source]¶
Run the unified stack for Posit Workbench / Posit Connect-style path proxies.
Equivalent to
fluxlit runwith--workbench: Uvicornproxy_headersis enabled,forwarded_allow_ipsdefaults followFluxlitSettings, and a startup banner prints suggested loopback URLs (setFLUXLIT_ROOT_PATHfor subpaths).- Return type:
The Streamlit entry script fluxlit.streamlit.main is executed by streamlit run with FLUXLIT_APP set. It is not import-safe for autodoc (module-level initialization). See the source file streamlit/main.py in the repository.