![PyPI version](https://img.shields.io/pypi/v/typenv)
typenv
Version 0.2.0
Typed environment variable parsing for Python
Table of Contents generated with mdformat-toc
Background
Typenv does environment variable parsing with an API almost identical to the excellent environs.
There are a few reasons why typenv might be preferred:
- Type annotated typecast functions: type checkers are able to understand types of parsed environment variables.
- More flexible prefix manipulation of environment variable names.
- Validation of environment variable names.
- Optional automatic uppercasing of environment variable names.
- Ability to generate a .env.example that shows expected types of environment variables.
- Less dependencies. No marshmallow required.
Installing
Installing from PyPI repository (https://pypi.org/project/typenv):
pip install typenv
Usage
Basics
Set environment variables:
export NAME='Harry Potter'
export AGE=14
export IS_WIZARD=true
export PATRONUM_SUCCESS_RATE=0.92
export BANK_BALANCE=134599.01
export LUCKY_NUMBERS=7,3,11
export EXTRA_DETAILS='{"friends": ["Hermione", "Ron"]}'
export FAVORITE_COLOR=0x7f0909
Parse the values in Python:
from typenv import Env
env = Env()
NAME = env.str("NAME")
AGE = env.int("AGE")
IS_WIZARD = env.bool("IS_WIZARD")
PATRONUM_SUCCESS_RATE = env.float("PATRONUM_SUCCESS_RATE")
BANK_BALANCE = env.decimal("BANK_BALANCE")
LUCKY_NUMBERS = env.list("LUCKY_NUMBERS", subcast=int)
EXTRA_DETAILS = env.json("EXTRA_DETAILS")
FAVORITE_COLOR = env.bytes("FAVORITE_COLOR", encoding="hex")
IS_DEATH_EATER = env.bool("IS_DEATH_EATER", default=False)
Supported types
The types supported by typenv are:
env.str
env.int
env.bool
env.float
env.decimal
env.list
- Takes a
subcast
keyword argument for casting list items to one of str
, int
, bool
, float
or decimal.Decimal
env.json
env.bytes
- Takes an
encoding
keyword argument for indicating how the bytes are encoded.
For now only hex
is supported.
Default values
Normally, if an environment variable is not found, typenv raises an exception.
If a default value is provided, however, that will be returned instead of raising.
from typenv import Env
env = Env()
BOOL = env.bool("NON_EXISTING_NAME", default=False)
LIST = env.list("NON_EXISTING_NAME", default=["a", "b"])
OPTIONAL_INT = env.int("NON_EXISTING_NAME", default=None)
Name prefixes
export FLASK_HOST=127.0.0.1
export FLASK_PORT=44144
from typenv import Env
env = Env()
HOST = env.str("FLASK_HOST")
PORT = env.int("FLASK_PORT")
with env.prefixed("FLASK_"):
HOST = env.str("HOST")
PORT = env.int("PORT")
env.prefix.append("FLASK_")
HOST = env.str("HOST")
PORT = env.int("PORT")
env.prefix.pop()
Name character set
Typenv validates environment variable names.
By default, the set of allowed characters includes upper case ASCII letters, digits and the underscore (_
).
The set of allowed characters can be configured:
from typenv import Env
env = Env(allowed_chars="ABCDEFGHIJKLMNOPQRSTUVWXYZ")
Name uppercasing
export UPPER_CASE_NAME=true
from typenv import Env
env = Env(upper=True)
NAME = env.bool("upper_casE_Name")
Validation
export NAME='Harry Potter'
export AGE=14
from typenv import Env
env = Env()
NAME = env.str("NAME", validate=lambda n: n.startswith("Harry"))
def is_positive(num):
if num <= 0:
raise Exception("Number is not positive")
def is_less_than_thousand(num):
if num >= 1000:
return False
return True
AGE = env.int("AGE", validate=(is_positive, is_less_than_thousand))
Reading from a .env
file
While developing, it is often useful to read environment variables from a file.
Typenv supports this via the Env.read_end()
method.
The method will look for a file (by default) named .env
in current working directory
and import environment variables from it.
If a file is not found,
the method will walk up in the directory tree until a file is found or the root directory is reached.
The method returns a boolean that is True
if a file is found.
Given a .env
file in current working directory with the following content
SOME_VAR='some value'
The following code will be able to read and parse the value
from typenv import Env
env = Env()
env.read_env()
SOME_VAR = env.str("SOME_VAR")
Dumping parsed values
export SOME_STR=blaablaa
export SOME_INT=99
from typenv import Env, ParsedValue
env = Env()
SOME_STR = env.str("SOME_STR")
SOME_INT = env.int("SOME_INT")
assert env.dump() == {
"SOME_INT": ParsedValue(value=99, type="int", optional=False),
"SOME_STR": ParsedValue(value="blaablaa", type="str", optional=False),
}
Acknowledgments
The public API of this library is almost an exact copy of environs,
which is based on envparse and django-environ.
Credit for the interface goes to the authors of those libraries.