Anyconfig First Look
python-anyconfig is a MIT licensed python library provides common APIs to load and dump configuration files in various formats with some useful features such as contents merge, templates, query, schema validation and generation support.
This notebook demonstrates some features of anyconfig for loading and dumping data. We raise a comparsion to traitlets.config at the end where a backend for python config files is created.
import anyconfig, pydantic, munch, json, toolz
anyconfig can load to multiple formats.
config = anyconfig.loads("""a: 10""", ac_parser='yaml')
config.update(anyconfig.loads("""{"b": 10}""", ac_parser='json'))
anyconfig.loads("""a.q=10""", ac_parser='toml')
{'a': {'q': 10}}
anyconfig allows jinja2 templates.
anyconfig.loads("a: \n", ac_parser='yaml', ac_template=True)
{'a': 'aaa'}
anyconfig.loads("a: \n", ac_parser='yaml', ac_template=True, ac_context={'a': 3})
{'a': 3}
anyconfig can dump to multiple formats.
print(anyconfig.dumps(config, 'json'))
{"a": 10, "b": 10}
print(anyconfig.dumps(config, 'yaml'))
a: 10
b: 10
anyconfig provides jsonschema validation. We’ll use pydantic to generate schema.
class Schema(pydantic.BaseModel): a: int; b: int
valid, _ = anyconfig.validate(config, Schema.schema())
assert Schema and valid
class BadSchema(pydantic.BaseModel): a: int; b: str
valid, errors = anyconfig.validate(config, BadSchema.schema())
assert not valid
print(errors)
10 is not of type 'string'
Failed validating 'type' in schema['properties']['b']:
{'title': 'B', 'type': 'string'}
On instance['b']:
10
In traitlets we could load configurations from python files. Below we add similar functionality to anyconfig for a python backend.
def load(object, **c):
if hasattr(object, 'read'): object = object.read()
c['c'] = c.get('c', munch.Munch())
return exec(object, c, c) or c['c']
class Python(anyconfig.backend.base.StringStreamFnParser):
_cid = "python"
_type = "python"
_extensions = ["python"]
_ordered = True
_load_opts = _dump_opts = _dict_opts = ["_dict"]
_load_from_string_fn = anyconfig.backend.base.to_method(load)
_load_from_stream_fn = anyconfig.backend.base.to_method(load)
_dump_to_string_fn = anyconfig.backend.base.to_method(toolz.compose('c = '.__add__, json.dumps))
_dump_to_stream_fn = anyconfig.backend.base.to_method(json.dump)
Loading a python config.
data = anyconfig.loads("""c.a = list(range(10))""", ac_parser=Python); data
{'a': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
Writing a python config.
anyconfig.dumps(data, ac_parser=Python)
'c = {"a": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}'