Mailing List Archive

Initialising a Config class
Hi,

Having solved my problem regarding setting up 'logger' such that it is
accessible throughout my program (thanks to the help on this list), I
now have problem related to a slightly similar issue.

My reading suggests that setting up a module with a Config class which
can be imported by any part of the program might be a reasonable approach:


import configparser

class Config:

def __init__(self, config_file):

config = configparser.ConfigParser()
config.read(config_file)


However, in my config file I am using sections, so 'config' is a dict of
dicts. Is there any cleverer generic way of initialising the class than


self.config = config


?

This seems a bit clunky, because I'll end up with something like


import config
...
c = config.Config(config_file)
uids = get_uids(int(c.config["uids"]["minimum_uid"]))


rather than something like, maybe


uids = get_uids(int(c.minimum_uid))


or


uids = get_uids(int(c.uids_minimum_uid))


So the question is: How can I map a dict of dicts onto class attributes
in a generic way such that only code which wants to use a new
configuration parameter needs to be changed and not the Config class
itself? Or should I be doing this differently?

Note that the values from ConfigParser are all strings, so I am fine
with the attributes being strings - I'll just convert them as needed at
the point of use (but maybe there is also a better way of handling that
within a class).

Cheers,

Loris

--
This signature is currently under constuction.
--
https://mail.python.org/mailman/listinfo/python-list
RE: Initialising a Config class [ In reply to ]
Not sure if I'm fully understanding the question. But one option instead of making everything class attributes is to just define __getattr__ for when it doesn't find an attribute.

Won't work for every single valid section and option name (because of spaces, name overlaps, etc) but should cover most things.
For example, you could use a dunder to separate section and option. Then something like this?


import configparser

class Config:
def __init__(self, configFile):
self._config = configparser.ConfigParser()
self._config.read(configFile)
def __getattr__(self, option):
if "__" in option:
section, option = option.split("__", 1)
else:
section = self._config.default_section
return self._config[section][option]

c = Config("SomeConfigFile.txt")
print(c.uids__minimum_uid) #Will check for the option "minimum_uid" in the "uids" section
print(c.minimum_uid) #Will check the default section


Not sure if that works as you said the Config class itself should not need to be changed

> Hi,
>
> Having solved my problem regarding setting up 'logger' such that it is
> accessible throughout my program (thanks to the help on this list), I
> now have problem related to a slightly similar issue.
>
> My reading suggests that setting up a module with a Config class which
> can be imported by any part of the program might be a reasonable approach:
>
>
> import configparser
>
> class Config:
>
> def __init__(self, config_file):
>
> config = configparser.ConfigParser()
> config.read(config_file)
>
>
> However, in my config file I am using sections, so 'config' is a dict of
> dicts. Is there any cleverer generic way of initialising the class than
>
>
> self.config = config
>
>
> ?
>
> This seems a bit clunky, because I'll end up with something like
>
>
> import config
> ...
> c = config.Config(config_file)
> uids = get_uids(int(c.config["uids"]["minimum_uid"]))
>
>
> rather than something like, maybe
>
>
> uids = get_uids(int(c.minimum_uid))
>
>
> or
>
>
> uids = get_uids(int(c.uids_minimum_uid))
>
>
> So the question is: How can I map a dict of dicts onto class attributes
> in a generic way such that only code which wants to use a new
> configuration parameter needs to be changed and not the Config class
> itself? Or should I be doing this differently?
>
> Note that the values from ConfigParser are all strings, so I am fine
> with the attributes being strings - I'll just convert them as needed at
> the point of use (but maybe there is also a better way of handling that
> within a class).
>
> Cheers,
>
> Loris
>
--
https://mail.python.org/mailman/listinfo/python-list
Re: Initialising a Config class [ In reply to ]
On 12/04/2023 02.29, Loris Bennett wrote:
> Hi,
>
> Having solved my problem regarding setting up 'logger' such that it is
...

> My reading suggests that setting up a module with a Config class which
> can be imported by any part of the program might be a reasonable approach:
...

> However, in my config file I am using sections, so 'config' is a dict of
> dicts. Is there any cleverer generic way of initialising the class than
...

> This seems a bit clunky, because I'll end up with something like
...

> So the question is: How can I map a dict of dicts onto class attributes
> in a generic way such that only code which wants to use a new
> configuration parameter needs to be changed and not the Config class
> itself? Or should I be doing this differently?
>
> Note that the values from ConfigParser are all strings, so I am fine
> with the attributes being strings - I'll just convert them as needed at
> the point of use (but maybe there is also a better way of handling that
> within a class).

Good progress!

The first achievement has been related to the (OO) concept of
"encapsulation" - collecting related data into one place.

The second, has been the making of this, globally-accessible within the
application.


The balancing-act may now have become: making sub-sets of the data
available.

Thus, describing which database server and schema/view to use is part of
the application's environment/config, just as much as the labels, eg
company name, used in the GUI or reporting. Such data has been collected
together (into a single 'source of truth'), but will be used in quite
separate and/or disparate functionality within the application.

The config file has been (sensibly) split into sections - when the code
is dealing with the DB it does not need to be concerned with
GUI-settings - or vice-versa.

Accordingly, and like any other class (encapsulation), having been
collected en-masse (or 'amassed', eg cmdLN options combined with a
JSON/YAML/.ini file's settings) the data should be delivered
appropriately. Thus, a 'getter' method (or property) to deliver the name
of the company (likely a string). The one for the database may deliver a
dict or key-value pairs which can be immediately 'pasted' into some
db-open function-call...

Such retrieval-methods will be targeted to the sub-systems of the
application. They can perform formatting and coercion tasks, as
necessary, eg construct full-name from two or more separate data-items,
eg first_name and family_name, or perhaps providing floats where the
config-collection only receives strings. (best to 'hide' all that within
the class, than require the application to deal with the 'clunkiness').
Plus, they could?should provide whatever combination of data-items is
appropriate to THAT part of the application's need for config-data or
constraints. (etc)


Stuff as much as is possible into the config class - how to collect
environment-data, and satisfying any/all demands for its use. Then, the
application can be relieved of all detail ("give me what I want"), only
asking for whatever it requires, when it requires, and in the format it
requires - tailored and ready for immediate-use...

--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list