wuttjamaican.conf

WuttJamaican - app configuration

class wuttjamaican.conf.WuttaConfig(files=[], defaults={}, appname='wutta', usedb=None, preferdb=None, configure_logging=None)[source]

Configuration class for Wutta Framework

A single instance of this class is typically created on app startup, by calling make_config().

The global config object is mainly responsible for providing config values to the app, via get() and similar methods.

The config object may have more than one place to look when finding values. This can vary somewhat but often the priority for lookup is like:

  • settings table in the DB

  • one or more INI files

  • “defaults” provided by app logic

Parameters:
  • files – List of file paths from which to read config values.

  • defaults – Initial values to use as defaults. This gets converted to defaults during construction.

  • appname – Value to assign for appname.

  • usedb – Flag indicating whether config values should ever be looked up from the DB. Note that you can override this when calling get().

  • preferdb – Flag indicating whether values from DB should be preferred over the values from INI files or app defaults. Note that you can override this when calling get().

  • configure_logging – Flag indicating whether logging should be configured during object construction. If not specified, the config values will determine behavior.

Attributes available on the config instance:

appname

Code-friendly name (“key”) for the app. This is used as the basis for various config settings and will therefore determine what is returned from get_app() etc.

For instance the default appname value is 'wutta' which means a sample config file might look like:

[wutta]
app.handler = wuttjamaican.app:AppHandler

[wutta.db]
default.url = sqlite://

But if the appname value is e.g. 'rattail' then the sample config should instead look like:

[rattail]
app.handler = wuttjamaican.app:AppHandler

[rattail.db]
default.url = sqlite://
configuration

Reference to the python-configuration:config.ConfigurationSet instance which houses the full set of config values which are kept in memory. This does not contain settings from DB, but does contain defaults as well as values read from INI files.

defaults

Reference to the python-configuration:config.Configuration instance containing config default values. This is exposed in case it’s useful, but in practice you should not update it directly; instead use setdefault().

files_read

List of all INI config files which were read on app startup. These are listed in the same order as they were read. This sequence also reflects priority for value lookups, i.e. the first file with the value wins.

usedb

Whether the settings table should be searched for config settings. This is False by default but may be enabled via config file:

[wutta.config]
usedb = true

See also Where Values Come From.

preferdb

Whether the settings table should be preferred over config files when looking for config settings. This is False by default, and in any case is ignored unless usedb is True.

Most apps will want to enable this flag so that when the settings table is updated, it will immediately affect app behavior regardless of what values are in the config files.

[wutta.config]
usedb = true
preferdb = true

See also Where Values Come From.

get(key, default=<object object>, require=False, ignore_ambiguous=False, message=None, usedb=None, preferdb=None, session=None)[source]

Retrieve a string value from config.

Warning

While the point of this method is to return a string value, it is possible for a key to be present in config which corresponds to a “subset” of the config, and not a simple value. For instance with this config file:

[foo]
bar = 1
bar.baz = 2

If you invoke config.get('foo.bar') the return value is somewhat ambiguous. At first glance it should return '1' - but just as valid would be to return the dict:

{'baz': '2'}

And similarly, if you invoke config.get('foo') then the return value “should be” the dict:

{'bar': '1',
 'bar.baz': '2'}

Despite all that ambiguity, again the whole point of this method is to return a string value, only. Therefore in any case where the return value “should be” a dict, per logic described above, this method will ignore that and simply return None (or rather the default value).

It is important also to understand that in fact, there is no “real” ambiguity per se, but rather a dict (subset) would always get priority over a simple string value. So in the first example above, config.get('foo.bar') will always return the default value. The string value '1' will never be returned since the dict/subset overshadows it, and this method will only return the default value in lieu of any dict.

