Skip to main content

Type safe environment variables

Project description

codecov Build Passing PyPI

pysafe-config

pysafe-config is a lightweight Python library designed to simplify the process of reading environment variables.

It provides a set of four fully type-hinted functions to read environment variables, one for each of the following commonly used type of rnvironment variqgle {str, int, float, bool}. The docs can be found here.

Why it exists

The Problem: Boilerplate and Error-Prone Environment Variable Handling

Handling environment variables isn't something you should be worrying about when writing an application or service in Python. However, it can involve writing repetitive and error-prone code, especially when dealing with large numbers of environment variables requiring casting to their expected types. Other libraries exist to help manage your environment (Dynaconf, py-dotenvsafe), but what if you just want a type-aware (and as type-safe as possible in Python!) version os.getenv?

Consider the common scenario of retrieving an environment variable, SAMPLING_RATIO as a float:

import os
SAMPLING_RATIO = os.getenv("SAMPLING_RATIO", None)

if SAMPLING_RATIO is None:
    raise RuntimeError("SAMPLING_RATIO is unset")
else:
    SAMPLING_RATIO = float(SAMPLING_RATIO)

This approach is susceptible to ValueError if the conversion fails, requires explicit checks for None in the case that the variable is unset, and potentially requires additional validation for weird edge-cases like "-inf".

The Solution: pysafe-config

pysafe-config streamlines this process, allowing you to retrieve and validate environment variables with minimal code. The previous example can be reduced to a single clear line.

from pysafe_config import getenv_float

SAMPLING_RATIO: float = getenv_float("SAMPLING_RATIO")

# or, for non-critical env vars

SAMPLING_RATIO: float | None = getenv_float("SAMPLING_RATIO", required=False)

Features and Benefits

  • Strict By Default: Raises an exception if no environment variable is set by default, unless it has explicitly been marked as optional, preventing silent failures.
  • Consistent Validation: Enforces strict, consistent and reliable validation rules for different types, using a sensible and deterministic approach.
  • Clear and Verbose Error Messages: Provides descriptive error messages for missing or invalid environment variables.
  • Reduced Boilerplate: Significantly cuts down the amount of code needed to read and validate environment variables.
  • Type Safety: Works with all modern type linters. No more checking for Nones and raising errors in config files.

Installation

poetry

poetry add pysafe-config

pip

pip install pysafe-config

Usage

The default behaviour is that a RuntimeError will be raised if the variable is missing, or a ValueError if the type conversion fails. This behaviour can be switched off if the function is called with required=False

from pysafe_config import (
    getenv_int,
    getenv_str,
    getenv_bool,
    getenv_float,
)
# Optional string with a default value
LOG_LEVEL: str | None = getenv_str("LOG_LEVEL", default="INFO", required=False)

# Required integer - raises a RuntimeError if MAX_RETRIES is unset
MAX_RETRIES: int = getenv_int("MAX_RETRIES")

# Required boolean with no default -  raises a RuntimeError if DEBUG_MODE is unset
DEBUG_MODE: bool = getenv_bool("DEBUG_MODE", required=True)

# Optional float with no default value - can return None
SCALING_FACTOR: float | None = getenv_float("SCALING_FACTOR", required=False)

# Required boolean - raises a ValueError if RETURN_UPSTREAM_ERRORS is not a sensible boolean value
RETURN_UPSTREAM_ERRORS: bool | None = getenv_bool("RETURN_UPSTREAM_ERRORS")

Supported Boolean Values

pysafe-config provides robust parsing for boolean environment variables. The following case-insensitive values are recognised:

True values False values
"true" "false"
"1" "0"
"yes" "no"
"y" "n"
"on" "off"
"enable" "disable"
"enabled" "disabled"
"t" "f"

Supported Float Values

Float values must adhere to a strict format:

  • Contain only digits (0-9), optionally preceded by a single + or - sign.
  • Include exactly one decimal point to separate the whole and fractional parts.
  • Not contain any whitespace, commas, or alphabetic characters.
Valid strings Invalid strings
"50.2" "50"
"-0.0" "5.5.5"
"+1000.5" " 12.3"
"-99.0" "12,3"
"0.0001" "ten"
"+.5" "5."
"-1.23" "" (empty)

Supported Integer Values

Integer values must adhere to a strict format:

  • Contain only digits (0-9), optionally preceded by a single + or - sign.
  • Not contain any whitespace.
  • Not include decimal points, letters, or special symbols.
Valid strings Invalid strings
"100" " 100"
"1" "10.5"
"-50" "1,000"
"+1000" "12a"
"0" "++5"
"-0" "5-"
"123456" "ten"
"-123456" "" (empty)

Contributing

Contributions are welcome! Please refer to the CONTRIBUTING.md for guidelines.

License

This project is licensed under the MIT License.

Release docs

The release process needs work, but for now:

  1. Ensure to bump the version number in pyproject.toml
  2. Get the names of the closed PRs since the last release
  3. Create a new release, paste in the names of the previous MRs into the changelog
  4. Create the new tag, being sure to use the next version up since the previous release
  5. Go to Actions and approve the Github workflow
  6. Once finished, try installing the latest version in a shell using pip install pysafe-config

Future work

  • Add a function for parsing enums from environment variables
  • Add a function that allows the user to pass the type they are expecting into a get_env function
    • get_env("NUM_ROWS", int, ...)
  • Test the error strings in error messages

Project details


Download files

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

Source Distribution

pysafe_config-1.0.0.tar.gz (9.2 kB view details)

Uploaded Source

Built Distribution

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

pysafe_config-1.0.0-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file pysafe_config-1.0.0.tar.gz.

File metadata

  • Download URL: pysafe_config-1.0.0.tar.gz
  • Upload date:
  • Size: 9.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pysafe_config-1.0.0.tar.gz
Algorithm Hash digest
SHA256 8b37dcb8efb791b6bb13f0860603c06419bb40acaf75039defd1aaccfb4f3b78
MD5 1eeb8040bbeed6eb27c87ce983b1ea2c
BLAKE2b-256 deafa4b360a659f6d2c1fcfc2af33c0a8a152530a06776d0b0ba2beeb9406625

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysafe_config-1.0.0.tar.gz:

Publisher: publish-release.yml on Lancasterg/pysafe-config

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

File details

Details for the file pysafe_config-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: pysafe_config-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 10.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pysafe_config-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 46f9f3dc87c516fe26ac5b2697ad021471ef1e2d87bafe593136bab0a18629be
MD5 1768e7c671854edd0d3eb997dbbf4ba7
BLAKE2b-256 cffb50c49ad6baed39931cc73db8c0cd3c975b2a3697e1a2eaa66369b5d995fc

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysafe_config-1.0.0-py3-none-any.whl:

Publisher: publish-release.yml on Lancasterg/pysafe-config

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

Supported by

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