Glorpen Config

https://travis-ci.org/glorpen/glorpen-config.svg?branch=master https://readthedocs.org/projects/glorpen-config/badge/?version=latest

Config framework for Your projects - with validation, interpolation and value normalization!

Features

You can:

  • create custom fields for custom data
  • define configuration schema inside Python app
  • convert configuration values to Python objects
  • validate configuration
  • use interpolation to fill config values
  • set default values

Loading data

glorpen.config.Config uses glorpen.config.loaders to allow loading data from different sources.

Loaders should accept:

  • path, filepath constructor argument
  • file-like object, fileobj constructor argument

Additionally you can just pass dict data to config with glorpen.config.Config.load_data() or glorpen.config.Config.finalize().

Interpolation

You can reuse values from config with {{ path.to.value }} notation, eg:

project:
   path: "/tmp"
   cache_path: "{{ project.path }}/cache"

String interpolation currently can be used only with glorpen.config.fields.String fields.

Normalization and validation

Each field type has own normalization rules, eg. for glorpen.config.fields.log.LogLevel:

logging: DEBUG

config.get("logging") would yield value 10 as is logging.DEBUG.

Additionally it will raise glorpen.config.exceptions.ValidationError if invalid level name is given.

Default values

Each field can have default value. If no value is given in config but default one is set, it will be used instead.

Default values adhere to same interpolation and normalization rules - each default value is denormalized and then passed to normalizers. That way complex object can still profit from config interpolation. There should not be any real impact on performance as it is done only once.

Contents

Example usage

Using fields

Your first step should be defining configuration schema:

import logging
import glorpen.config.fields.simple as f
from glorpen.config.fields.log import LogLevel

project_path = "/tmp/project"

spec = f.Dict({
  "project_path": f.Path(default=project_path),
  "project_cache_path": f.Path(default="{{ project_path }}/cache"),
  "logging": fl.LogLevel(default=logging.INFO),
  "database": f.String(),
  "sources": f.Dict({
      "some_param": f.String(),
      "some_path": f.Path(),
  }),
  "maybe_string": f.Variant([
      f.String(),
      f.Number()
  ])
})

Example yaml config:

logging: "DEBUG"
database: "mysql://...."
sources:
  some_param: "some param"
  some_path: "/tmp"
maybe_string: 12

Then you can create glorpen.config.Config instance:

from glorpen.config import Config
import glorpen.config.loaders as loaders

loader = loaders.YamlLoader(filepath=config_path)
cfg = Config(loader=loader, spec=spec).finalize()

cfg.get("sources.some_param") #=> 'some param'
cfg.get("project_path") #=> '/tmp/project'
cfg.get("project_cache_path") #=> '/tmp/project/cache'
cfg.get("logging") #=> 10
cfg.get("maybe_string") #=> 12

Creating custom fields

Custom field class should extend glorpen.config.fields.base.Field or glorpen.config.fields.base.FieldWithDefault.

glorpen.config.fields.base.Field.make_resolvable() method should register normalizer functions which later will be called in registration order. Each value returned by normalizer is passed to next one. After chain end value is returned as config value.

Returned glorpen.config.fields.base.ResolvableObject instance is resolved before passing it to next normalizer.

If value passed to normalizator is invalid it should raise glorpen.config.exceptions.ValidationError. Sometimes value can be lazy loaded - it is represented as glorpen.config.fields.base.ResolvableObject. You can get real value by using glorpen.config.fields.base.resolve().

class MyValue(object):
   def __init__(self, value):
      super(MyValue, self).__init__()
      self.value = value

class MyField(Field):

    def to_my_value(self, value, config):
        return MyValue(value)

    def is_value_supported(self, value):
        return True

    def make_resolvable(self, r):
        r.on_resolve(self.to_my_value)

The last thing is to use prepared custom field in configuration spec.

glorpen.config API Documentation

glorpen.config

glorpen.config.__version__

Current package version.

class glorpen.config.Config(spec, loader=None, split_character='.')[source]

Config validator and normalizer.

finalize(data=None)[source]

Load and resolve configuration in one go.

If data argument is given loader specified in constructor will not be used.

get(p)[source]

Gets value from config. To get value under some_key use dotted notation: some_key.value (defaults).

load_data(data)[source]

Loads given data as source.

resolve()[source]

Visits all values and converts them to normalized form.

glorpen.config.fields.base

class glorpen.config.fields.base.Field[source]

