TypedEnv

Plumbum provides this utility class to facilitate working with environment variables. Similar to how plumbum.cli.Application parses command line arguments into pythonic data types, plumbum.typed_env.TypedEnv parses environment variables:

class MyEnv(TypedEnv):

username = TypedEnv.Str(“USER”, default=’anonymous’) path = TypedEnv.CSV(“PATH”, separator=”:”, type=local.path) tmp = TypedEnv.Str([“TMP”, “TEMP”]) # support ‘fallback’ var-names is_travis = TypedEnv.Bool(“TRAVIS”, default=False) # True is ‘yes/true/1’ (case-insensitive)

We can now instantiate this class to access its attributes:

>>> env = MyEnv()
>>> env.username
'ofer'

>>> env.path
[<LocalPath /home/ofer/bin>,
 <LocalPath /usr/local/bin>,
 <LocalPath /usr/local/sbin>,
 <LocalPath /usr/sbin>,
 <LocalPath /usr/bin>,
 <LocalPath /sbin>,
 <LocalPath /bin>]

>>> env.tmp
Traceback (most recent call last):
  [...]
KeyError: 'TMP'

>>> env.is_travis
False

Finally, our TypedEnv object allows us ad-hoc access to the rest of the environment variables, using dot-notation:

>>> env.HOME
'/home/ofer'

We can also update the environment via our TypedEnv object:

>>> env.tmp = "/tmp"
>>> env.tmp
'/tmp'
>>> from os import environ
>>> env.TMP
'/tmp'
>>> env.is_travis = True
>>> env.TRAVIS
'yes'
>>> env.path = [local.path("/a"), local.path("/b")]
>>> env.PATH
'/a:/b'

TypedEnv as an Abstraction Layer

The TypedEnv class is very useful for separating your application from the actual environment variables. It provides a layer where parsing and normalizing can take place in a centralized fashion.

For example, you might start with this simple implementation:

class CiBuildEnv(TypedEnv):
    job_id = TypedEnv.Str("BUILD_ID")

Later, as the application gets more complicated, you may expand your implementation like so:

class CiBuildEnv(TypedEnv):
    is_travis = TypedEnv.Bool("TRAVIS", default=False)
    _travis_job_id = TypedEnv.Str("TRAVIS_JOB_ID")
    _jenkins_job_id = TypedEnv.Str("BUILD_ID")

    @property
    def job_id(self):
        return self._travis_job_id if self.is_travis else self._jenkins_job_id

TypedEnv vs. local.env

It is important to note that TypedEnv is separate and unrelated to the LocalEnv object that is provided via local.env.

While TypedEnv reads and writes directly to os.environ, local.env is a frozen copy taken at the start of the python session.

While TypedEnv is focused on parsing environment variables to be used by the current process, local.env’s primary purpose is to manipulate the environment for child processes that are spawned via plumbum’s local commands.