Environment variables¶
Overview¶
fastenv provides a DotEnv
class for working with environment variables.
The implementation of fastenv.DotEnv
is based on os.environ
, and it inherits from the same MutableMapping
class (see comparisons for a description of this data structure). It is intended to be a superset of os.environ
, meaning that it contains some, but not all, of the variables in os.environ
.
Practically speaking, "superset of os.environ
" means:
- When an environment variable is set in an instance of
class DotEnv
, it is also set inos.environ
. - When an environment variable is deleted from an instance of
class DotEnv
, it is also deleted fromos.environ
. - When an environment variable is set directly with
os.environ
, it is not automatically set in instances ofclass DotEnv
.os.environ
contains variables specific to the local environment, such asos.environ["HOME"]
, so these variables are not included inclass DotEnv
by default.
Getting started¶
To get started, let's set up a virtual environment and install fastenv from the command line.
Setting up a virtual environment
python3 -m venv .venv
. .venv/bin/activate
python -m pip install fastenv
Next, we will use the Python interpreter to run a REPL ("Read-Eval-Print Loop"), import fastenv, and create a DotEnv
instance.
Instantiating fastenv.DotEnv
.venv ❯ python
>>> import fastenv
>>> dotenv = fastenv.DotEnv()
That's it! We are ready to start managing our environment variables with fastenv.
Getting, setting, and deleting environment variables¶
Using the os.environ
-style API¶
After instantiating class DotEnv
, environment variables can be managed in the same fashion as with os.environ
, substituting the name of the DotEnv
instance for os.environ
.
Here is an example REPL session demonstrating how to use the os.environ
-style API to manage environment variables. The fastenv
package should be installed in the environment from which the REPL session is started.
Using the os.environ
-style API
.venv ❯ python
>>> import os
>>> import fastenv
>>> dotenv = fastenv.DotEnv()
>>> dotenv["EXAMPLE_VARIABLE"] = "example_value"
>>> dotenv["EXAMPLE_VARIABLE"]
'example_value'
>>> os.environ["EXAMPLE_VARIABLE"]
'example_value'
>>> del dotenv["EXAMPLE_VARIABLE"]
>>> dotenv.getenv("EXAMPLE_VARIABLE", "variable_was_deleted")
'variable_was_deleted'
>>> os.getenv("EXAMPLE_VARIABLE", "variable_was_deleted")
'variable_was_deleted'
Instantiating class DotEnv
¶
Environment variables can be set when creating instances of class DotEnv
. Positional arguments ("args"), keyword arguments ("kwargs"), or a combination of each can be used. Positional arguments can be formatted as individual strings ("KEY1=value1", "KEY2=value2"
), or with multiple variables in the same string separated by spaces ("KEY1=value1 KEY2=value2"
).
Instantiating class DotEnv
with variables
.venv ❯ python
>>> import fastenv
>>> dotenv = fastenv.DotEnv("KEY1=value1", "KEY2=value2 KEY3=value3", key4="value4")
>>> dict(dotenv)
{'KEY1': 'value1', 'KEY2': 'value2', 'KEY3': 'value3', 'KEY4': 'value4'}
Calling DotEnv
instances¶
DotEnv
instances can also get or set environment variables when they are called.
Getting variables with calls¶
A single positional argument with a key only will return the value, or None
if the value is unset. DotEnv
instances also have a getenv
method, corresponding to os.getenv
, that allows an optional default argument to be passed in.
Multiple positional arguments (and multi-variable strings) with keys only will return a mapping of the keys and values from the DotEnv
instance.
Getting variables from a DotEnv
instance
.venv ❯ python
>>> import fastenv
>>> dotenv = fastenv.DotEnv("KEY1=value1")
>>> dotenv("KEY1")
'value1'
>>> dotenv("NOT_SET")
>>> dotenv.getenv("NOT_SET", "default_value")
'default_value'
>>> dotenv("KEY1", "NOT_SET NOT_SET_EITHER")
{'KEY1': 'value1', 'NOT_SET': None, 'NOT_SET_EITHER': None}
Setting variables¶
DotEnv
instance calls with "KEY=value"
strings or keyword arguments will not only set variables, but also return a dict of variables that were set.
If no return value is needed, the setenv
method can be used.
Setting variables in a DotEnv
instance
.venv ❯ python
>>> import fastenv
>>> dotenv = fastenv.DotEnv()
>>> dotenv("KEY1=value1", "KEY2=value2 KEY3=value3", key4="value4")
{'KEY1': 'value1', 'KEY2': 'value2', 'KEY3': 'value3', 'KEY4': 'value4'}
>>> dotenv.setenv(key5="value5")
>>> dict(dotenv)
{'KEY1': 'value1', 'KEY2': 'value2', 'KEY3': 'value3', 'KEY4': 'value4', 'KEY5': 'value5'}
Getting and setting in the same call¶
Complex combinations of getting and setting can be accomplished in the same call, and the result will be returned.
Getting and setting in the same call to a DotEnv
instance
.venv ❯ python
>>> import fastenv
>>> dotenv = fastenv.DotEnv("KEY1=value1")
>>> dotenv("KEY1", "KEY2=value2 KEY3=value3", key4="value4")
{'KEY1': 'value1', 'KEY2': 'value2', 'KEY3': 'value3', 'KEY4': 'value4'}
Deleting variables¶
Single variables can be deleted by using del
.
Multiple variables can be deleted by calling the delenv
method.
Deleting variables from a DotEnv
instance
.venv ❯ python
>>> import fastenv
>>> dotenv = fastenv.DotEnv()
>>> dotenv("KEY1=value1", "KEY2=value2 KEY3=value3", key4="value4")
{'KEY1': 'value1', 'KEY2': 'value2', 'KEY3': 'value3', 'KEY4': 'value4'}
>>> del dotenv["KEY4"]
>>> dotenv.delenv("KEY1", "KEY2", "KEY3")
>>> len(dotenv)
0
Tips¶
Formatting environment variables
In general, environment variables should be formatted with valid shell syntax. Variable values that contain spaces should be quoted to ensure correct parsing.
The example below demonstrates how to set a JSON object as an environment variable from the command line. See the guide to understanding JSON schema for many helpful examples of how JSON data types correspond to Python data types.
❯ JSON_EXAMPLE={"array": [1, 2, 3], "exponent": 2.99e8, "number": 123}
zsh: parse error near `}`
❯ JSON_EXAMPLE='{"array": [1, 2, 3], "exponent": 2.99e8, "number": 123}'
❯ echo $JSON_EXAMPLE
{"array": [1, 2, 3], "exponent": 2.99e8, "number": 123}
Handling type errors
Environment variable keys and values should be strings.
If non-string positional arguments ("args") are passed to a DotEnv
instance, it will raise a TypeError
, rather than attempting to handle the args. This is because args can be used either to get or set variables, and it can be challenging to infer the user's intent when non-string args are used in this situation. Are they passing in a list of args to get? Or maybe the value is intended to be a JSON array? Or maybe the user accidentally passed in a dict of keys and values to set directly, instead of unpacking a dict into kwargs?
For keyword arguments ("kwargs"), the situation is a little easier, because kwargs only set variables. Non-string kwarg values will be converted to strings.
.venv ❯ python
>>> import fastenv
>>> dotenv = fastenv.DotEnv(incorrect_type=[1, 2, 3])
>>> dict(dotenv)
{'INCORRECT_TYPE': '[1, 2, 3]'}