Advanced Features
#
Command Line InputAnyfig offers the functionality to override config-values through command line arguments. Anyfig will throw an error if the user inputs a key that doesn't exist making it possible to override argument, not to define new ones. By not allowing new keys, Anyfig protects against misspellings that can result in silent errors.
#
Argument TypesGoogle's Fire project is used to parse command line arguments' types and validity. It support any Python literals (numbers, strings, tuples, lists, dictionaries, sets). Read more about how Fire handles parsing.
A problem arises when one wants to override a non-literal, like a Pathlib Path, from the command line. Anyfig solves this by parsing the input to a Python literal and use that to create a new object from the class definition of the old value.
#
Command Line HelpHelp for the config-options are exposed to the command line when the user inputs the --help flag.
#
Multiple Config ClassesSometimes it's useful to have multiple config-classes. Perhaps one config for every main script or one config for normal use and one for debugging. The ability to create multiple config-classes is very powerful and essential to Anyfig.
One can choose which config-class to use via the command line. If a config-class is not supplied, it will default to the config-class given in the anyfig.init_config function.
#
InheritanceWhat's the object oriented way to become wealthy?
💰 InheritanceFor situations where multiple config-classes are similar to one another it often makes sense to use inheritance to avoid code duplication.
#
Modular ConfigsFor projects where the configuration grows large it helps to modularize the config-values. Anyfig allows for nested config-classes to reduce code duplication and increase code readability.
#
Constraining Config-ValuesTo avoid unintended behaviours its good practice to validate the config. This can be done by checking that the config-values are the correct types and within a subset of allowed values.
#
TypesAnyfig assures that a config-value will have the correct type if it's declared via the anyfig.field
function.
The field serves as an interface that defines the allowed type for that particular config-value.
That config-value is required to be overridden which allows the developer to e.g. enforce that certain config-values are supplied through the command line input.
More complex types are supported through Python's typing module. This makes it possible to specify that a config-value should be a list of ints, written as typing.List[int]
or any other schema supported by the typeguard package that performs the type checking.
#
ValuesValidating the type for config-values is a great start but can't protect against unallowed values of that type. For example, if a config-value controls the age of a person, a negative number could pass the type test whilst still being nonsensical.
By allowing developers to define their own tests for the config-values within Anyfig, config-errors are caught in the setup phase with a clear error message instead of creating bugs downsteam.
It also clearly communicates the allowed values in contrast to a json config-file where one has to also read any validation code to understand which options are allowed.
#
ConstantsIt's possible to mark attributes as constants to avoid that they are overridden in a subclass or from command line input. Anyfig handles constants as a special case of anyfig.field(tests=mytest)
where the mytest compares object equality via ==
or the is
operator.
#
Target ClassesConfig-classes also support configuring objects with dependencies that are not available at config initialization. Connect the config-class to any callable via the "target" argument.