Skip to main content

🦉 owl · check

CI Python Pydantic pydantic-settings License PyPI

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 Settings subclass is the schema. Scattered os.environ.get(...) calls in handlers, workers, and helpers are explicitly the failure mode owlcheck exists 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), not database_url: field required.
  • Undeclared .env keys are surfaced. Any variable in your .env file 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) or default. You always know what configuration the process actually loaded.
  • Immutable after load. Once load_or_exit() returns, the contract is frozen. Attempts to mutate settings.x = ... raise ValidationError. 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:

  1. A contributor adds a feature that reads os.getenv("NEW_FLAG"). Code review does not catch it; nothing connects NEW_FLAG to the declared schema.
  2. The feature ships. In production, NEW_FLAG is unset. The feature degrades silently in some flows, loudly in others. Nobody notices until a customer complains.
  3. You spend an afternoon greping for every os.getenv and os.environ.get in 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 None at runtime, declare it T | None. owlcheck does not provide "soft optional" markers that lie to the type checker.
  • Library, not framework. owlcheck does not configure logging for you. Configure your application's logging once; owlcheck writes to logging.getLogger("owlcheck") like any well-behaved library.
  • Immutable after load. Once load() returns, the contract is frozen. See above.

License

MIT

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)

Source distribution for owlcheck 0.2.1
File Size Uploaded
owlcheck-0.2.1.tar.gz 9.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for owlcheck 0.2.1
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page