Cookbook

EnvVar variable

EnvVars are best defined as global variables (so they will be included in the description). Also, to differentiate the environment variables and their eventually retrieved values, we should end the name of the EnvVar variables with the suffix _ev.

board_size_ev : EnvVar[int] = env_var('BOARD_SIZE', type=int, default=8)

...

class MyApp:
    def __init__(...):
        ...
        self.board_size = board_size_ev.get()
        ...

Retrieving EnvVar Values

EnvVars should be retrieved once, preferably at the start of the program or initialization of singletons. This is important for consistency. While envolved handles environment variables changing from within the python program, external changes to environment variables are not handled.

Warning

This is especially important when running on python 3.7, where in some cases, the environment variables will have to be reloaded on every retrieval.

Common Factories

Here are some common types and factories to use when creating a SchemaEnvVar

class Point(typing.NamedTuple):
    x: int
    y: int

origin_ev = env_var('ORIGIN_', type=Point, args={
    'x': inferred_env_var(),
    'y': inferred_env_var(),
})

source_ev = env_var('Source_', type=SimpleNamespace, args={
    'x': inferred_env_var(type=int),
    'y': inferred_env_var(type=int),
})

# both these will result in a namespace that has ints for x and y

class PointTD(typing.TypedDict):
    x: int
    y: int

destination_ev = env_var('ORIGIN_', type=PointTD, args={
    'x': inferred_env_var(),
    'y': inferred_env_var(),
})

# this will result in a dict that has ints for keys "x" and "y"

Inferring Schema Parameter Names Without a Schema

We can actually use inferred_env_var() to infer the name of EnvVar parameters without a schema. This is useful when we want to prototype a schema without having to create a schema class.

from envolved import ...

my_schema_ev = env_var('FOO_', type=SimpleNamespace, args={
    'x': inferred_env_var(type=int, default=0),
    'y': inferred_env_var(type=string, default='hello'),
})

# this will result in a namespace that fills `x` and `y` with the values of `FOO_X`
# and `FOO_Y` respectively

Note a sticking point here, we have to specify not only the type of the inferred env var, but also the default value.

from envolved import ...

my_schema_ev = env_var('FOO_', type=SimpleNamespace, args={
    'x': inferred_env_var(type=int),  # <-- this code will raise an exception
})

Note

Why is this the behaviour?

In normal env_var(), not passing a default implies that the EnvVar is required, why can’t we do the same for inferred_env_var()? We do this to reduce side effects when an actual schema is passed in. If we were to assume that the inferred env var is required, then plugging in a schema that has a default value for that parameter would be a hard-to-detect breaking change that can have catostraphic consequences. By requiring the default value to be passed in, we force the user to be explicit about the default values, ehan it might be inferred.

We can specify that an inferred env var is required by explicitly stating default=missing

from envolved import ..., missing

my_schema_ev = env_var('FOO_', type=SimpleNamespace, args={
    'x': inferred_env_var(type=int, default=missing),
    'y': inferred_env_var(type=string, default='hello'),
})

# this will result in a namespace that fills `x` with the value of `FOO_X`
# and will raise an exception if `FOO_X` is not set

Absolute Variable Names

When creating a schema, we can specify a child env var whose name will not be prefixed with the schema name by making the key of the child env var an intance of the AbsoluteName class.

from envolved import AbsoluteName

my_schema_ev = env_var('FOO_', type=SimpleNamespace, args={
    'x': env_var("X", type=int),
    'y': env_var(AbsoluteName("BAR_Y"), type=int),
})

# this will result in a namespace that fills `x` with the value of `FOO_X`,
#  but `y` with the value of `BAR_Y`
class AbsoluteName[source]

A subclass of str that is used to specify that an env var should not be prefixed.