Single field in configuration file.

Custom fields should register own resolvers/validators/normalizers by extending make_resolvable().

For handling registered callbacks, see ResolvableObject.

is_value_supported(value)[source]

Checks if provided value is supported by this field

make_resolvable(r)[source]

Used to register normalizes in current ResolvableObject.

resolve(v, checked=False)[source]

Wraps value in ResolvableObject optionally checking whether provided value is supported.

class glorpen.config.fields.base.FieldWithDefault(default=<class glorpen.config.fields.base._UnsetValue>, allow_blank=False)[source]

Base class for nullable fields with defaults.

class glorpen.config.fields.base.ResolvableObject(o)[source]

Configuration value ready to be resolved.

Callbacks are registered by calling on_resolve.

To each callback are passed:

  • currently handled value
  • Config instance

By using Config instance you can realize value based on any other value in configuration.

If value is invalid, callback should raise ValidationError with appropriate error message.

on_resolve(f)[source]

Registers given callback to run when resolving values. Passed function should accept following arguments:

resolve(config)[source]

Resolves value with given config

glorpen.config.fields.base.path_validation_error(*args, **kwds)[source]

Adds given path to validation error to make exceptions easy to read

glorpen.config.fields.base.resolve(obj, config)[source]

Returns real object value (resolved) if applicable

glorpen.config.fields.simple

class glorpen.config.fields.simple.Any(default=<class glorpen.config.fields.base._UnsetValue>, allow_blank=False)[source]

Field that accepts any value.

class glorpen.config.fields.simple.Dict(schema=None, keys=None, values=None, **kwargs)[source]

Converts values to collections.OrderedDict

Supports setting whole schema (specific keys and specific values) or just keys type and values type.

Dict values are lazy resolved.

__init__(schema=None, keys=None, values=None, **kwargs)[source]

To set specific schema pass dict to schema argument: {"param1": SomeField()}.

To specify keys and values type use keys and values arguments: Dict(keys=String(), values=Number()).

class glorpen.config.fields.simple.List(schema, **kwargs)[source]

Converts value to list.

List values are lazy resolved.

class glorpen.config.fields.simple.Number(default=<class glorpen.config.fields.base._UnsetValue>, allow_blank=False)[source]

Converts value to numbers.

class glorpen.config.fields.simple.Path(default=<class glorpen.config.fields.base._UnsetValue>, allow_blank=False)[source]

Converts given value to disk path.

class glorpen.config.fields.simple.PathObj(default=<class glorpen.config.fields.base._UnsetValue>, allow_blank=False)[source]

Converts value to pathlib.Path object

class glorpen.config.fields.simple.String(default=<class glorpen.config.fields.base._UnsetValue>, allow_blank=False)[source]

Converts value to string with optional interpolation.

class glorpen.config.fields.simple.Variant(schema, try_resolving=False)[source]

Converts value to normalized state using one Field chosen from multiple provided.

To allow blank values you have to pass child field with enabled blank values. First field which supports value (Field.is_value_supported()) will be used to convert it.

When try_resolving mode is disabled (default), value for child fields will only be checked with is_value_supported, so resulting field will be based only of data type, not value.

When enabled, in addition to checking for supported values data will be resolved and first non error result used.

glorpen.config.fields.log

class glorpen.config.fields.log.LogLevel(default=<class glorpen.config.fields.base._UnsetValue>, allow_blank=False)[source]

Converts log level name to internal number for use with logging

glorpen.config.fields.version

glorpen.config.loaders

class glorpen.config.loaders.BaseLoader(filepath=None, fileobj=None)[source]

Base class for any loader.

_parse(data)[source]

Extending classes should overwrite this method with parsing logic.

_setup()[source]

Extending classes can use it to setup loader.

load()[source]

Reads source specified in constructor.

class glorpen.config.loaders.YamlLoader(filepath=None, fileobj=None)[source]

Reads yaml files.

glorpen.config.exceptions

exception glorpen.config.exceptions.CircularDependency(*args, **kwargs)[source]

Thrown when interpolation causes loop.

exception glorpen.config.exceptions.ConfigException[source]

Base exception for config errors.

exception glorpen.config.exceptions.PathValidationError(validation_error)[source]

Exception for improved readability - uses ValidationError to provide full path to field with error.

exception glorpen.config.exceptions.ValidationError(message, *args)[source]

Exception for when there is error in validation of values in fields.

Indices and tables