python-anyconfig [1] is a 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.


python-anyconfig provides very simple and unified APIs to process configuration files in various formats and related functions:

  • Loading configuration files:

    anyconfig.load (path_specs, ac_parser=None, ac_dict=None, ac_template=False, ac_context=None, **options)

    loads configuration data from path_specs. path_specs may be a list of file paths, files or file-like objects, ~pathlib.Path class object, a namedtuple ~anyconfig.globals.IOInfo objects represents some inputs to load data from, and return a dict or dict like object, or a primitive types’ data other than dict represents loaded configuration.

    anyconfig.loads (content, ac_parser=None, ac_dict=None, ac_template=False, ac_context=None, **options)

    loads configuration data from a string just like json.loads does.

  • Dumping configuration files:

    anyconfig.dump (data, out, ac_parser=None, **options)

    dumps a configuration data data in given format to the output out, may be a file, file like object.

    anyconfig.dumps (data, ac_parser=None, **options)

    dumps a configuration data loaded from a string

  • Open configuration files: (path, mode=None, ac_parser=None, **options)

    open configuration files with suitable flags and return file/file-like objects, and this object can be passed to the anyconfig.load().

  • Merge dicts:

    anyconfig.merge (self, other, ac_merge=MS_DICTS, **options)

    Update (merge) a mapping object ‘self’ with other mapping object ‘other’ or an iterable ‘other’ yields (key, value) tuples according to merge strategy ‘ac_merge’.

  • Schema validation and generation of configuration files:

    anyconfig.validate (data, schema, ac_schema_safe=True, ac_schema_errors=False, **options)

    validates configuration data loaded with anyconfig.load() with JSON schema [2] object also loaded with anyconfig.load(). anyconfig.load() may help loading JSON schema file[s] in any formats anyconfig supports.

    anyconfig.gen_schema (data, **options)

    generates a mapping object represents a minimum JSON schema to validate configuration data later. This result object can be serialized to any formats including JSON with anyconfig.dump or anyconfig.dumps.

It enables to load configuration file[s] in various formats in the same manner, and in some cases, even there is no need to take care of the actual format of configuration file[s] like the followings:

import anyconfig

# Config type (format) is automatically detected by filename (file
# extension) in some cases.
conf1 = anyconfig.load("/path/to/foo/conf.d/a.yml")

# Similar to the above but the input is pathlib.Path object.
import pathlib
path_1 = pathlib.Path("/path/to/foo/conf.d/a.yml")
conf1_1 = anyconfig.load(path_1)

# Similar to the first one but load from file object opened:
with"/path/to/foo/conf.d/a.yml") as fileobj:
    conf1_2 = anyconfig.load(fileobj)

# Loaded config data is a mapping object, for example:
#   conf1["a"] => 1
#   conf1["b"]["b1"] => "xyz"
#   conf1["c"]["c1"]["c13"] => [1, 2, 3]

# Or you can specify the format (config type) explicitly if its automatic
# detection may not work.
conf2 = anyconfig.load("/path/to/foo/conf.d/b.conf", ac_parser="yaml")

# Likewise.
with"/path/to/foo/conf.d/b.conf") as fileobj:
    conf2_2 = anyconfig.load(fileobj, ac_parser="yaml")

# Specify multiple config files by the list of paths. Configurations of each
# files will be merged.
conf3 = anyconfig.load(["/etc/foo.d/a.json", "/etc/foo.d/b.json"])

