Skip to main content

Quillstack Dotenv

Tests Latest Version Downloads Python Version CodeFactor Quality Gate Coverage Maintainability Reliability Security License

Reads a .env file. Values keep the type they plainly have, and nothing is expanded unless you ask for it.

Why this exists

It does not expand ${SOMETHING}, and that is on purpose

Most .env libraries resolve one value from another out of the box. This one does not, and the model it follows is JavaScript's.

dotenv for Node is the most installed .env library anywhere, and it does not interpolate. Nor does dotenv-java. In that world, building values from other values is a second package, because it is a second decision: it turns a list of pairs into a small language, with escaping and ordering and undefined names to settle.

The same choice is made here, and by quillstack/dotenv in PHP. A .env file which quietly became a template is a .env file you have to read twice.

A value keeps the type it has

if settings["APP_DEBUG"]:
    ...

Read as text, false is a non-empty string and therefore true. That is a bug which looks like working code, and it is the reason the values are typed rather than handed back as strings.

The values do not go into os.environ

os.environ holds strings and nothing else, so a port put there comes back '5432' and a false comes back true — the exact thing the typing avoids. What is read stays where its types survive, and export() is there for when something else needs the environment set.

Requirements

  • Python 3.11 or newer

Installation

pip install quillstack-dotenv

Usage

APP_DEBUG=true
APP_NAME=quillstack
DB_PORT=5432
from quillstack.dotenv import Dotenv

settings = Dotenv(".env").load()

settings["APP_DEBUG"]    # True, a boolean
settings["APP_NAME"]     # 'quillstack'
settings["DB_PORT"]      # 5432, a number

It is a Mapping, so len(), in, iteration and unpacking all work on it.

Saying you meant the text

Quote it:

DB_PORT_TEXT="5432"
settings["DB_PORT_TEXT"]   # '5432', a string

Default values

settings.get("MISSING", "a default")   # 'a default'
settings.get("MISSING")                # None

Required keys

Where there is no sensible default, say so and find out at boot rather than at midnight:

settings.required("DATABASE_HOST")
ValueNotSetError: Value not set for key: DATABASE_HOST

Comments after a value

A # starts a comment where a shell would treat it as one — after whitespace, and outside quotes:

COMMENTED=5432 # the default
PASSWORD=hunter2#7
QUOTED="a # inside quotes"
settings["COMMENTED"]   # 5432
settings["PASSWORD"]    # 'hunter2#7'
settings["QUOTED"]      # 'a # inside quotes'

A parser which took every # would turn a password into a shorter password and say nothing about it.

Nothing is expanded

URL=https://${APP_NAME}.org
settings["URL"]   # 'https://${APP_NAME}.org'

Setting the environment anyway

For the sake of something else which reads os.environ directly:

settings.export()                 # leaves what is already set alone
settings.export(override=True)    # does not

What goes out is text: True is exported as true, because that is what it was in the file and what another reader expects to find. A deployment which set a variable meant it, which is why what is already there wins unless you say otherwise.

Benchmark

Not measured against python-dotenv, which is the obvious comparison and not a fair one: it hands back strings and this reads types, so the two are doing different amounts of work on purpose. Timing them against each other would produce a number saying this is slower at a job it is not doing.

Either way, a .env file is read once at boot and has perhaps thirty lines in it. Where an application is slow to start, this is not why.

Tests

uv run pytest

Static analysis

uv run ruff check --no-cache
uv run mypy

--no-cache on purpose: a cached ruff result once said a Quillstack package was clean while CI said it was not.

Against the standard

uv run quillstack-standards .

The rest of Quillstack

This is one component of Quillstack, the same way of building APIs in more than one language.

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quillstack_dotenv-0.1.0.tar.gz (53.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quillstack_dotenv-0.1.0-py3-none-any.whl (9.0 kB view details)

Uploaded Python 3

File details

Details for the file quillstack_dotenv-0.1.0.tar.gz.

File metadata

  • Download URL: quillstack_dotenv-0.1.0.tar.gz
  • Upload date:
  • Size: 53.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for quillstack_dotenv-0.1.0.tar.gz
Algorithm Hash digest
SHA256 826849f9e0aec5f295e986e8d002ae176c9bfa9b473d465597946c8c60d7d879
MD5 f9c34f7fcc1f69caafc1aec3cc973677
BLAKE2b-256 6a9a6418345581e3ef220b735dbff09f4e1e87f1c6dcb29bdfa6240df37ffd91

See more details on using hashes here.

Provenance

The following attestation bundles were made for quillstack_dotenv-0.1.0.tar.gz:

Publisher: release.yml on quillstack-py/dotenv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file quillstack_dotenv-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for quillstack_dotenv-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f22fca0452b53a8f4044103aefdf9c9f2e452e6912175013bd2a781497b49f14
MD5 111acc387989da68ab9b3de36a2de041
BLAKE2b-256 ce49fd5a174fc3de9117a72ba0acb7486b5bf1ebe56884abf982675a1881b417

See more details on using hashes here.

Provenance

The following attestation bundles were made for quillstack_dotenv-0.1.0-py3-none-any.whl:

Publisher: release.yml on quillstack-py/dotenv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.1

2 files

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page