fields

class cincoconfig.Field(*, key=None, schema=None, name=None, required=False, default=None, validator=None, sensitive=False, description=None, help=None, env=None)

The base configuration field. Fields provide validation and the mechanisms to retrieve and set values from a Config. Field’s are composable and reusable so they should not store state or store the field value.

Validation errors should raise a ValueError exception with a brief message.

There are three steps to validating a value:

  1. validate() - checks the value against the required parameter and then calls:

  2. _validate() - validate function that is implemented in subclasses of Field

  3. Field.validator - custom validator method specified when the field is created

The pseudo code for the validate() function:

1def validate(self, cfg, value):
2    if value is None and self.required:
3        raise ValueError
4
5    value = self._validate(cfg, value)
6    if self.validator:
7        value = self.validate(cfg, value)
8    return value

Since each function in the validation chain returns the value, each validator can transform the value. For example, the BoolField _validate method converts the string value to a bool.

Each Field has the following lifecycle:

  1. __init__ - created by the application

  2. __setkey__() - the field is added to a Schema

  3. __setdefault__() - the field is added to a config and the config is populated with the

    default value

Whenever a config value is set, the following methods are called in this order:

  1. validate() / _validate() / validator - validation chain

  2. __setval__() - set a validated value to the config

Finally, whenever code retrieves a config value, the __getval__() is called.

Most field subclasses only need to implement the _validate method and most do not need to implement the __setkey__, __setdefault__, __getval__ and __setval__ methods, unless the field needs to modify the default behavior of these methods.

The Field _key is used to set and reference the value in the config.

Each Field subclass can define a class or instance level storage_type which holds the annotation of the value being stored in memory.

Environment Variables

Fields can load their default value from an environment variable. The Schema and Field accept an env argument in the constructor that controls whether and how environment variables are loaded. The default behavior is to not load any environment variables and to honor the Field.default value.

There are two ways to load a field’s default value from an environment variable.

  • Schema.env: Provide True or a string.

  • Field.env: Provide True or a string.

When Schema.env or Field.env is None (the default), the environment variable configuration is inherited from the parent schema. A value of True will load the the field’s default value from an autogenerated environment variable name, based on the field’s full path. For example:

schema = Schema(env=True)
schema.mode = ApplicationModeField(env="APP_MODE")
schema.port = PortField(env=False)

schema.db.host = HostnameField()

schema.auth = Schema(env="SECRET")
schema.auth.username = StringField()
  • The top-level schema is configured to autogenerate and load environment variables for all fields.

  • mode is loaded from the APP_MODE environment variable.

  • port is not loaded from any the environment variable.

  • db.host is loaded from the DB_HOST environment variable.

  • The auth schema has a environment variable prefix of SECRET. All children and nested fields/schemas will start with SECRET_.

  • The auth.username field is loaded from the SECRET_USERNAME environment variable.

All builtin Fields accept the following keyword parameters.

Parameters
  • name (Optional[str]) – field friendly name, used for error messages and documentation

  • key (Optional[str]) – the key of the field in the config, this is typically not specified and, instead the __setkey__() will be called by the config

  • required (bool) – the field is required and a ValueError will be raised if the value is None

  • default (Union[Callable, Any, None]) – the default value, which can be a called that is invoke with no arguments and should return the default value

  • validator (Optional[Callable[[Config, Any], Any]]) – an additional validator function that is invoked during validation

  • sensitive (bool) – the field stores a sensitive value

  • help (Optional[str]) – the field documentation

_validate(cfg, value)

Subclass validation hook. The default implementation just returns value unchanged.

Return type

Any

__setkey__(schema, key)

Set the field’s _key, which is called when the field is added to a schema. The default implementation just sets self._key = key

Parameters
  • schema (Schema) – the schema the field belongs to

  • key (str) – the field’s unique key

__setdefault__(cfg)

Set the default value of the field in the config. This is called when the config is first created.

Parameters

cfg (Config) – current config

Return type

None

__getval__(cfg)

Retrieve the value from the config. The default implementation retrieves the value from the config by the field key.

Parameters

cfg (Config) – current config

Return type

Any

Returns

the value stored in the config

__setval__(cfg, value)

Set the validated value in the config. The default implementation passes the value through the validation chain and then set’s the validated value int the config.

Parameters
  • cfg (Config) – current config

  • value (Any) – value to validated

property default: Any
Returns

the field’s default value

property name
Returns

the field’s friendly name: name or key

property short_help: Optional[str]

A short help description of the field. This is derived from the help attribute and is the first paragraph of text in help. The intention is that short_help can be used for the field description and help will have the full documentation. For example:

