🦉 owl · check
Your Python service must not start with a broken environment. owlcheck enforces that.
One call at the top of your application's entrypoint validates that every environment variable your code declares it needs is present and well-typed. The process either starts with a complete configuration or it does not start at all.
This eliminates a specific class of production failure: the service that boots cleanly, accepts traffic for ten minutes, then crashes the first time a code path reaches for os.environ.get("STRIPE_SECRET"). With owlcheck, that variable is checked before the first request — or the process exits before any request can arrive.
Status
Early development. API is not yet stable. Requires pydantic>=2, pydantic-settings>=2, Python 3.10+.
Installation
pip install owlcheck
The canonical pattern
There is exactly one way to use owlcheck. This is by design.
# main.py
from owlcheck import Settings
from pydantic import Field
class AppSettings(Settings):
database_url: str = Field(..., alias="DATABASE_URL", description="Postgres DSN")
stripe_secret: str = Field(..., alias="STRIPE_SECRET", description="Stripe API secret")
debug: bool = Field(False, alias="DEBUG")
settings = AppSettings.load_or_exit()
That's the entire integration. After this line returns, settings is a validated, immutable record of your application's configuration. Import it anywhere:
from main import settings
connect(settings.database_url)
If any required environment variable is missing or invalid, the process exits with code 1 and a log message that names the violated contract — before any handler, worker, or background task can run.
What this enforces
- No partial-config startup. Validation runs before your application accepts any work. If something required is missing, the process fails immediately with a readable report; it does not run for ten minutes and crash at request time.
- One source of truth. Your
Settingssubclass is the schema. Scatteredos.environ.get(...)calls in handlers, workers, and helpers are explicitly the failure modeowlcheckexists to prevent. - Aliased error messages. Validation errors name the environment variable (the field's alias), not the Python attribute. Operators read
DATABASE_URL: missing (Postgres DSN), notdatabase_url: field required. - Undeclared
.envkeys are surfaced. Any variable in your.envfile that isn't a declared field is reported at startup - that undeclared surface is the failure mode owlcheck exists to remove - and ones that look like a typo of a field name get a "did you mean" hint. (Ambient environment variables aren't pulled in; only keys actually in the file.) Every extra is then dropped so nothing undeclared reaches your code. - Per-field status log. Each declared field is reported on startup as
provided(from env or override) ordefault. You always know what configuration the process actually loaded. - Immutable after load. Once
load_or_exit()returns, the contract is frozen. Attempts to mutatesettings.x = ...raiseValidationError. The configuration of a running process does not change under the code that depends on it.
Why "one call"
The alternative — scattered os.getenv("X") checks across handlers, workers, and helpers — is a tax that compounds:
- A contributor adds a feature that reads
os.getenv("NEW_FLAG"). Code review does not catch it; nothing connectsNEW_FLAGto the declared schema. - The feature ships. In production,
NEW_FLAGis unset. The feature degrades silently in some flows, loudly in others. Nobody notices until a customer complains. - You spend an afternoon
greping for everyos.getenvandos.environ.getin the repo to figure out what the actual configuration surface of the service is.
owlcheck makes one canonical pattern strictly easier than every alternative. Declare every environment variable your service needs as a Field on your Settings subclass. Call load_or_exit() once in main.py. Use settings.x everywhere else. The schema is the contract; the call enforces it.
Public API
| Symbol | Purpose |
|---|---|
Settings |
Base class. Subclass it; declare fields with Field(alias=...). |
Settings.load_or_exit(**kw) |
The canonical entrypoint. Loads, validates, prints diagnostics; calls sys.exit(1) if anything is wrong. |
Settings.load(**kw) |
Same as above, but raises ValidationError instead of exiting. For callers that must handle the error themselves (rare). |
load(cls, **kw) / load_or_exit(cls, **kw) |
Functional forms for when you cannot subclass Settings (e.g., a third-party BaseSettings type passed in). |
clear_cache() |
Test helper. Drops cached load() results. Not for application code. |
Design choices
- Honest typing only. If a field can be
Noneat runtime, declare itT | None.owlcheckdoes not provide "soft optional" markers that lie to the type checker. - Library, not framework.
owlcheckdoes not configure logging for you. Configure your application's logging once;owlcheckwrites tologging.getLogger("owlcheck")like any well-behaved library. - Immutable after load. Once
load()returns, the contract is frozen. See above.
License
Metadata
Release files for owlcheck 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| owlcheck-0.2.1.tar.gz | 9.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| owlcheck-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 19.5 kB
Release files / owlcheck-0.2.1.tar.gz
| Download URL | owlcheck-0.2.1.tar.gz |
|---|---|
| Size | 9.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9c77a00f753c20e933fc22e06a0a2c7b6d2e31f4dd31cc08d1a336a3c91cfc0f
|
|
BLAKE2b-256 checksum How to use checksums |
4e4f6fd31d98f2623b8e7433353614a230af178dd3ed9a76a20635b5265226d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 May 24, 2026.
Transparency logRelease files / owlcheck-0.2.1-py3-none-any.whl
| Download URL | owlcheck-0.2.1-py3-none-any.whl |
|---|---|
| Size | 9.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ff73fadf9c4e781967799d94c0122c8bc2bb8c5ffd585b9f98d6067fec9c4a53
|
|
BLAKE2b-256 checksum How to use checksums |
81510202d88c2e06d4fb3765e39e428815b7149ddb93216a006d3b8106f7867d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 May 24, 2026.
Transparency log