Package: config-file
Config FileSimple manipulation of ini, json, yaml, or toml filesAbout Config FileThe Config File project is designed to allow you to easily manipulate your
configuration files with the same simple API whether they are in INI, JSON,
YAML, or TOML.InstallationConfig File is available to download through PyPI.$pipinstallconfig-fileInstalling ExtrasIf you want to manipulate YAML and TOML, you'll want to download the extras as well.$pipinstallconfig-file[yaml,toml]You can also usePoetry.$poetryinstallconfig-file-Eyaml-EtomlUsageFor this overview, let's say you have the followinginifile
you want to manipulate.Do note, however, that theiniformat is the oddest format thatConfigFilesupports in that it has no formal specification and is
not type aware. When retrieving items from the file, it will return
them as strings by default. Others are more type aware and do not
require as much type coercion.[section]num_key=5str_key=blahbool_key=truelist_key=[1, 2][second_section]dict_key={ "another_num": 5 }It must have a.iniextension in order
for the package to recognize it and use the correct parser for it.Setting up ConfigFileTo use the package, we import in theConfigFileobject. This object
is the only thing considered to be part of the public API.We can set it up by giving it a string orpathlib.Pathas the argument.
Any home tildes~in the string orPathare recognized and converted
to the full path for us.fromconfig_fileimportConfigFileconfig=ConfigFile("~/some-project/config.ini")Handling ConfigFile Initialization Errorsfromconfig_fileimportConfigFile,ParsingErrortry:config=ConfigFile("~/some-file.ini")exceptParsingError:print("could not parse the file")exceptValueError:print("extension that isn't supported was used or is a directory")exceptFileNotFoundError:print("file does not exist")Usingget()A recurring pattern you'll see here is that all methods that
need to specify something inside your configuration file will
do so using a dot syntax.Retrieving keys and sectionsSo to retrieve ournum_key, we'd specify the heading and the
key separated by a dot. All values will then be retrieved as
strings.config.get('section.num_key')>>>'5'While we can retrieves keys, we can also retrieve the entire
section, which will be returned back to us as a dictionary.config.get('section')>>>{'num_key':'5','str_key':'blah','bool_key':'true','list_key':'[1, 2]'}Furthermore, you can also index into theConfigFileobject
to retrieve keys if that is preferred.config['section']['num_key']>>>'5'Coercing the return typesHowever, some of these keys are obviously not strings natively.
If we are retrieving a particular value of a key, we may want to
coerce it right away without doing clunky type conversions after
each time we retrieve a value. To do this, we can utilize thereturn_typekeyword argument.config.get('section.num_key',return_type=int)>>>5Sometimes we don't have structures quite that simple though. What
if we wanted all the values insectioncoerced? For that, we can
utilize aparse_typeskeyword argument.config.get('section',parse_types=True)>>>{'num_key':5,'str_key':'blah','bool_key':True,'list_key':[1,2]}It also works for regular keys.config.get('section.num_key',parse_types=True)>>>5Handling non-existent keysSometimes we want to retrieve a key but are unsure of if it will exist.
There are two ways we could handle that.The first is the one we're used to seeing: catch the error.try:important_value=config.get('section.i_do_not_exist')exceptKeyError:important_value=42However, thegetmethod comes with adefaultkeyword argument that we
can utilze for this purpose.config.get('section.i_do_not_exist',default=42)>>>42This can be handy if you have a default for a particular configuration value.Usingset()We can useset()to set a existing key's value.config.set('section.num_key',6)The method does not return anything, since there is nothing
useful to return. If something goes wrong where it is unable to set
the value, an exception will be raised instead. This is the case
for most methods onConfigFile, such asdelete()orsave(),
where there would be no useful return value to utilize.Withset(), we can also create and set keys that don't exist yet.config.set('new_section.new_key','New key value!')Would then result in the following section being added to our original file:[new_section]new_key=New key value!The exact behavior of how these new keys or sections are added are a bit
dependent on the file format we're using, since every format is a little
different in it's structure and in what it supports. Mostly though,iniis just the odd one.If we try the following inini, which does not support subsections or
nested keys, we simply get a single section.config.set("section.sub_section.sub_sub_section.key",5)[section.sub_section.sub_sub_section]key=5Lastly, we can set values using an array notation as well. The underlying
content is all manipulated as a dictionary for every file type. If we wanted
to create a new section, we'd simply set it to be an empty dictionary.config['new_section']={}Which would result to be an empty section:[new_section]Usingdelete()delete()allows us to delete entire sections or specific keys.config.delete('section')Would result in the entire section being removed from our configuration file.
However, we can also just delete a single key.config.delete('section.num_key')We can also use the array notation here as well.delconfig['section']['num_key']Usinghas()has()allows us to check whether a given key exists in our file. There
are two ways to usehas().The first is using the dot syntax.config.has('section.str_key')>>>Trueconfig.has('does_not_exist')>>>FalseThis will check if our specific key or section exists. However, we can
also check in general if a given key or sections exists anywhere in our
file with thewildkeyword argument.config.has('str_key',wild=True)>>>TrueUsingsave()For any changes we make to our configuration file, they are not written out
to the filesystem until we callsave(). This is to avoid unnecessary write
calls after each operation until we actually need to save.config.delete('section.list_key')config.save()Stringifying our ConfigFileTo retrieve the file as a string, with any changes we've made, we can use the
built-instr()method on the ConfigFile. This will always show us our latest changes since it is stringify-ing our internal representation of the configuration file, not just the file we've read in.str(config)>>>'[section]\nnum_key = 5\nstr_key = blah\nbool_key = true\nlist_key = [1, 2]\n\n[second_section]\ndict_key = { "another_num": 5 }\n\n'Usingrestore_original()If we have a initial configuration file state, we could keep a copy of that
initial file and restore back to it whenever needed usingrestore_original().By default, if we created ourConfigFileobject with the path of~/some-project/config.ini,restore_original()will look for our original file at~/some-project/config.original.ini.config.restore_original()However, if we have a specific path elsewhere that this original configuration file is or it
is named differently than what the default expects, we can utilize theoriginal_pathkeyword argument.config.restore_original(original_path="~/some-project/original-configs/config.ini")Format Versions SupportedFormatSpecification version supportedININo official specification.JSONRFC 7159YAMLv1.2TOMLv1.0.0-rc.1Foriniandjson, Python's standard library modules are used.
Regardingini, there is no formal specification so the syntax that configparser
supports is what is supported here.LicenseTheMITLicense.