>>> field = Field(help="""
... This is a short description
... that can span multiple lines.
...
... This is more information.
... """)
>>> print(field.short_help)
this is a short description
that can span multiple lines.
Returns

the first paragraph of help

to_basic(cfg, value)

Convert the Python value to the basic value.

The default implementation just returns value. This method is called when the config is saved to a file and will only be called with the value associated with this field.

Parameters
  • cfg (Config) – current config

  • value (Any) – value to convert to a basic type

Return type

Any

Returns

the converted basic type

to_python(cfg, value)

Convert the basic value to a Python value. Basic values are serializable (ie. not complex types). The following must hold true for config file saving and loading to work:

assert field.to_python(field.to_basic(value)) == value

The default implementation just returns value. This method is called when the config is loaded from a file and will only be called with the value associated with this field.

In general, basic types are any types that can be represented in JSON: string, number, list, dict, boolean.

Parameters
  • cfg (Config) – current config

  • value (Any) – value to convert to a Python type

Return type

Any

Returns

the converted Python type

validate(cfg, value)

Start the validation chain and verify that the value is specified if required=True.

Parameters
  • cfg (Config) – current config

  • value (Any) – value to validate

Return type

Any

Returns

the validated value

class cincoconfig.StringField(*, min_len=None, max_len=None, regex=None, choices=None, transform_case=None, transform_strip=None, **kwargs)

A string field.

The string field can perform transformations on the value prior to validating it if either transform_case or transform_strip are specified.

Parameters
  • min_len (Optional[int]) – minimum allowed length

  • max_len (Optional[int]) – maximum allowed length

  • regex (Optional[str]) – regex pattern that the value must match

  • choices (Optional[List[str]]) – list of valid choices

  • transform_case (Optional[str]) – transform the value’s case to either upper or lower case

  • transform_strip (Union[bool, str, None]) – strip the value by calling str.strip(). Setting this to True will call str.strip() without any arguments (ie. striping all whitespace characters) and if this is a str, then str.strip() will be called with transform_strip.

storage_type

alias of str

class cincoconfig.LogLevelField(levels=None, **kwargs)

A field representing the Python log level.

Parameters

levels (Optional[List[str]]) – list of log levels. If not specified, the default Python log levels will be used: debug, info, warning, error, and critical.

storage_type

alias of str

class cincoconfig.ApplicationModeField(modes=None, create_helpers=True, **kwargs)

A field representing the application operating mode.

The create_helpers parameter will create a boolean VirtualField for each mode named is_<mode>_mode, that returns True when the mode is active. When create_helpers=True then each mode name must be a valid Python variable name.

Parameters
  • modes (Optional[List[str]]) – application modes, if not specified the default modes will be used: production and development

  • create_helpers (bool) – create helper a bool VirtualField for each mode

storage_type

alias of str

class cincoconfig.SecureField(method='best', sensitive=True, **kwargs)

A secure storage field where the plaintext configuration value is encrypted on disk and decrypted in memory when the configuration file is loaded.

Parameters

method (str) – encryption method, see _get_provider()

storage_type

alias of str

class cincoconfig.IntField(**kwargs)

Integer field.

storage_type

alias of int

class cincoconfig.FloatField(**kwargs)

Float field.

storage_type

alias of float

class cincoconfig.PortField(**kwargs)

Network port field.

storage_type

alias of int

class cincoconfig.IPv4AddressField(*, min_len=None, max_len=None, regex=None, choices=None, transform_case=None, transform_strip=None, **kwargs)

IPv4 address field.

The string field can perform transformations on the value prior to validating it if either transform_case or transform_strip are specified.

Parameters
  • min_len (Optional[int]) – minimum allowed length

  • max_len (Optional[int]) – maximum allowed length

  • regex (Optional[str]) – regex pattern that the value must match

  • choices (Optional[List[str]]) – list of valid choices

  • transform_case (Optional[str]) – transform the value’s case to either upper or lower case

  • transform_strip (Union[bool, str, None]) – strip the value by calling str.strip(). Setting this to True will call str.strip() without any arguments (ie. striping all whitespace characters) and if this is a str, then str.strip() will be called with transform_strip.

storage_type

alias of str

class cincoconfig.IPv4NetworkField(min_prefix_len=None, max_prefix_len=None, **kwargs)

IPv4 network field. This field accepts CIDR notation networks in the form of A.B.C.D/Z.

Parameters
  • min_prefix_len (Optional[int]) – minimum subnet prefix length (/X), in bits

  • max_prefix_len (Optional[int]) – maximum subnet prefix length (/X), in bits

