Typed application settings with a .NET-like configuration builder for Python.
Project description
axa-fr-app-settings
A Python 3.10+ package designed for uv that provides a typed, chainable, .NET-like configuration builder.
The idea is to be able to write:
import os
from axa_fr_app_settings import ConfigurationBuilder, SettingsModel
class ApiSettings(SettingsModel):
debug: bool = False
http_timeout: int = 45
environment = os.getenv("PYTHON_ENVIRONMENT", "development")
settings = (
ConfigurationBuilder(ApiSettings)
.add_yaml_file("settings.yaml", optional=True)
.add_yaml_file(f"settings.{environment}.yaml", optional=True)
.add_json_file("settings.json", optional=True)
.add_json_file(f"settings.{environment}.json", optional=True)
.add_environment_variables(prefix="", nested_delimiter="__")
.build()
)
What the package provides
- Fluent API à la
.NET ConfigurationBuilder - YAML as the default source
- Override by order of source addition
- Environment variable support with
__for nested keys .envfile support- Typed validation with Pydantic v2
- Compatible with
dict[str, SubModel], lists, booleans, integers, etc.
Installation
With uv:
uv add axa-fr-app-settings
Locally for contributing:
uv sync --dev
Usage
1. Define typed models
from pydantic import Field
from axa_fr_app_settings import SettingsModel
class OIDCSettings(SettingsModel):
endpoint_url: str
issuer: str
client_id: str
client_secret: str | None = None
private_key: str | None = None
scopes: str
class DatabaseSettings(SettingsModel):
endpoint_url: str
class CacheRedisSettings(SettingsModel):
master: str = "mymaster"
sentinels: str = "redis-ha:26379"
expiry_time: int = 60
class CacheSettings(SettingsModel):
type: str = "redis"
redis: CacheRedisSettings = Field(default_factory=CacheRedisSettings)
class AppSettings(SettingsModel):
database: dict[str, DatabaseSettings] = Field(default_factory=dict)
llm_oidc: dict[str, OIDCSettings] = Field(default_factory=dict)
debug: bool = False
http_timeout: int = 45
http_verify: bool = False
cache: CacheSettings = Field(default_factory=CacheSettings)
2. Build the configuration
import os
from axa_fr_app_settings import ConfigurationBuilder
environment = os.getenv("PYTHON_ENVIRONMENT", "development")
settings = (
ConfigurationBuilder(AppSettings)
.add_yaml_file("settings.yaml", optional=True)
.add_yaml_file(f"settings.{environment}.yaml", optional=True)
.add_json_file("settings.json", optional=True)
.add_json_file(f"settings.{environment}.json", optional=True)
.add_env_file(".env", optional=True)
.add_environment_variables(prefix="", nested_delimiter="__")
.build()
)
3. Environment variable examples
export DEBUG=true
export HTTP_TIMEOUT=30
export CACHE__REDIS__EXPIRY_TIME=120
export DATABASE__main__ENDPOINT_URL="postgresql://localhost:5432/app"
4. YAML example
debug: false
http_timeout: 45
database:
main:
endpoint_url: "postgresql://localhost:5432/app"
cache:
type: redis
redis:
master: mymaster
sentinels: redis-ha:26379
expiry_time: 60
5. JSON example
{
"debug": false,
"http_timeout": 45,
"database": {
"main": {
"endpoint_url": "postgresql://localhost:5432/app"
}
},
"cache": {
"type": "redis",
"redis": {
"master": "mymaster",
"sentinels": "redis-ha:26379",
"expiry_time": 60
}
}
}
YAML and JSON sources can be mixed freely. The last source added always wins.
Priority order
As in .NET, the last source added wins.
Example:
settings = (
ConfigurationBuilder(AppSettings)
.add_yaml_file("settings.yaml", optional=True)
.add_yaml_file("settings.production.yaml", optional=True)
.add_environment_variables()
.build()
)
Here:
settings.yamlloads the base valuessettings.production.yamloverrides them- environment variables override everything
Available API
add_yaml_file(path, optional=False, encoding="utf-8")add_json_file(path, optional=False, encoding="utf-8")add_env_file(path=".env", optional=False, prefix="", nested_delimiter="__", case_sensitive=False)add_environment_variables(prefix="", nested_delimiter="__", case_sensitive=False)add_in_memory_collection(data)add_source(source)build()build_data()
Full example
A complete example is provided in examples/api_settings.py.
Publishing to PyPI with GitHub Actions
The repository includes two workflows:
| Workflow | File | Trigger |
|---|---|---|
| CI | .github/workflows/ci.yml |
push / PR on main |
| Publish | .github/workflows/publish.yml |
every merge (push) on main |
The publish workflow automatically:
- Runs lint + tests
- Builds the wheel and sdist with
uv build - Publishes to PyPI with
uv publish
Setup
Add a PYPI_API_TOKEN secret in your GitHub repository settings:
Settings → Secrets and variables → Actions → New repository secret
| Secret name | Value |
|---|---|
PYPI_API_TOKEN |
Your PyPI API token (starts with pypi-) |
That's it — every merge to main will publish a new version automatically.
Development
uv sync --dev
uv run ruff check .
uv run pytest
uv build
License
MIT
Project details
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 axa_fr_app_settings-0.1.0.tar.gz.
File metadata
- Download URL: axa_fr_app_settings-0.1.0.tar.gz
- Upload date:
- Size: 7.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","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 |
102e29bc88db19688faa88a579951e905ebcf8c43350c351aed4438d52196ef7
|
|
| MD5 |
77b3bdb812f039e28675ea20ec0947da
|
|
| BLAKE2b-256 |
31ff3610bf0d8ab9770391451b0552b8b13b613189c43bb7940103d32ea8b7d5
|
File details
Details for the file axa_fr_app_settings-0.1.0-py3-none-any.whl.
File metadata
- Download URL: axa_fr_app_settings-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","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 |
4674669e1063a0f9ece89d58342c901540799c92eaaa40675a611e4f40eb9dcd
|
|
| MD5 |
42803b2ca8063bbabc77d4279935993c
|
|
| BLAKE2b-256 |
f0675434a877b9ae89ce171b7e5429d57c2b1564af0b8a8fc8d892ec0783ee98
|