Skip to main content

speckenv

speckenv because a speck is a synonym for a dot and because Speck is awesome.

Usage

Basic

Read the settings contained in ./.env into os.environ:

from speckenv import read_speckenv

read_speckenv()

Note that read_speckenv uses os.environ.setdefault to set new values, which means that if a particular key exists more than once in the file the first value is retained, not the last.

If the file is named differently or resides in a different path, pass the full path as first argument to read_speckenv.

Read individual values:

from speckenv import env

# Standard usage:
SETTING1 = env("SETTING1")

# Fallback if SETTING2 does not exist:
SETTING2 = env("SETTING2", default="bla")

# Fail hard if missing:
SETTING3 = env("SETTING3", required=True)

# Coerce the value before returning it (coercion is also applied to
# default values):
SETTING4 = env(
    "SETTING4",
    coerce=lambda value: date(*(int(part) for part in value.split("-"))),
    default="1970-01-01",
)

The following values are evaluated as Python literals, therefore coercing values may be useful less often than you might think:

BOOL=True  # And False, None etc.
NUMBER=42
SWEET_HOME=["localhost", "127.0.0.1"]

Additional whitespace around the equals sign is supported. Empty lines and lines starting with a # are ignored:

THIS_IS_IGNORED
# COMMENTED_OUT=VALUE
THIS = WORKS

You shouldn’t use comments in lines though. They sometimes work by accident but it’s a bad idea.

If a value looks like a Python type but you want to load it as a string you have to add quote characters (" or ') around the value or use coercion, e.g.

NUMBER_AS_STRING = env("NUMBER", coerce=str)

# Alternatively, read the value directly from os.environ:
NUMBER_AS_STRING = os.environ["NUMBER"]

Custom mapping instead of os.environ

It may be useful to use a mapping separate from os.environ. This is easily possible by overriding the default mapping argument:

from speckenv import env, read_speckenv

mapping = {}
read_speckenv("file_with_variables.env", mapping=mapping)
setting1 = env("SETTING1", mapping=mapping)

Django support

speckenv comes with a few utilities for configuring Django using environment variables. These are all pure functions without any side effects and no dependency on their environment. They are only bundled with speckenv because they are useful and because it’s convenient to do so.

Many other projects exist which already do this but speckenv_django is different in that it only covers interesting settings. Also, the implementation doesn’t add monkey patches to urllib.parse.

speckenv doesn’t depend on Django, if you don’t want to use Django or the speckenv_django module you’re not paying anything besides a few KiB on the harddisk.

django_cache_url

Covers configuring a Redis, locmem or dummy cache backend with optional authentication credentials. The Redis configuration only supports Django 4 or better. redis:// and hiredis:// are equivalent since recent enough versions of redis-py automatically select the hiredis parser if it is available. Query string parameters other than key_prefix are passed on to redis-py’s connection pool; values are parsed using ast.literal_eval where possible. Setting timeouts is a good idea, without them a request may hang for a long time if the Redis server goes away without closing the connection: ?socket_connect_timeout=2&socket_timeout=2&health_check_interval=30.

from speckenv import env
from speckenv_django import django_cache_url

# CACHE_URL=hiredis://localhost:6379/1/?key_prefix=example_com"
CACHES = {"default": django_cache_url(env("CACHE_URL", default="locmem://"))}
# NOTE! locmem:// may be a bad default, but that's up to you really.

django_database_url

Covers configuring a PostgreSQL, PostGIS or sqlite database engine with authentication credentials.

from speckenv import env
from speckenv_django import django_database_url

# DATABASE_URL=postgres://localhost:5432/example_com
DATABASES = {"default": django_database_url(env("DATABASE_URL", required=True))}

django_email_url

Covers configuring an email backend. Known backends are smtp://, submission:// (same as smtp:// but with TLS and a default port of 587), locmem://, console:// and dummy:.

The utility also supports explicitly requesting SSL (?ssl=true), TLS (?tls=true), SMTP timeouts (?timeout=10), setting a DEFAULT_FROM_EMAIL address (?_default_from_email=info@example.com) and setting a SERVER_EMAIL address (?_server_email=info@example.com). Note that since Django uses individual variables instead of a dictionary you have to pass the return value to globals().update().

from speckenv import env
from speckenv_django import django_email_url

# EMAIL_URL=smtp://
if DEBUG:
    globals().update(django_email_url(env("EMAIL_URL", default="console://")))
else:
    globals().update(django_email_url(env("EMAIL_URL", default="smtp://")))

Django 6.1 deprecated the individual EMAIL_* settings in favor of the MAILERS dictionary; use django_mailer_url below instead when you’re using Django 6.1 or better.

django_mailer_url

Returns an entry for the MAILERS dictionary introduced in Django 6.1. Supports the same URLs as django_email_url, and additionally accepts ?ssl_keyfile=... and ?ssl_certfile=.... SERVER_EMAIL isn’t a part of a mailer’s configuration, so _server_email raises a ValueError. _default_from_email is passed on as a default_from_email option; Django’s own backends reject it, but custom backends may support it. Use the backend keyword argument to select such a backend, e.g. django_mailer_url(url, backend="email_hosts.backends.EmailHostsBackend").

from speckenv import env
from speckenv_django import django_mailer_url

# MAILER_URL=submission://user:password@smtp.example.com
MAILERS = {
    "default": django_mailer_url(
        env("MAILER_URL", default="console://" if DEBUG else "smtp://")
    )
}
DEFAULT_FROM_EMAIL = env("DEFAULT_FROM_EMAIL", default="webmaster@localhost")

Automatically substituting other Django 12factor libraries

speckenv ships a Python module which inserts Python modules named dj_database_url, django_cache_url and dj_email_url into sys.modules (if they do not exist already) which contain basic functions calling the functions mentioned above. This module is almost guaranteed to NOT work in an arbitrary environment but it may be useful as a quick solution if you do want to change the settings module as little as possible when upgrading your code to Django 4.0 and are already using speckenv. To use it you should insert the following line at the top of your settings module:

import speckenv_django_patch  # noqa: isort:skip

import dj_database_url, django_cache_url, dj_email_url
DATABASES = dj_database_url.config()
CACHES = django_cache_url.config()
globals().update(dj_email_url.config())

You should check the module’s code to view defaults; they are adopted from the libraries which are being substituted, but when you’re in doubt better check twice.

Metadata

Release files for speckenv 6.4.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 speckenv 6.4.0
File Size Uploaded Provenance
speckenv-6.4.0.tar.gz 8.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for speckenv 6.4.0
File Interpreter ABI Platform
speckenv-6.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 17.7 kB

Release files / speckenv-6.4.0.tar.gz

Download URL speckenv-6.4.0.tar.gz
Size 8.5 kB
Tags Source
SHA-256 checksum
How to use checksums
777f00cb849bedc495621de4489d89e6a967d68304e4dcc7d7ccdd66ef79b462
BLAKE2b-256 checksum
How to use checksums
f937a3ab959d3558e5072bfdfa545d440236b52fab64db90ddac910e472b7518
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Oct 21, 2026.

Transparency log

Release files / speckenv-6.4.0-py3-none-any.whl

Download URL speckenv-6.4.0-py3-none-any.whl
Size 9.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7ab19c61aced1a327b6524d75425ba9403432a42f879cd6c877be37ae1c392b6
BLAKE2b-256 checksum
How to use checksums
dac19e467560e697f6e7f2b3bcf87b1cf0e4c9a2b71834326a4352f0ff72d0c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Oct 21, 2026.

Transparency log

Security for speckenv 6.4.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for speckenv-6.4.0.tar.gz

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 Oct 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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