Creating a class with all the elements specified in a file using ConfigParser

生来就可爱ヽ(ⅴ<●) 提交于 2019-11-28 08:50:57
pillmuncher

What J.F. Sebastian said.

Also, you could do it like Alex Martelli does in his Bunch class:

file MyConfig.py:

from ConfigParser import SafeConfigParser


section_names = 'official', 'debugging'


class MyConfiguration(object):

    def __init__(self, *file_names):
        parser = SafeConfigParser()
        parser.optionxform = str  # make option names case sensitive
        found = parser.read(file_names)
        if not found:
            raise ValueError('No config file found!')
        for name in section_names:
            self.__dict__.update(parser.items(name))  # <-- here the magic happens


config = MyConfiguration('my.cfg', 'other.cfg')

file foo.py:

from MyConfig import config
# ...

file MyProgram.py:

from MyConfig import config

print config.checkForAbort

import foo

assert config is foo.config

The Python Language Reference states that "Import statements are executed in two steps: (1) find a module, and initialize it if necessary; (2) define a name or names in the local namespace (of the scope where the import statement occurs)."

What that means is that, when a module gets imported, one or more local names are bound to a module object, and only the first time it is imported during the runtime of a Python program it gets initialized (i.e. read from file and run).

In the code above the name config is just a local name that refers to an attribute of a module object. The module object has been initialized by the Python interpreter when it was referenced (via from MyConfig import config) in MyProgram. When MyProgram imports foo it is already initialized and gets bound to a local name in module foo and in MyProgram we can refer to it as foo.config. But both names refer to the very same object.

self.name = value doesn't work as you expect. You might mean setattr(self, name, value) It creates instance attributes dynamicallly.

To make it a singleton you could make the instance to be a global variable in config/settings module. Initialize it once on a program startup e.g., like the logging module does it for the root logger: logging.config.fileConfig('logging.conf').

It is a common desire to use an attribute access for what is essentially a dict e.g., argparse.Namespace that carries command-line options.

You could access the config later by importing it: from mypackage.config import config, e.g., mypackage/config.py:

class Config(object):
    ...

config = Config() # empty or default config without any configuration

In mypackage/__main__.py:

from .config import config
...
# initialization code
config.update_from_file('mypackage.conf') # it might call `setattr()` inside

Note: setattr() works correctly even you set properties. __dict__.update() breaks in this case:

class XValidatorMixin(object):
    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        if value < 0:
            raise ValueError
        self._x = value


class CUpdate(XValidatorMixin):
    def __init__(self, **options):
        self.__dict__.update(options)


class CSetAttr(XValidatorMixin):
    def __init__(self, **options):
        for name, value in options.items():
            setattr(self, name, value)

for C in [CUpdate, CSetAttr]:
    o = C(a=1, b=2) # non-property attributes work as expected
    assert o.a == 1 and o.b == 2

o = CSetAttr(x=1)
assert o.x == 1 # setattr also sets property

o = CUpdate(x=1)
try:
    o.x # .update() doesn't set property
except AttributeError:
    pass
else:
    assert 0


try:
    o = CSetAttr(x=-1)  # invokes property setter
except ValueError: # that correctly reject negative values
    pass
else:
    assert 0

The Answer by pillmuncher is very helpful and can be easily adapted to use within an existing class. Furthermore, it is also possible to automatically convert the data types using the localconfig module (link). To get these additional functionalities you can use something like:

from localconfig import LocalConfig

configfile = 'config.ini'
config = LocalConfig(configfile)
sections = list(config)

for section in sections:
    items = list(config.items(section))
    CLASS.__dict__.update(items)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!