storage_type

alias of str

class cincoconfig.HostnameField(*, allow_ipv4=True, resolve=False, **kwargs)

A field representing a network hostname or, optionally, a network address.

Parameters
  • allow_ipv4 (bool) – allow both a hostname and an IPv4 address

  • resolve (bool) – resolve hostnames to their IPv4 address and raise a ValueError if the resolution fails

storage_type

alias of str

class cincoconfig.FilenameField(*, exists=None, startdir=None, **kwargs)

A field for representing a filename on disk.

The exists parameter can be set to one of the following values:

  • None - don’t check file’s existence

  • False - validate that the filename does not exist

  • True - validate that the filename does exist

  • "dir" - validate that the filename is a directory that exists

  • "file" - validate that the filename is a file that exists

The startdir parameter, if specified, will resolve filenames starting from a directory and will cause all filenames to be validate to their absolute file path. If not specified, filename’s will be resolve relative to os.getcwd() and the relative file path will be validated.

Parameters
  • exists (Union[bool, str, None]) – validate the filename’s existence on disk

  • startdir (Optional[str]) – resolve relative paths to a start directory

storage_type

alias of str

class cincoconfig.BoolField(*, key=None, schema=None, name=None, required=False, default=None, validator=None, sensitive=False, description=None, help=None, env=None)

A boolean field.

All builtin Fields accept the following keyword parameters.

Parameters
  • name (Optional[str]) – field friendly name, used for error messages and documentation

  • key (Optional[str]) – the key of the field in the config, this is typically not specified and, instead the __setkey__() will be called by the config

  • required (bool) – the field is required and a ValueError will be raised if the value is None

  • default (Union[Callable, Any, None]) – the default value, which can be a called that is invoke with no arguments and should return the default value

  • validator (Optional[Callable[[Config, Any], Any]]) – an additional validator function that is invoked during validation

  • sensitive (bool) – the field stores a sensitive value

  • help (Optional[str]) – the field documentation

FALSE_VALUES = ('f', 'false', '0', 'off', 'no', 'n')

Accepted values that evaluate to False

TRUE_VALUES = ('t', 'true', '1', 'on', 'yes', 'y')

Accepted values that evaluate to True

storage_type

alias of bool

class cincoconfig.FeatureFlagField(*, key=None, schema=None, name=None, required=False, default=None, validator=None, sensitive=False, description=None, help=None, env=None)

Concrete implementation of the feature flag field. When this field’s value is set to False, the bound configurations will not perform validation.

All builtin Fields accept the following keyword parameters.

Parameters
  • name (Optional[str]) – field friendly name, used for error messages and documentation

  • key (Optional[str]) – the key of the field in the config, this is typically not specified and, instead the __setkey__() will be called by the config

  • required (bool) – the field is required and a ValueError will be raised if the value is None

  • default (Union[Callable, Any, None]) – the default value, which can be a called that is invoke with no arguments and should return the default value

  • validator (Optional[Callable[[Config, Any], Any]]) – an additional validator function that is invoked during validation

  • sensitive (bool) – the field stores a sensitive value

  • help (Optional[str]) – the field documentation

class cincoconfig.UrlField(*, min_len=None, max_len=None, regex=None, choices=None, transform_case=None, transform_strip=None, **kwargs)

A URL field. Values are validated that they are both a valid URL and contain a valid scheme.

The string field can perform transformations on the value prior to validating it if either transform_case or transform_strip are specified.

Parameters
  • min_len (Optional[int]) – minimum allowed length

  • max_len (Optional[int]) – maximum allowed length

  • regex (Optional[str]) – regex pattern that the value must match

  • choices (Optional[List[str]]) – list of valid choices

  • transform_case (Optional[str]) – transform the value’s case to either upper or lower case

  • transform_strip (Union[bool, str, None]) – strip the value by calling str.strip(). Setting this to True will call str.strip() without any arguments (ie. striping all whitespace characters) and if this is a str, then str.strip() will be called with transform_strip.

storage_type

alias of str

class cincoconfig.ListField(field=None, **kwargs)

A list field that can optionally validate items against a Field. If a field is specified, a ListProxy will be returned by the _validate method, which handles individual item validation.

Specifying required=True will cause the field validation to validate that the list is not None and is not empty.

Parameters

field (Union[BaseField, Type[ConfigType], None]) – Field to validate values against

to_basic(cfg, value)

Convert to basic type.

Parameters
Return type

list

to_python(cfg, value)

Convert to Pythonic type.

