Fileconfig turns config file sections into instances of your class. Create a class referring to an INI file collecting the arguments for the different instances to be created. Calling the class with the section name as parameter will return the instance with the parameters specified in the given section.
- GitHub: https://github.com/xflr6/fileconfig
- PyPI: https://pypi.org/project/fileconfig/
- Issue Tracker: https://github.com/xflr6/fileconfig/issues
- Download: https://pypi.org/project/fileconfig/#files
This package runs under Python 3.8+, use pip to install:
$ pip install fileconfig
Create as subclass of fileconfig.Config
and set its filename
attribute to the path of your INI file.
If the filename is relative, it is resolved relative to the path of the module where your class is defined (i.e. not relative to the current working directory if its file not happens do be there).
>>> import fileconfig
>>> class Cfg(fileconfig.Config):
... filename = 'docs/pet-shop.ini'
... def __init__(self, key, **kwargs):
... self.key = key
... self.__dict__.update(kwargs)
On instance creation, the __init__
method will be called with the section name (key
) and the keyword parameters from the given section of the specified file.
Suppose your INI file begins like this:
[parrot]
species = Norwegian blue
can_talk = yes
quantity = 0
characteristics = beautiful plumage, pining for the fjords
To retrieve this instance, call the class with its section name.
>>> c = Cfg('parrot')
>>> print(c)
{
'can_talk': 'yes',
'characteristics': 'beautiful plumage, pining for the fjords',
'key': 'parrot',
'quantity': '0',
'species': 'Norwegian blue'
}
Only one instance will be created, cached and returned for each config file section (a.k.a. the singleton pattern):
>>> Cfg('parrot') is c
True
The constructor is also idempotent:
>>> Cfg(c) is c
True
The default __repr__
of instances allows round-trips:
>>> c
__main__.Cfg('parrot')
You can specify a space-delimited list of aliases
for each section:
[slug]
aliases = snail special_offer
species = slug
can_talk = no
quantity = 1
For changing the delimiter, see below.
Aliases map to the same instance:
>>> s = Cfg('special_offer')
>>> s
__main__.Cfg('slug')
>>> s is Cfg('snail') is Cfg('slug')
True
Inspect instance names
(key + aliases):
>>> s.key
'slug'
>>> s.aliases
['snail', 'special_offer']
>>> s.names
['slug', 'snail', 'special_offer']
Config file sections can inherit from another section:
[Polly]
inherits = parrot
can_talk = no
characteristics = dead, totally stiff, ceased to exist
Specified keys override inherited ones:
>>> print(Cfg('Polly'))
{
'can_talk': 'no',
'characteristics': 'dead, totally stiff, ceased to exist',
'inherits': 'parrot',
'key': 'Polly',
'quantity': '0',
'species': 'Norwegian blue'
}
Sections can inherit from a single section. Multiple or transitive inheritance is not supported.
Use the class to iterate over the instances from all section:
>>> list(Cfg)
[__main__.Cfg('parrot'), __main__.Cfg('slug'), __main__.Cfg('Polly')]
Print the string representation of all instances:
>>> Cfg.pprint_all() # doctest: +ELLIPSIS
{
'can_talk': 'yes',
'characteristics': 'beautiful plumage, pining for the fjords',
'key': 'parrot',
...
Apart from the key
, aliases
, and inherits
parameters, your __init__
method receives the unprocessed strings from the config file parser.
Use the __init__
method to process the other parameters to fit your needs.
>>> class Pet(Cfg):
... def __init__(self, can_talk, quantity, characteristics=None, **kwargs):
... self.can_talk = {'yes':True, 'no': False}[can_talk]
... self.quantity = int(quantity)
... if characteristics is not None and characteristics.strip():
... self.characteristics = [c.strip() for c in characteristics.split(',')]
... super().__init__(**kwargs)
>>> print(Pet('Polly'))
{
'can_talk': False,
'characteristics': ['dead', 'totally stiff', 'ceased to exist'],
'inherits': 'parrot',
'key': 'Polly',
'quantity': 0,
'species': 'Norwegian blue'
}
This way, the __init__
method also defines parameters as required or optional, set their defaults, etc.
Sometimes one wants to combine multiple config files, e.g. have a default file included in the package directory, overridden by a user-supplied file in a different location.
To support this, subclass fileconfig.Stacked
and set the filename
to the location of the default config.
>>> class Settings(fileconfig.Stacked):
... filename = 'docs/pet-shop.ini'
Use the add
method to load an overriding config file on top of that:
>>> Settings.add('docs/lumberjack.ini')
If the filename is relative, it is resolved relative to the path of the module where the add
method has been called.
You can access the sections from all files:
>>> print(Settings('Bevis'))
{
'can_talk': 'yes',
'characteristics': "sleeps all night, works all day, puts on women's clothing",
'key': 'Bevis',
'species': 'human'
}
As long as they have different names:
>>> print(Settings('Polly'))
{
'can_talk': 'no',
'characteristics': 'dead, totally stiff, ceased to exist',
'inherits': 'parrot',
'key': 'Polly',
'quantity': '0',
'species': 'Norwegian blue'
}
Config files added to the top of the stack mask sections with the same names from previous files:
>>> print(Settings('parrot'))
{
'characteristics': 'unsolved problem',
'key': 'parrot'
}
To use a different delimiter for aliases
override the _split_aliases
method on your class. Make it a staticmethod
or classmethod
that takes a string argument and returns the splitted list.
By default, fileconfig will use ConfigParser.SafeConfigParser
from the standard library to parse the config file. To use a different parser, override the _parser
attribute in your fileconfig.Config
subclass.
To specify the encoding from which the config file should be decoded by the config parser, override the _encoding
attribute on your subclass.
Fileconfig raises an error, if the config file is not found. If you want this error to pass silently instead, set the _pass_notfound
attribute on your subclass to True
.
This package uses sys._getframe
(which is almost the same as inspect.currentframe
, see docs). Under IronPython this might require enabling the FullFrames
option of the interpreter.
Fileconfig is distributed under the MIT license.