Skip to main content

Map a Python configuration from environment variables

Project description

https://travis-ci.org/jmcs/ecological.svg?branch=master Codacy Badge https://api.codacy.com/project/badge/Coverage/1ff45d0e1a5a40b8ad0569e3edb0539d

Ecological

Ecological combines PEP526 and environment variables to make the configuration of 12 factor apps easy.

Getting Started

Ecological automatically gets and converts environment variables according to the configuration class definition.

For example, imagine your application has a configurable (integer) Port and (boolean) Debug flag and a (string) Log Level, that is INFO by default, you could simply declare your configuration as:

class Configuration(ecological.Config):
    port: int
    debug: bool
    log_level: str = "INFO"

And then set the environment variables PORT, DEBUG and LOG_LEVEL. Ecological will automatically set the class properties from the environment variables with the same (but upper cased) name.

By default the values are set at the class definition type and assigned to the class itself (i.e. the class doesn’t need to be instantiated). If needed this behavior can be changed (see the Autoloading section).

Tutorial

The tutorial can be used to get to know with the library’s basic features interactively.

Typing Support

Ecological also supports some of the types defined in PEP484, for example:

class Configuration(ecological.Config):
    list_of_values: List[str]

Will automatically parse the environment variable value as a list.

Prefixed Configuration

You can also decide to prefix your application configuration, for example, to avoid collisions:

class Configuration(ecological.Config, prefix='myapp'):
    home: str

In this case the home property will be fetched from the MYAPP_HOME environment property.

Nested Configuration

Ecological.Config also supports nested configurations, for example:

class Configuration(ecological.Config):
    integer: int

    class Nested(ecological.Config, prefix='nested'):
        boolean: bool

This way you can group related configuration properties hierarchically.

Advanced

Fine-grained Control

You can control some behavior of how the configuration properties are set.

It can be achieved by providing a ecological.Variable instance as the default value for an attribute or by specifying global options on the class level:

my_source = {"KEY1": "VALUE1"}

class Configuration(ecological.Config, transform=lambda v, wt: v, wanted_type=int, ...):
    my_var1: WantedType = ecological.Variable(transform=lambda v, wt: wt(v), source=my_source, ...)
    my_var2: str
    # ...

All possible options and their meaning can be found in the table below:

Option

Class level

Variable level

Default

Description

prefix

yes

no

None

A prefix that is uppercased and prepended when a variable name is derived from an attribute name.

variable_name

yes

yes

Derived from attribute name and prefixed with prefix if specified; uppercased.

When specified on the variable level it states the exact name of the source variable that will be used.

When specified on the class level it is treated as a function that returns a variable name from the attribute name with the following signature:

def func(attribute_name: str, prefix: Optional[str] = None)

default

no

yes

(no default)

Default value for the property if it isn’t set.

transform

yes

yes

A source value is casted to the wanted_type In case of non-scalar types (+ scalar bool) the value is Python-parsed first.

A function that converts a value from the source to the value and wanted_type you expect with the following signature:

def func(source_value: str, wanted_type: Union[Type, str])

source

yes

yes

os.environ

Dictionary that the value will be loaded from.

wanted_type

yes

yes

str

Desired Python type of the attribute’s value.

On the variable level it is specified via a type annotation on the attribute: my_var_1: my_wanted_type.

However it can be also specified on the class level, then it acts as a default when the annotation is not provided:

class MyConfig(ecological.Config, wanted_type=int, ...)

The following rules apply when options are resolved:

  • when options are specified on both levels (variable and class), the variable ones take precedence over class ones,

  • when some options are missing on the variable level, their default values are taken from the class level,

  • it is not necessary to assign an ecological.Variable instance to change the behavior; it can still be changed on the class level (globally).

Autoloading

It is possible to defer/disable autoloading (setting) of variable values by specifying the autoload option on class definition.

On class creation (default)

When no option is provided values are loaded immediately on class creation and assigned to class attributes:

class Configuration(ecological.Config):
    port: int
# Values already read and set at this point.
# assert Configuration.port == <value-of-PORT-env-var>
Never

When this option is chosen, no autoloading happens. In order to set variable values, the Config.load method needs to be called explicitly:

class Configuration(ecological.Config, autoload=ecological.Autoload.NEVER):
    port: int
# Values not set at this point.
# Accessing Configuration.port would throw AttributeError.

Configuration.load()
# Values read and set at this point.
# assert Configuration.port == <value-of-PORT-env-var>
On object instance initialization

If it is preferred to load and store attribute values on the object instance instead of the class itself, the Autoload.OBJECT strategy can be used:

class Configuration(ecological.Config, autoload=ecological.Autoload.OBJECT):
    port: int
# Values not set at this point.

config = Configuration()
# Values read and set at this point on ``config``.
# assert config.port == <value-of-PORT-env-var>
# Accessing ``Configuration.port`` would throw AttributeError.

Caveats and Known Limitations

  • Ecological doesn’t support (public) methods in Config classes

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

ecological-2.0.0.tar.gz (11.2 kB view details)

Uploaded Source

Built Distribution

ecological-2.0.0-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file ecological-2.0.0.tar.gz.

File metadata

  • Download URL: ecological-2.0.0.tar.gz
  • Upload date:
  • Size: 11.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/0.12.16 CPython/3.7.2 Darwin/18.6.0

File hashes

Hashes for ecological-2.0.0.tar.gz
Algorithm Hash digest
SHA256 1b147a1e9f517cc3cd8b5d721fdcc562f371af3d4507711d19ab1d47b89d3c5a
MD5 d56054e54780c5a8f8d1cf00f097cd11
BLAKE2b-256 1306c6c60ba2b394942276d58fb1c8b20a8c77b06b60d7e9204e486a99298025

See more details on using hashes here.

File details

Details for the file ecological-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: ecological-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 9.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/0.12.16 CPython/3.7.2 Darwin/18.6.0

File hashes

Hashes for ecological-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6c90386d3606911410246aef4b04592bd961c99c2789f52e23fcc66152b5164b
MD5 96e10302bd57bcca404b63c75b975a4c
BLAKE2b-256 8e423d83e880115dbe5daf42a1cc5326eb674cf627fc199910e069cd3d0c2a03

See more details on using hashes here.

Supported by

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