Parameters
  • cfg (Config) – current config

  • value (list) – basic type value

Return type

Union[list, ListProxy]

class cincoconfig.VirtualField(getter, setter=None, **kwargs)

A calculated, readonly field that is not read from or written to a configuration file.

Parameters
  • getter (Callable[[Config], Any]) – a callable that is called whenever the value is retrieved, the callable will receive a single argument: the current Config.

  • setter (Optional[Callable[[Config, Any], Any]]) – a callable that is called whenever the value is set, the callable will receive two arguments: config, value, the current Config and the value being set

class cincoconfig.DictField(key_field=None, value_field=None, **kwargs)

A generic dict field that optionally validates keys and values. The key_field and value_field parameters control whether and how the dictionary keys and values are validated, respectively. Setting these will cause the internal representation to be stored in a DictProxy which handles the validation operations.

Specifying required=True will cause the field validation to validate that the dict is not None and is not empty.

storage_type

alias of dict

to_basic(cfg, value)

Convert to basic type.

Parameters
Return type

dict

to_python(cfg, value)

Convert to Pythonic type.

Parameters
  • cfg (Config) – current config

  • value (dict) – basic type value

Return type

Union[dict, DictProxy]

class cincoconfig.BytesField(encoding='base64', **kwargs)

Store binary data in an encoded string.

Parameters

encoding (str) – binary data encoding, must be one of ENCODINGS

ENCODINGS = ('base64', 'hex')

Available encodings: base64 and hex

storage_type

alias of bytes

to_basic(cfg, value)
Return type

str

Returns

the encoded binary data

to_python(cfg, value)
Return type

Optional[bytes]

Returns

the decoded binary data

class cincoconfig.IncludeField(startdir=None, **kwargs)

A special field that can include another configuration file when loading from disk. Included files are in the same scope as where the include field is defined for example:

# file1.yaml
db:
  include: "db.yaml"
include: "core.yaml"

# db.yaml
host: "0.0.0.0"
port: 27017

# core.yaml
mode: "production"
ssl: true

The final parsed configuration would be equivalent to:

db:
  host: "0.0.0.0"
  port: 27017

mode: "production"
ssl: true

Included files must be in the same configuration file format as their parent file. So, if the base configuration file is stored in JSON then every included file must also be in JSON.

Cincoconfig does not track which configuration file set which field(s). When a config file is saved back to disk, it will be the entire configuration, even if it was originally defined across multiple included files.

Parameters

startdir (Optional[str]) – resolve relative include paths to a start directory

combine_trees(base, child)

An extension to dict.update() but properly handles nested dict objects.

Parameters
  • base (dict) – base tree to extend

  • child (dict) – child tree to apply onto base

Return type

dict

Returns

the new combined dict

include(config, fmt, filename, base)

Include a configuration file and combine it with an already parsed basic value tree. Values defined in the included file will overwrite values in the base tree. Nested trees (dict objects) will be combined using a dict.update() like method, combine_trees().

Parameters
  • config (Config) – configuration object

  • fmt (ConfigFormat) – configuration file format that will parse the included file

  • filename (str) – included file path

  • base (dict) – base config value tree

Return type

dict

Returns

the new basic value tree containing the base tree and the included tree

Secure Fields

The following fields provide secure configuration option storage and challenges.

class cincoconfig.ChallengeField(hash_algorithm='sha256', **kwargs)

A field whose value is securely stored as a hash (DigestValue). This field can be used as a secure method of password storage and comparison, since the password is only stored in hashed form and not in plaintext. A digest value is pair of salt and hash(salt + plaintext) values.

Values are stored in memory as DigestValue instances. For example:

>>> schema = Schema()
>>> schema.password = ChallengeField('md5')
>>> cfg = schema()
>>> cfg.password = "Hello"
>>> print(type(cfg.password))
<class 'cincoconfig.fields.DigestValue'>

>>> print(cfg.password)
Yt4Qm5cC9FoRSdU3Ly7B7A==:+GXXhO36XvJ446fqXYJ+1w==

>>> cfg.password.digest
b'øeׄíú^òxã§ê]‚~×'

The default value of a challenge field can be either:

  • A plaintext string. In this case, the salt will be randomly generated.

  • A DigestValue instance.

When the default value is a string, the salt will change between application executions. For example:

>>> schema = Schema()
>>> schema.password = ChallengeField('md5', default='hello')
>>> cfg = schema()
# First time application executes
>>> print(cfg.password)
Yt4Qm5cC9FoRSdU3Ly7B7A==:+GXXhO36XvJ446fqXYJ+1w==