Parameters:
  • key – String key for which value should be returned.

  • default – Default value to be returned, if config does not contain the key. If no default is specified, None will be assumed.

  • require

    If set, an error will be raised if config does not contain the key. If not set, default value is returned (which may be None).

    Note that it is an error to specify a default value if you also specify require=True.

  • ignore_ambiguous – By default this method will log a warning if an ambiguous value is detected (as described above). Pass a true value for this flag to avoid the warnings. Should use with caution, as the warnings are there for a reason.

  • message – Optional first part of message to be used, when raising a “value not found” error. If not specified, a default error message will be generated.

  • usedb – Flag indicating whether config values should be looked up from the DB. The default for this param is None, in which case the usedb flag determines the behavior.

  • preferdb – Flag indicating whether config values from DB should be preferred over values from INI files and/or app defaults. The default for this param is None, in which case the preferdb flag determines the behavior.

  • session – Optional SQLAlchemy session to use for DB lookups. NOTE: This param is not yet implemented; currently ignored.

Returns:

Value as string.

get_app()[source]

Returns the global AppHandler instance, creating it if necessary.

See also App Handler.

get_bool(*args, **kwargs)[source]

Retrieve a boolean value from config.

Accepts same params as get() but if a value is found, it will be coerced to boolean via parse_bool().

get_dict(prefix)[source]

Retrieve a particular group of values, as a dictionary.

Please note, this will only return values from INI files + defaults. It will not return values from DB settings. In other words it assumes usedb=False.

For example given this config file:

[wutta.db]
keys = default, host
default.url = sqlite:///tmp/default.sqlite
host.url = sqlite:///tmp/host.sqlite
host.pool_pre_ping = true

One can get the “dict” for SQLAlchemy engine config via:

config.get_dict('wutta.db')

And the dict would look like:

{'keys': 'default, host',
 'default.url': 'sqlite:///tmp/default.sqlite',
 'host.url': 'sqlite:///tmp/host.sqlite',
 'host.pool_pre_ping': 'true'}
Parameters:

prefix – String prefix corresponding to a subsection of the config.

Returns:

Dictionary containing the config subsection.

get_from_db(key, session=None)[source]

Retrieve a config value from database settings table.

This is a convenience wrapper around get_setting().

get_int(*args, **kwargs)[source]

Retrieve an integer value from config.

Accepts same params as get() but if a value is found, it will be coerced to integer via the python:int() constructor.

get_list(*args, **kwargs)[source]

Retrieve a list value from config.

Accepts same params as get() but if a value is found, it will be coerced to list via parse_list().

Returns:

If a value is found, a list is returned. If no value, returns None.

get_prioritized_files()[source]

Returns list of config files in order of priority.

By default, files_read should already be in the correct order, but this is to make things more explicit.

require(*args, **kwargs)[source]

Retrieve a value from config, or raise error if no value can be found. This is just a shortcut, so these work the same:

config.get('foo', require=True)

config.require('foo')
setdefault(key, value)[source]

Establish a default config value for the given key.

Note that there is only one default value per key. If multiple calls are made with the same key, the first will set the default and subsequent calls have no effect.

Returns:

The current config value, outside of the DB. For various reasons this method may not be able to lookup settings from the DB, e.g. during app init. So it can only determine the value per INI files + config defaults.

class wuttjamaican.conf.WuttaConfigExtension[source]

Base class for all config extensions.

configure(config)[source]

Subclass should override this method, to extend the config object in any way necessary.

wuttjamaican.conf.generic_default_files(appname)[source]

Returns a list of default file paths which might be used for making a config object. This function does not check if the paths actually exist.

Parameters:

appname – App name to be used as basis for default filenames.

Returns:

List of default file paths.

wuttjamaican.conf.get_config_paths(files=None, plus_files=None, appname='wutta', env_files_name=None, env_plus_files_name=None, env=None, default_files=None, winsvc=None)[source]

This function determines which files should ultimately be provided to the config constructor. It is normally called by make_config().

In short, the files to be used are determined by typical priority:

  • function params - files and plus_files

  • environment variables - e.g. WUTTA_CONFIG_FILES

  • app defaults - e.g. generic_default_files()

The “main” and so-called “plus” config files are dealt with separately, so that “defaults” can be used for the main files, and any “plus” files are then added to the result.

In the end it combines everything it finds into a single list. Note that it does not necessarily check to see if these files exist.

