Configuration
This module implements functionality to manage configurations in applications and services. Most applications and
services will use a hierarchical structure for configuration to allow configuration values to be overwritten by
configuration overrides. The Config
class allows applications and services to represent that hierarchy.
Imagine a service that will run in the cloud as a serverless application in AWS Lambda. We normally implement this application as a Flask application, so we can test it locally, and then deploy it to Lambda using Zappa.
The application has multiple environments and allows for configuration overrides. The idea is to have a default configuration with the most appropriate values. This default configuration can be overwritten by a separate configuration file. The override will reside locally in the development environment, and in AWS S3 when running in cloud environments. Finally, we will like to support environment variables that can override some of the configuration values.
The application can expose a config.py
module that provides the configuration. The following is an example of such
config.py
:
# In config.py
import os
import en_core.configuration as c
import en_core.configuration.local as cl
import en_core.configuration.s3 as cs3
# Default configuration definition
DEFAULT_CONFIGURATION = {
'max_threads': 10,
'dbconnect': 'file:///data.sqlite
}
_config = None
def get_config():
global _config
if not _config:
# Environment variables are case insensitive in Windows
# but not Linux
#
env_config = c.CaseInsensitiveMapping(os.environ)
environment = os.environ.get('ENVIRONMENT')
if environment.lower() == 'local':
override_file = os.environ.get('CONFIG_OVERRIDE')
source = cl.LocalJsonFile(override_file)
else:
bucket = os.environ.get('CONFIG_BUCKET')
key = os.environ.get('CONFIG_KEY')
source = cs3.S3JsonFile(bucket, key)
override_config = c.CaseInsensitiveFileMapping(source)
default_config = c.CaseInsensitiveMapping(DEFAULT_CONFIGURATION)
_config = c.Config(env_config, override_config, default_config)
return _config
# In application code.
import config
configuration = config.get_config()
connect_str = configuration.get('DBCONNECT')
In the example above, the environment is specified first; therefore, it will override other configuration values with the same keys. If the key is not found in the environment, it will look in the override file. Finally, it will look in the default configuration if the key is not found.
- class CaseInsensitiveFileMapping(source)
This class extends
CaseInsensitiveMapping
to initialize the values using a source. The source object must implement a .read() method that returns a mapping.- Parameters
source (Source) – Object that provides the initial mapping returned from the .read() method.
import en_core.configuration as config import en_core.configuration.s3 as s3c source = s3c.S3JsonFile('my-bucket', 'path/to/config.json') mapping = config.CaseInsensitiveFileMapping(source) mapping.get('existing') # Returns value from the file. mapping.get('ANOTHER_EXISTING') # Returns value from the file. mapping.get('INEXISTENT') # Returns None.
- class CaseInsensitiveMapping(mapping)
This class implements the
collections.abc.Mapping
interface treating keys as case insensitive. The class is initialized with other mapping object used as a source for the values.- Parameters
mapping (Mapping) – Mapping object containing the initial values of the map.
import en_core.configuration as config original_mapping = { 'value1: 1, 'value2: 'second value', 'value_3': 3 } mapping = config.CaseInsensitiveMapping(original_mapping) mapping.get('VALUE1') # -> 1 mapping.get('Value2') # -> 'second value' mapping.get('vAlUe_3) # -> 3 mapping.get('INEXISTENT) # -> None
The mapping returns all the keys in upper case, so it can be used for configuration because some applications require configuration keys to be all upper case.
# Continue example mapping.keys() # -> ['VALUE1', 'VALUE2', 'VALUE_3']
- class Config(*mappings)
This class represents the configuration of an application and service. The class is initialized with a list of mappings (dictionary like objects) where the configuration parameters are stored. The look up priority is done in the order in which the mappings are added; therefore, mappings added in-front will override values of subsequent mappings.
The class supports the full
collections.abc.Mapping
interface, which makes it suitable as a configuration object from most application frameworks.
JSON Sources
Base classes for JSON based sources.
Local Sources
This module implements functionality that allow using local files as sources for configuration.
- class LocalJsonFile(file_name, _open_func=None)
Implements the configuration Source interface to read the configuration from a JSON file in the local file system. The class is initialized with the path pointing to the file containing the configuration.
- Parameters
file_name (str) – Name of the bucket where the configuration is stored.
AWS S3 Sources
This module provides functionality to read configurations from AWS S3. Applications and services using this module are
required to add ptaws
as a dependency since this library doesn’t include it.
- class S3JsonFile(bucket, file_obj, _client=None)
Implements the configuration Source interface to read the configuration from a JSON file in S3. The class is initialized with the S3 bucket and file key pointing to the file containing the configuration.
- Parameters
bucket (str) – Name of the bucket where the configuration is stored.
file_obj (str) – Key to the JSON configuration file