# Second time application executes
>>> print(cfg.password)
c2MPwSJw1QYMOcE2O+cVFA==:JSNbBj3wCgh7alFM7l0geg==

Digest values are saved to disk as a dict containing two keys:

  • salt - base64 encoded salt

  • digest - base64 encoded digest

The challenge field supports loading plaintext string values from the configuration file. So, when manually writing the config file, the user does not need to create the salt and digest pair but, instead, just specify a plaintext string to hash. The value will be properly saved as a salt/digest pair the next time the config file is saved to disk.

Available hash algorithms are:

  • md5

  • sha1

  • sha224

  • sha256

  • sha384

  • sha512

Parameters

hash_algorithm (str) – hash algorithm to use, must be a key of ALGORITHMS

ALGORITHMS: Dict[str, Callable[[bytes], hashlib._Hash]] = {'md5': <built-in function openssl_md5>, 'sha1': <built-in function openssl_sha1>, 'sha224': <built-in function openssl_sha224>, 'sha256': <built-in function openssl_sha256>, 'sha384': <built-in function openssl_sha384>, 'sha512': <built-in function openssl_sha512>}

Available hashing algorithms

storage_type

alias of DigestValue

to_basic(cfg, value)

Convert to a dict and indicate the type so we know on load whether we’ve already dealt with the field

Parameters
Return type

dict

Returns

encrypted/hashed value

to_python(cfg, value)

Decrypt the value if loading something we’ve already handled. Hash the value if it hasn’t been hashed yet.

Parameters
Return type

DigestValue

Returns

decrypted value or unmodified hash

Raises

ValueError – if the value read from the config is neither a dict nor a string

class cincoconfig.DigestValue(salt, digest, algorithm)

Digest value tuple storing hashed value: (salt, digest, algorithm). The digest is the hash of the concatenated salt and plaintext value (hash(salt + plaintext)).

Create new instance of TDigestValue(salt, digest, algorithm)

challenge(plaintext)

Challenge a plaintext value against the digest value. This will raise a ValueError if the challenge is unsuccessful.

Raises

ValueError – the challenge was unsuccessful

Return type

None

classmethod create(plaintext, algorithm, salt=None)

Hash a plaintext value and return the new digest value. The digest is calculated as:

salt[:digest_size] + plaintext

The salt will be randomly generated if not specified. If the salt is specified and it is larger than the algorithm digest_size, the salt will be truncated to the digest_size.

Parameters
  • plaintext – string to hash

  • algorithm – hashlib algorithm to use

  • salt – hash salt

Returns

the created digest value

classmethod parse(value, algorithm)

Parse a base64-encoded salt/digest pair, as returned by __str__()

class cincoconfig.SecureField(method='best', sensitive=True, **kwargs)

A secure storage field where the plaintext configuration value is encrypted on disk and decrypted in memory when the configuration file is loaded.

Parameters

method (str) – encryption method, see _get_provider()

storage_type

alias of str

Instance Method Field

cincoconfig.instance_method(schema, name)

Bind a function to a schema as an instance method. Use this as a decorator:

schema = Schema()

@instance_method(schema, "say_hello")
def say_hello_method(config: Config) -> str:
    return "Hello, world!"

config = schema()
print(config.say_hello())  # "Hello, world!"
Parameters
  • schema (Schema) – schema

  • name (str) – instance method name

Return type

Callable

Internal Types and Base fields

The following classes are used internally by cincoconfig and should not have to be used or referenced directly in applications. These are not included in the public API and must be imported explicitly from the cincoconfig.fields module.

class cincoconfig.DictProxy(cfg, dict_field, iterable=None)

A Field-validated dict proxy. This proxy supports all methods that the builtin dict supports with the added ability to validate keys and values against a Field. This is the value returned by the DictField validation chain.

property key_field: Field
Returns

the field for each item stored in the list.

property value_field: Field
Returns

the field for each item stored in the list.

class cincoconfig.ListProxy(cfg, list_field, iterable=None)

A Field-validated list proxy. This proxy supports all methods that the builtin list supports with the added ability to validate items against a Field. This is the field returned by the ListField validation chain.

property item_field: Union[BaseField, Type[Config]]
Returns

the field for each item stored in the list.

class cincoconfig.NumberField(type_cls, *, min=None, max=None, **kwargs)

Base class for all number fields. This field should not be used directly, instead consider using IntField or FloatField.

Parameters
  • type_cls (type) – number type class that values will be converted to

  • min (Union[int, float, None]) – minimum value (inclusive)

  • max (Union[int, float, None]) – maximum value (inclusive)