Parameters:
  • files – Explicit set of “main” config files. If not specified, environment variables and/or default lookup will be done to get the “main” file set. Specify an empty list to force an empty main file set.

  • plus_files – Explicit set of “plus” config files. Same rules apply here as for the files param.

  • appname – The “app name” to use as basis for other things - namely, constructing the default config file paths etc. For instance the default appname value is 'wutta' which leads to default env vars like WUTTA_CONFIG_FILES.

  • env_files_name – Name of the environment variable to read, if files is not specified. The default is WUTTA_CONFIG_FILES unless you override appname.

  • env_plus_files_name – Name of the environment variable to read, if plus_files is not specified. The default is WUTTA_CONFIG_PLUS_FILES unless you override appname.

  • env – Optional environment dict; if not specified os.environ is used.

  • default_files

    Optional lookup for “default” file paths.

    This is only used a) for the “main” config file lookup (but not “plus” files), and b) if neither files nor the environment variables yielded anything.

    If not specified, generic_default_files() will be used for the lookup.

    You may specify a single file path as string, or a list of file paths, or a callable which returns either of those things. For example any of these could be used:

    mydefaults = '/tmp/something.conf'
    
    mydefaults = [
        '/tmp/something.conf',
        '/tmp/else.conf',
    ]
    
    def mydefaults(appname):
        return [
            f"/tmp/{appname}.conf",
            f"/tmp/{appname}.ini",
        ]
    
    files = get_config_paths(default_files=mydefaults)
    

  • winsvc

    Optional internal name of the Windows service for which the config object is being made.

    This is only needed for true Windows services running via “Python for Windows Extensions” - which probably only includes the Rattail File Monitor service.

    In this context there is no way to tell the app which config files to read on startup, so it can only look for “default” files. But by passing a winsvc name to this function, it will first load the default config file, then read a particular value to determine the “real” config file(s) it should use.

    So for example on Windows you might have a config file at C:\ProgramData\rattail\rattail.conf with contents:

    [rattail.config]
    winsvc.RattailFileMonitor = C:\ProgramData\rattail\filemon.conf
    

    And then C:\ProgramData\rattail\filemon.conf would have the actual config for the filemon service.

    When the service starts it calls:

    make_config(winsvc='RattailFileMonitor')
    

    which first reads the rattail.conf file (since that is the only sensible default), but then per config it knows to swap that out for filemon.conf at startup. This is because it finds a config value matching the requested service name. The end result is as if it called this instead:

    make_config(files=[r'C:\ProgramData\rattail\filemon.conf'])
    

Returns:

List of file paths.

wuttjamaican.conf.make_config(files=None, plus_files=None, appname='wutta', env_files_name=None, env_plus_files_name=None, env=None, default_files=None, winsvc=None, usedb=None, preferdb=None, factory=None, extend=True, extension_entry_points=None, **kwargs)[source]

Make a new config (usually WuttaConfig) object, initialized per the given parameters and (usually) further modified by all registered config extensions.

This function really does 3 things:

  • determine the set of config files to use

  • pass those files to config factory

  • apply extensions to the resulting config object

Some params are described in get_config_paths() since they are passed as-is to that function for the first step.

Parameters:
  • appname – The app name to use as basis for other things - namely, it affects how config files are located. This name is also passed to the config factory at which point it becomes appname.

  • usedb – Passed to the config factory; becomes usedb.

  • preferdb – Passed to the config factory; becomes preferdb.

  • factory – Optional factory to use when making the object. Default factory is WuttaConfig.

  • extend

    Whether to “auto-extend” the config with all registered extensions.

    As a general rule, make_config() should only be called once, upon app startup. This is because some of the config extensions may do things which should only happen one time. However if extend=False is specified, then no extensions are invoked, so this may be done multiple times.

    (Why anyone would need this, is another question..maybe only useful for tests.)

  • extension_entry_points – Name of the setuptools entry points section, used to identify registered config extensions. The default is wutta.config.extensions unless you override appname.

Returns:

The new config object.