Releases: FtrOnOff/ftrio-python
Release list
1.0.1
FtrIO Python v1.0.1
Released: 2026-07-08
A patch release completing case-insensitive key handling across every configuration source, so keys resolve the same on every platform.
Fixed
- Config keys are now matched case-insensitively.
AppSettingsConfiguration.get_valueresolves colon-path keys regardless of case (e.g.Toggles:newcheckoutfindsToggles:NewCheckout), mirroringMicrosoft.Extensions.Configuration'sOrdinalIgnoreCasecomparer. An exact match is still preferred as a fast path. - Environment-variable buffer mode now works on Windows.
EnvironmentVariableToggleParsermatched its prefix case-sensitively, but Windows uppercases env-var names at the OS boundary (FTRIO__Toggles__BufAbecomesFTRIO__TOGGLES__BUFA), so buffer mode staged nothing there. The prefix is now matched case-insensitively; the extracted key keeps the OS-provided case, which is harmless because toggle keys are compared case-insensitively throughout. Standalone mode was already correct and is unchanged.
Internal
- Added a hidden
conformance-resolveCLI command (help suppressed, not user-facing) that reads one resolution case as JSON on stdin and prints the outcome as JSON, letting the cross-languageftrio-conformancematrix exercise the port's real resolution logic.
Notes
No API or behavioural changes for correctly-cased keys; existing configurations continue to work unchanged. This is the environment/OS counterpart to the JSON-side config fix, making key handling consistently case-insensitive across every source on every platform.
Full changelog: v1.0.0...v1.0.1
1.0.0
FtrIO for Python 1.0.0
Initial release. A faithful Python port of the .NET
FtrIO feature-toggle library.
Decorate a function with @toggle and it is gated by its own name. Add a matching
key to appsettings.json, and the function runs only when the toggle is on. Richer
decisions (percentage rollouts, A/B buckets, blue/green slots, user and attribute
targeting, per-user overrides) layer in through a strategy chain. The core depends
on the standard library only.
Install
pip install ftrioOptional Azure App Configuration provider:
pip install "ftrio[azure]"Highlights
@toggle/@toggle_asyncdecorators: gate a function by its own name; off
returnsNone(sync) or an awaitable resolving toNone(async), soawaitis
always safe.- Strategy chain:
Boolean(always-on fallback),PercentageRollout("20%"),
UserTargeting("users:alice,bob"),AttributeRule
("attribute:plan equals premium", seven operators),ABTest("ab:50"), and
BlueGreen("blue"/"green"). First match wins. - Deterministic A/B: the same user, key, and salt always bucket identically, and
identically to the .NET implementation (SHA-256, first four bytes little-endian
signed, absolute value mod 100). - Per-user overrides:
TogglesOverrideswin unconditionally, before any strategy. - Parsers: appsettings.json, strategy chain, environment variables (standalone or
buffered), and a first-winsCompositeToggleParser. - Providers + buffer:
ToggleProviderBufferflushes staged values to
appsettings.jsonatomically; HTTP (stdlib) and Azure App Config (optional extra)
providers, both fail-safe. - Configuration: colon-path access, environment overlay
(appsettings.{Environment}.json), and reload-on-change, replicating
IConfigurationwith the standard library only. ftrio lintCLI: flags any@togglefunction whose key is missing from
appsettings.json(diagnosticFTRIO001); supports--exclude, default excludes,
and-v/--verbose. Exits non-zero to gate CI.python -m playground: a live demo honouring reload-on-change.
Notes for adopters
- Toggle keys follow the host language's method-naming convention: snake_case keys
derived from snake_case method names. The PascalCase in the .NET original was a C#
artifact, not part of the wire contract (which is the JSON shape). - Exceptions use the Python-canonical
*Errorsuffix (ToggleDoesNotExistError,
ToggleParsedOutOfRangeError,ToggleAttributeMissingError).
Quality
Full pytest suite (re-proving every behaviour the .NET NUnit suite covers),
ruff (including pep8-naming) clean, and mypy clean on the public surface.