# Similar to the above but all or one of config file[s] might be missing.
conf4 = anyconfig.load(["/etc/foo.d/a.json", "/etc/foo.d/b.json"],

# Specify config files by glob path pattern:
conf5 = anyconfig.load("/etc/foo.d/*.json")

# Similar to the above, but parameters in the former config file will be simply
# overwritten by the later ones instead of merge:
conf6 = anyconfig.load("/etc/foo.d/*.json", ac_merge=anyconfig.MS_REPLACE)

Also, it can process configuration files which are jinja2-based template files:

  • Enables to load a substantial configuration rendered from half-baked configuration template files with given context

  • Enables to load a series of configuration files indirectly ‘include’-d from a/some configuration file[s] with using jinja2’s ‘include’ directive.

In [1]: import anyconfig

In [2]: open("/tmp/a.yml", 'w').write("a: {{ a|default('aaa') }}\n")

In [3]: anyconfig.load("/tmp/a.yml", ac_template=True)
Out[3]: {'a': 'aaa'}

In [4]: anyconfig.load("/tmp/a.yml", ac_template=True, ac_context=dict(a='bbb'))
Out[4]: {'a': 'bbb'}

In [5]: open("/tmp/b.yml", 'w').write("{% include 'a.yml' %}\n")  # 'include'

In [6]: anyconfig.load("/tmp/b.yml", ac_template=True, ac_context=dict(a='ccc'))
Out[6]: {'a': 'ccc'}

And python-anyconfig enables to validate configuration files in various formats with using JSON schema like the followings:

# Validate a JSON config file (conf.json) with JSON schema (schema.yaml).
# If validation succeeds, `rc` -> True, `err` -> ''.
conf1 = anyconfig.load("/path/to/conf.json")
schema1 = anyconfig.load("/path/to/schema.yaml")
(rc, err) = anyconfig.validate(conf1, schema1)  # err is empty if success, rc == 0

# Validate a config file (conf.yml) with JSON schema (schema.yml) while
# loading the config file.
conf2 = anyconfig.load("/a/b/c/conf.yml", ac_schema="/c/d/e/schema.yml")

# Validate config loaded from multiple config files with JSON schema
# (schema.json) while loading them.
conf3 = anyconfig.load("conf.d/*.yml", ac_schema="/c/d/e/schema.json")

# Generate jsonschema object from config files loaded and get string
# representation.
conf4 = anyconfig.load("conf.d/*.yml")
scm4 = anyconfig.gen_schema(conf4)
scm4_s = anyconfig.dumps(scm4, "json")

And you can query loaded data with JMESPath [3] expressions:

In [2]: dic = dict(a=dict(b=[dict(c="C", d=0)]))

In [3]: anyconfig.loads(anyconfig.dumps(dic, ac_parser="json"),
   ...:                 ac_parser="json", ac_query="a.b[0].c")
Out[3]: u'C'

In [4]:

And in the last place, python-anyconfig provides a CLI tool called anyconfig_cli to process configuration files and:

  • Convert a/multiple configuration file[s] to another configuration files in different format

  • Get configuration value in a/multiple configuration file[s]

  • Validate configuration file[s] with JSON schema

  • Generate minimum JSON schema file to validate given configuration file[s]

Supported configuration formats

python-anyconfig supports various file formats if requirements are satisfied and backends in charge are enabled and ready to use:

  • Always supported formats of which backends are enabled by default:

Always supported formats






json (standard lib) or simplejson [4]



configparser (standard lib)



pickle (standard lib)



ElementTree (standard lib)

Java properties [5]


None (native implementation with standard lib)



None (native implementation with standard lib)



None (native implementation)

  • Supported formats of which backends are enabled automatically if requirements are satisfied:

Supported formats if requirements are satisfied






ruamel.yaml [6] or PyYAML [7]



toml [8]

  • Supported formats of which backends are enabled automatically if required plugin modules are installed: python-anyconfig utilizes plugin mechanism provided by setuptools [9] and may support other formats if corresponding plugin backend modules are installed along with python-anyconfig:

Supported formats by pluggable backend modules



Required backend

Amazon Ion


anyconfig-ion-backend [10]



anyconfig-bson-backend [11]



anyconfig-cbor-backend [12] or anyconfig-cbor2-backend [13]



anyconfig-configobj-backend [14]



anyconfig-msgpack-backend [15]

The supported formats of python-anyconfig on your system are able to be listed by ‘anyconfig_cli -L’ like this:

$ anyconfig_cli -L
Supported config types: bson, configobj, ini, json, msgpack, toml, xml, yaml

or with the API ‘anyconfig.list_types()’ will show them:

In [8]: anyconfig.list_types()
Out[8]: ['bson', 'configobj', 'ini', 'json', 'msgpack', 'toml', 'xml', 'yaml']

In [9]:



Many runtime dependencies are resolved dynamically and python-anyconfig just disables specific features if required dependencies are not satisfied. Therefore, only python standard library is required to install and use python-anyconfig at minimum.

The following packages need to be installed along with python-anyconfig to enable the features.




YAML load/dump

ruamel.yaml or PyYAML

ruamel.yaml will be used instead of PyYAML if it’s available to support the YAML 1.2 specification.

TOML load/dump

toml [16] or tomllib [17] and tomli-w [18] or tomli [19] and tomli-w or tomlkit [20]

tomllib is in the standard lib since python 3.11.0

BSON load/dump


bson from pymongo package may work and bson [21] does not

Template config

Jinja2 [22]


Validation with JSON schema

jsonschema [23]

Not required to generate JSON schema.

Query with JMESPath expression

jmespath [24]


How to install

There is a couple of ways to install python-anyconfig:

  • Binary RPMs:

    If you’re running Fedora 27 or later, or CentOS, you can install RPMs from these official yum repos. And if you’re running Red Hat Enterprise Linux 7 or later, you can install RPMs from EPEL repos [25] .

    Or if you want to install the latest version, optionally, you can enable my copr repo, .

  • PyPI: You can install python-anyconfig from PyPI with using pip:

    $ pip install anyconfig
  • pip from git repo:

    $ pip install git+
  • Build RPMs from source: It’s easy to build python-anyconfig with using rpm-build and mock:

    # Build Source RPM first and then build it with using mock (better way)
    $ python bdist_rpm --source-only && mock dist/python-anyconfig-<ver_dist>.src.rpm


    # Build Binary RPM to install
    $ python bdist_rpm

    and install RPMs built.

  • Build from source: Of course you can build and/or install python modules in usual way such like ‘python bdist’.

Help and feedbak

If you have any issues / feature request / bug reports with python-anyconfig, please open issue tickets on,

The following areas are still insufficient, I think.

  • Make python-anyconfig robust for invalid inputs

  • Make python-anyconfig scalable: some functions are limited by max recursion depth.

  • Make python-anyconfig run faster: current implementation might be too complex and it run slower than expected as a result.

  • Documentation:

    • Especially API docs need more fixes and enhancements! CLI doc is non-fulfilling also.

    • English is not my native lang and there may be many wrong and hard-to-understand expressions.

Any feedbacks, helps, suggestions are welcome! Please open github issues for these kind of problems also!


How to test

Run ‘[WITH_COVERAGE=1] ./pkg/ [path_to_python_code]’ or ‘tox’ for tests.

About test-time requirements, please take a look at pkg/test_requirements.txt.

How to write backend plugin modules

Backend class must inherit anyconfig.backend.base.Parser or its children in anyconfig.backend.base module and need some members and methods such as load_from_string(), load_from_path(), load_from_stream(), dump_to_string(), dump_to_path() and dump_to_stream(). And anyconfig.backend.tests.ini.Test10 and anyconfig.backend.tests.ini.Test20 may help to write test cases of these methods.

JSON and YAML backend modules (anyconfig.backend.{json,yaml}_) should be good examples to write backend modules and its test cases, I think.

Also, please take a look at some example backend plugin modules mentioned in the Supported configuration formats section.

How to test backend modules

Basically, you only need to do the followings to test loaders.

  • Arrange test data (input file, expected output and option file) under tests/res/1/loaders/<parser’s cid>/[0-9]{2}/

    • Arange input file of the file type parser expects as inputs:

      • example #1. tests/res/1/loaders/json.stdlib/10/360_a_nested_map.json (json)

      • example #2. tests/res/1/loaders/sh.variables/10/

    • Arange expected output files as python code (.py) or json (.json) data with name, <input_filename>.<extension>

      • example #1. tests/res/1/loaders/json.stdlib/10/e/

      • example #2. tests/res/1/loaders/sh.variables/10/e/

    • Optionaly, arrange data file contains options given to paser.load{,s} functions

      • tests/res/1/loaders/json.stdlib/20/o/360_a_nested_map.json.json

  • Arrange test code as tests/backend/loader/<ype>/<laoder_filename> by either way of the followings

    • Make a symlink to tests/backend/loaders/json/ if any modifications are not needed

      • example: tests/backend/loaders/xml/

    • Copy tests/backend/loaders/json/ and modify as you need

      • example: tests/backend/loaders/toml/

See also the actual examples under tests/backend/ and tests/res/1/loaders/

And for dumers, do same thing as doing for loaders.