Package: lazyConfig
lazyConfiglazily loading and overriding configurationlazyConfig is an opinionated configuration provider. It can load.yml,.yaml,.jsonand.tomlconfiguration files out of the box but can be extended with
custom loaders. Opinionated since it requires you to
structure your configuration in a certain way in order to work.Why lazyConfig?seeMotivationUsageIn order to load your configuration folder into adictlike structure, simply
pointlazyConfigto the folderimportlazyConfigconfig=lazyConfig.from_path(config='/path/to/default/config',override=['/path/to/override','/path/to/another/override/',...])# or with environment variables:os.environ['CONFIG']='/path/to/default/config'os.environ['CONFIG_OVERRIDE']=f'/path/to/override/{os.pathsep}/path/to/another/override/'config=lazyConfig.from_env()You can change the envrionment variable names by passing their names, e.g.lazyConfig.from_env(config='DEFAULT_CONFIG',override='CONFIG')Files are overriden left to right (i.e. the last argument has
priority)you could mix and match usingConfig.from_pathandos.environ['ENV_VAR']Add overrideIf you are using an command line interface parser (e.g. argparse) to generate
a dictionary for overriding configuration, you might want to add an
additional override. You can useconfig.add_override(argparse_results)whereargparse_resultsis of typeMappingusevars()to obtain adictfrom anarparse.Namespacewhich is the
return type of an arparse parserarparse usesNoneto indicate missing configuration. Soadd_overrideignoresNoneby default. If you provide the parameternone_can_override=True, you can
remove configuration withNonevalues.Override RestrictionsYou can only override keys which exist in the default configuration. This
requirement ensures that the default configuration documents all possible
configuration options. Use the valueNonein the default configuration for
settings you do not want to select a default for. You can obtain a dict without
these entries withconfig.as_dict(strip_none=True)strip_none=Trueis the default, set it to false if you want a dict
including allNonevaluesAssumptions about the file structureFilenames are used as keys in theconfigdict, so without any caveats
you would be forced to have a minimum depth of1for any configuration.This might not make sense for some high level, flat configuration. For this
reason there is a special filename__config__(.yml,.yaml,.json,...),
which allows you to define top level keys and values.Exampleconfig
    database
        configuration.yml
        __config__.yml
    app.yml
    __config__.ymlconfig/__config__.yml:name: my-app
author: ME!
version: -1.0app.yml:primary_color: 'blue'
secondary_color: 'green'config/database/__config__.yml:connection:
    hosts:
        - {host: "myElasticsearchServer", port: 9200}
    timeout: 6000config/database/configuration.yml:indices:
    index1: {...}
    index2: {...}
pipelines:
    pipeline1: {...}would be loaded as the following dictionary (formatted inymlfor readability):name: my-app
author: ME!
version: -1.0
app:
    primary_color: 'blue'
    secondary_color: 'green'
database:
    connection:
        hosts:
            - {host: "myElasticsearchServer", port: 9200}
        timeout: 6000
    configuration:
        indices:
            index1: {...}
            index2: {...}
        pipelines:
            pipeline1: {...}Attribute accessYou could then accessindex1with:config.database.configuration.indices.index1Python does not allow attributes to start with a number. Soconfig.1attribute2breakthingswill not work. In these cases you will have to useconfig['1attribute2breakthings']Duplicate KeysDuplicate Keys are not allowed.lazyConfigtries to find keys inKeyfiles (__config__)FilenamesDirectoriesin that order! It will not keep looking whether or not there is a duplicate and
thus ignore a directory if a file with the same name (sans extension) or a key
with the same name in the keyfile exists.There might be a configuration validation function in the future to check for
duplicate keys (in debug mode or on manual call)ListsLists are overriden not extended. If the default configuration has the same key
for a list as an override, then the default list is ignored and the override is
used.Extending Lists would mean that you can not remove elements with a
configuration override. As this is not desirable you will just have to
duplicate lists in its entirety if you want to
change them (even if only slightly)Since numbers are discouraged anyway, you can defineDirectory Listslike this:config
    list
        0.yml
        1.yml
        2.yml
        3.ymlwhich is then converted toconfig:
    list:
        - {content from 0.yml}
        - {content from 1.yml}
        - {content from 2.yml}Directory Listsmuststart with0and end withn-1wherenis the
number of files in the directory.It is currently not possible to create a list of directories (instead of files).
This might become a feature in a future version if requestedSecurityUsingpyYAML.unsafe_load(),lazyConfigis currently not meant for external data.
Pass acustom_extension_loaderto the factory method:lazyConfig.from_path('path/to/config',custom_extension_loader={'.yml':yaml.safe_load,'.yaml':yaml.safe_load})This overrides the yaml loader while leaving the other loaders in place. To remove
a default loader, override the extension with a Falsy value (e.g.None)Future Featuresthings which I might get around to do some time:Configuration ValidationHorizontal override (Templates, e.g. for indices)Configuration SetterSince it is not obvious where to set directory/file boundaries inside the
dictionary, this is not as trivial as it might seem at first. It might be
necessary to provide the grouping level as an argument.generateJSON Schemafrom default configurationVersions0.5 proper none handling0.4 add_overwrite0.3 as_primitive, as_dict, as_list, laziness modes and custom loader, TOML support0.2.2 fix equality0.2.1 fix broken iterator0.2 Config implements Mapping0.1.1 handle NULL environment variables0.1: basic proof of concept