fancy-features
Headless feature management and metered-resource gating for Python. Feature flags, feature groups, per-plan quotas and billing-period usage — with no web framework, no ORM and no runtime dependencies at all.
The Python twin of particle-academy/laravel-fms
(PHP) and @particle-academy/fancy-features
(Node/TypeScript), and the owner of the shared feature contract
fancy-catalog consumes.
pip install fancy-features
In one minute
from fancy_features import create_features
features = create_features(
features={
"use-mcp": {"enabled": True},
"ai-tokens": {"type": "resource", "limit": 10_000},
},
groups=[
{"key": "pro", "features": ["sso"], "overrides": {"ai-tokens": {"limit": 250_000}}},
],
)
features.can_access("use-mcp", user) # True
features.remaining("ai-tokens", user) # 10000
features.try_consume("ai-tokens", user, 40) # True -- atomic check-and-increment
features.remaining("ai-tokens", user) # 9960
features.explain("ai-tokens", user) # AccessResult(source="config", used=40, ...)
Every method has an a-prefixed twin for async hosts — acan_access,
aremaining, atry_consume — and both drive one copy of the resolution
rules, so they cannot disagree.
How a verdict is reached
pre-strategies → gate → registry → groups (OR) → config → sources → deny
- pre-strategies and gate are authoritative: a non-
Noneanswer from either is final in both directions. That is what lets a billing service deny something a stray permission would allow. - everything after them is additive: a feature defined with
enabled=Falsedoes not block a group or a plan from turning it on.
For a resource feature:
pre-remaining strategies → MAX(group limit, source limit, feature limit) − usage
clamped at zero, with None meaning unlimited. MAX, because a plan should
be able to lift a base limit and never to lower one.
Adapters, all optional
| Contract | Default | What a host plugs in |
|---|---|---|
UsageStore |
InMemoryUsageStore |
its feature_usages table |
GroupStore |
InMemoryGroupStore |
its group-assignment table |
FeatureSource |
none | fancy-catalog, or its own entitlement service |
| gate | none | its permission system |
Every one may be synchronous or asynchronous. A dict-backed store returns an
int; a database-backed one returns a coroutine; both work.
Billing periods
from datetime import datetime, UTC
from fancy_features import BillingPeriod
january = BillingPeriod(
start=datetime(2026, 1, 1, tzinfo=UTC), end=datetime(2026, 2, 1, tzinfo=UTC)
)
features.try_consume("ai-tokens", user, 500, period=january)
features.remaining("ai-tokens", user, period=january)
features.reset_period(user, january) # the renewal reset
The period reaches the store on every quota path — reads and writes alike.
Composing with a Stripe catalog
from fancy_catalog import create_catalog
from fancy_catalog.features import create_catalog_feature_source
from fancy_features import create_features
catalog = create_catalog(stripe=stripe_client)
features = create_features(
sources=[create_catalog_feature_source(catalog, resolve_subscription=lookup)],
)
features.can_access("use-mcp", user) # resolved through the user's plan
features.remaining("ai-tokens", user) # the plan's included quantity, minus usage
The two packages share one definition of the contract, in
fancy_features.contract. The catalog imports it; there is no mirrored copy.
Guarding a route
from fancy_features import FeatureAccessDeniedError, require_feature
try:
require_feature(features, ["use-mcp", "use-agents"], user) # OR
except FeatureAccessDeniedError as denied:
return json_response({"features": denied.features}, status=denied.status)
No framework is imported and none is assumed.
One thing that will bite a porter
Every callback takes (subject, context) — check, enabled, limit,
usage, remaining. The Node package still publishes usage/remaining as
(key, subject, context). A three-parameter callback here raises, naming
the feature and the field, rather than binding subject to the key string and
quietly metering the wrong thing. Fewer parameters is fine: lambda: 30 works.
Requirements
Python 3.11+. No runtime dependencies.
License
MIT © Particle Academy
Metadata
Release files for fancy-features 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 | |
|---|---|---|---|
| fancy_features-0.2.0.tar.gz | 49.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fancy_features-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 85.1 kB
Release files / fancy_features-0.2.0.tar.gz
| Download URL | fancy_features-0.2.0.tar.gz |
|---|---|
| Size | 49.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bf58194c659e7e5eba1ca425293fb84f2f8be01f3f5ceedec202050b36c208f4
|
|
BLAKE2b-256 checksum How to use checksums |
768fee1e8b7b5c304a248c1497ce568857dde0f876f79ae5e307a088ad15176d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 19, 2026.
Transparency logRelease files / fancy_features-0.2.0-py3-none-any.whl
| Download URL | fancy_features-0.2.0-py3-none-any.whl |
|---|---|
| Size | 35.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d4f6c9b57a2f8a86823bd966aadbfb7af9a0bddd3c4150bdb383210cf066f5cd
|
|
BLAKE2b-256 checksum How to use checksums |
1c2d758377c601a3ca494ed12c754b8de5d886b29390e3b44eba436eda00173c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 19, 2026.
Transparency log