• Initialising a Config class

    From Loris Bennett@21:1/5 to All on Tue Apr 11 16:29:58 2023
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Raymond@21:1/5 to Not sure if that works as you on Tue Apr 11 19:38:31 2023
    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


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dn@21:1/5 to Loris Bennett on Wed Apr 12 08:26:45 2023
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)