Skip to main content

envdoctor (Python)

PyPI

Native Python port of envdoctor — a local-first consistency checker for environment variables, distributed on PyPI so Python projects can use it without Node.

See Why not X? for how envdoctor compares to dotenv-linter, gitleaks, and hosted secrets tools.

Install

pip install arun-envdoctor

The PyPI distribution is named arun-envdoctor (PyPI blocks envdoctor as too similar to an existing project), but the installed command and the importable package are both still envdoctor.

Quick start

envdoctor scan --dir .        # audit; exit 1 on errors
envdoctor scan --strict       # treat warnings as errors too
envdoctor scan --json         # emit findings as a JSON array (no values)

What it detects

Reconciles the environment variables used in your Python source (os.getenv("X"), os.environ.get("X"), os.environ["X"], and the from os import environ forms) against those defined in your .env files, then reports:

Rule Severity Meaning
undefined-in-source error Referenced (source or infra files) but not defined in any .env file
duplicates error The same key is defined 2+ times within a single .env file
public-prefix error A secret-looking variable is exposed to client bundles via a public prefix (NEXT_PUBLIC_, VITE_, REACT_APP_, EXPO_PUBLIC_, GATSBY_, NUXT_PUBLIC_, VUE_APP_, PUBLIC_)
type-mismatch error A variable's value has incompatible inferred types across environments (e.g. PORT=3000 vs PORT=abc)
unused warning Defined in .env but never referenced in source
environment-diff warning Defined in some environment files but missing from others
weak-secret warning A secret-looking variable has a weak, empty, or placeholder value
typo warning A used-but-undefined name closely matches a defined one (likely a typo)

In addition to Python source, envdoctor scans Docker Compose (docker-compose.yml / compose.yaml), GitHub Actions workflows (.github/workflows/*.yml), and Kubernetes manifests (any YAML with both apiVersion: and kind:) for referenced variables. Detection is dependency-free (regex only, no YAML parser): shell-style interpolation ${VAR} / $VAR (including ${VAR:-default} forms) across all three, plus ${{ secrets.X }}, ${{ vars.X }}, and ${{ env.X }} references in Actions. These references feed the same missing/undefined and unused detectors, so a variable referenced only in infra files but never defined is flagged, and one defined and referenced only in infra is not reported unused.

Comments and docstrings are stripped before scanning, so documented examples don't cause false positives. Nothing is uploaded and variable values are never printed — they are used only for detection and never appear in any output (human or --json). envdoctor scan exits 1 when there are errors (or with --strict, warnings), making it CI-friendly. Pass --json to emit a JSON array of findings (each with rule, severity, name, message, file, line) for machine consumption.

Library use

from pathlib import Path
from envdoctor import scan

result = scan(Path("."))
for finding in result.errors:
    print(finding.name, finding.message)

Development

pip install -e ".[dev]" pytest
pytest

Subcommands

Alongside scan, every port shares these environment subcommands:

envdoctor diff <envA> <envB>       # compare two environments (add --json)
envdoctor sync <from> <to>         # copy missing keys (add --dry-run)
envdoctor init [--force]           # generate .env.example + ENVIRONMENT.md
envdoctor fix                      # (re)generate both docs

diff reports which variable names are only in one environment; sync appends the missing keys to the target .env file as empty KEY= placeholders — values are never copied.

init / fix

Both commands generate two files at the project root from the union of every variable name (defined in any .env* file ∪ referenced in source/infra), sorted ascending. Values are never written.

  • .env.example — a header comment followed by one NAME= line per variable.
  • ENVIRONMENT.md — a Markdown table of each variable with Defined/Used columns.

init writes each file only if it does not already exist (--force overwrites); fix always regenerates both. Every port produces byte-identical files.

Schema validation

Add an envdoctor.schema.json at your project root to validate .env values:

{
  "PORT":  { "type": "integer", "min": 1, "max": 65535 },
  "LEVEL": { "enum": ["debug", "info", "warn", "error"] },
  "TOKEN": { "type": "string", "optional": true }
}

Supported rule fields: type (string/integer/float/boolean/url/json), enum, regex, min, max, optional. Values that fail are reported as schema-validation errors (values are never printed).

Help make envdoctor smarter

envdoctor is young and its detectors are opinionated. If it missed something or cried wolf, tell me:

Other languages

envdoctor ships as a standalone native port for each ecosystem:

Metadata

Release files for arun-envdoctor 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for arun-envdoctor 1.0.0
File Size Uploaded
arun_envdoctor-1.0.0.tar.gz 15.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for arun-envdoctor 1.0.0
File Interpreter ABI Platform
arun_envdoctor-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 28.9 kB

Release files / arun_envdoctor-1.0.0.tar.gz

Download URL arun_envdoctor-1.0.0.tar.gz
Size 15.6 kB
Tags Source
SHA-256 checksum
How to use checksums
6ff73a5e5b0697e8346005f03b444855df67b7dc99d9f362054bf1fea264fac7
BLAKE2b-256 checksum
How to use checksums
405965d373967674b1b63972e73d2fec761000289be6a4362f79f59a5c8257a4
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 Sep 30, 2026.

Transparency log

Release files / arun_envdoctor-1.0.0-py3-none-any.whl

Download URL arun_envdoctor-1.0.0-py3-none-any.whl
Size 13.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e1ff6d6f6a7f7e4b1991f68baf60dbfc52c7cc0eaee406b2f001a32a99d97db4
BLAKE2b-256 checksum
How to use checksums
cc7c7ace7fefda96cfd0188812b3580707badbcb49707d903ae2b9a778b9b272
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 Sep 30, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.1.2

2 release files

0.1.1

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