Notifig
A highly declarative, strictly typed, reactive config
Notifig is a configuration library built on Pydantic, and strongly rooted on these principles:
Declaration is behavior - The shape of a config field derives its usage.
Validation, serialization, value choices, CLI flags, all follow from writing the field itself.
For example, this statement creates a colors field that only accepts certain values and can be
set both with comma-separated values (--color "blue,red"") or explicit lists:
from enum import Enum
from typing import Annotated
from pydantic import Field
from notifig import Choice, Delimited, CLIFlags
class Color(Enum):
RED = "#FF0000"
GREEN = "#00FF00"
BLUE = "#0000FF"
COLORS = {name.lower(): color for name, color in Color.__members__.items()}
# Color type with restricted values
ColorType = Annotated[Color, Choice(COLORS)]
# List that can parse/serialize delimited color names (comma by default)
ColorList = Annotated[list[ColorType], Delimited()]
# List of colors with CLI flags
colors: Annotated[
ColorList,
CLIFlags(["color", "c"]), # creates --color/-c CLI flags
] = Field(
default="green", # default value
# info string for --help and CLI errors
description="Available colors",
)
# Usage
# YAML: `colors: green,blue`
# CLI: `--colors "blue,red"`
Single source of truth - Settings should be declared once, in a single mutable single register.
A common example is mapping CLI flags to their config value, which usually involves maintaining a parallel dict that references fields by string name and needs to be manually kept in sync with the config itself:
class BadSettings:
foo: str
bar: str | None = None
baz: int # We added baz, but forgot to add its CLI flag below
# If any field gets renamed or deleted, someone has to remember to change it here.
CLI_FLAGS = {
"foo": "foo",
"f": "foo",
"bar": "bar"
}
# Requires merging the CLI data into config fields
for flag, value in cli_data.items():
if (field := CLI_FLAGS[flag]):
setattr(config, field, value)
With Notifig, the CLI flags live on their respective field declarations. Deleting or altering a field and all its flags only touches one statement, in a single place.
class Settings(Config):
foo: Annotated[str, CLIFlags("foo", "f")] = Field(description="Value of Foo")
bar: Annotated[str|None, CLIFlags("bar")] = Field(
description="Name of Bar, if any",
default=None,
)
baz: int = Field(description="Amount of Baz")
Distributed awareness - Each part of an application only interacts with its own config section.
An application's structure hierarchy should map to its config structure. Each component declares its own config section with the fields it needs, and does not need to be
Reactive state - Changes in the config should inform anyone interested.
Adding, changing or deleting an entry should able to trigger behavior instead of relying on periodic checks. An observer is a callable or coroutine registered to a path, and it's called whenever it is altered. A simple example where changing a UI's theme causes it to redraw:
from typing import Annotated
from pydantic import Field
from notifig import Config, ConfigSection, ConfigChange, Choice
class UIConfig(ConfigSection):
theme: Annotated[str, Choice(["dark", "light"])] = Field(default="light")
class Settings(Config):
ui: UIConfig = Field(default_factory=UIConfig)
config = Settings()
# sync observer that logs every change
@config.on_change()
def print_changes(section: ConfigSection, changes: tuple[ConfigChange]):
for change in changes:
print(f"Change of type {change.__class__.__name__} on {change.path}")
# Simple assignment works for sync observers
config.ui.theme = "dark"
config.ui.theme = "light"
# async observer that redraws UI theme
@config.on_change("ui.theme")
async def redraw_theme(section: ConfigSection, changes: tuple[ConfigChange]):
await interface.update_theme(section.ui.theme)
# Async observers require `await` to be called
await config.ui.set_and_wait(theme="dark")
Install
pip install notifig
Requires Python ≥ 3.13.
Features
- Custom annotations - Notifig introduces several custom Pydantic annotations to express behavior from types:
CLIFlags- adds a shortcut CLI flag for a fieldChoice- restricts the values a field can take according to a list of optionsCommaSeparated- allows parsing a list delimited by,Link- links one field to another through its full path
- Observers -
- Static and Dynamic sections
- Obvious usage -
bar = section.foo,section["foo"] = "baz",section.get("foo.bar"),for name, field in section - File formats: supports config files in JSON, YAML, TOML, INI and .env
Built on
- Pydantic - The typing foundation, model validators and serializers, type adapters.
- Pydantic Settings -
- anyconfig - File serialization library with wide format support.
Metadata
Release files for notifig 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| notifig-0.2.0.tar.gz | 81.2 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| notifig-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 138.1 kB
Release files / notifig-0.2.0.tar.gz
| Download URL | notifig-0.2.0.tar.gz |
|---|---|
| Size | 81.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
aab6212ca2072b80429751619ee0007065be50dbc1559d9f2e192a4f434a2133
|
|
BLAKE2b-256 checksum How to use checksums |
db52e04754b1facc24a6699a5ccd0a4e45e2a1a475e2c446c8881ffe8aebb3b5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logRelease files / notifig-0.2.0-py3-none-any.whl
| Download URL | notifig-0.2.0-py3-none-any.whl |
|---|---|
| Size | 56.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ee27c7cf6febf27deaa175d0ed775041a8c01dc1b071f76cba204b4478be7940
|
|
BLAKE2b-256 checksum How to use checksums |
0501a79a08c5db3a845fcb2a902115857a3666f0f7706cc4d6a7b66be286f94c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logSecurity for notifig 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for notifig-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.