Allow factory override in make_config()
also add `winsvc` param for `get_config_paths()` to support RattailFileMonitor service on windows
This commit is contained in:
parent
ed6a5db452
commit
1431555605
|
@ -620,11 +620,12 @@ def generic_default_files(appname):
|
||||||
def get_config_paths(
|
def get_config_paths(
|
||||||
files=None,
|
files=None,
|
||||||
plus_files=None,
|
plus_files=None,
|
||||||
|
appname='wutta',
|
||||||
env_files_name=None,
|
env_files_name=None,
|
||||||
env_plus_files_name=None,
|
env_plus_files_name=None,
|
||||||
env=None,
|
env=None,
|
||||||
default_files=None,
|
default_files=None,
|
||||||
appname='wutta'):
|
winsvc=None):
|
||||||
"""
|
"""
|
||||||
This function determines which files should ultimately be provided
|
This function determines which files should ultimately be provided
|
||||||
to the config constructor. It is normally called by
|
to the config constructor. It is normally called by
|
||||||
|
@ -696,6 +697,42 @@ def get_config_paths(
|
||||||
|
|
||||||
files = get_config_paths(default_files=mydefaults)
|
files = get_config_paths(default_files=mydefaults)
|
||||||
|
|
||||||
|
:param 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:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[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.
|
:returns: List of file paths.
|
||||||
"""
|
"""
|
||||||
if env is None:
|
if env is None:
|
||||||
|
@ -748,6 +785,22 @@ def get_config_paths(
|
||||||
|
|
||||||
# combine all files
|
# combine all files
|
||||||
files.extend(plus_files)
|
files.extend(plus_files)
|
||||||
|
|
||||||
|
# when running as a proper windows service, must first read
|
||||||
|
# "default" file(s) and then consult config to see which file
|
||||||
|
# should "really" be used. because there isn't a way to specify
|
||||||
|
# which config file as part of the actual service definition in
|
||||||
|
# windows, so the service name is used for magic lookup here.
|
||||||
|
if winsvc:
|
||||||
|
config = configparser.SafeConfigParser()
|
||||||
|
config.read(files)
|
||||||
|
section = f'{appname}.config'
|
||||||
|
if config.has_section(section):
|
||||||
|
option = f'winsvc.{winsvc}'
|
||||||
|
if config.has_option(section, option):
|
||||||
|
# replace file paths with whatever config value says
|
||||||
|
files = parse_list(config.get(section, option))
|
||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
@ -759,10 +812,13 @@ def make_config(
|
||||||
env_plus_files_name=None,
|
env_plus_files_name=None,
|
||||||
env=None,
|
env=None,
|
||||||
default_files=None,
|
default_files=None,
|
||||||
|
winsvc=None,
|
||||||
usedb=None,
|
usedb=None,
|
||||||
preferdb=None,
|
preferdb=None,
|
||||||
|
factory=None,
|
||||||
extend=True,
|
extend=True,
|
||||||
extension_entry_points=None):
|
extension_entry_points=None,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Make a new config object (presumably for global use), initialized
|
Make a new config object (presumably for global use), initialized
|
||||||
per the given parameters and (usually) further modified by all
|
per the given parameters and (usually) further modified by all
|
||||||
|
@ -771,20 +827,25 @@ def make_config(
|
||||||
This function really does 3 things:
|
This function really does 3 things:
|
||||||
|
|
||||||
* determine the set of config files to use
|
* determine the set of config files to use
|
||||||
* pass those files to config constructor
|
* pass those files to config factory
|
||||||
* apply extensions to the resulting config object
|
* apply extensions to the resulting config object
|
||||||
|
|
||||||
Some params are described in :func:`get_config_paths()` since they
|
Some params are described in :func:`get_config_paths()` since they
|
||||||
are passed as-is to that function for the first step.
|
are passed as-is to that function for the first step.
|
||||||
|
|
||||||
:param appname: The "app name" to use as basis for other things -
|
:param appname: The :term:`app name` to use as basis for other
|
||||||
namely, it affects how config files are located. This name is
|
things - namely, it affects how config files are located. This
|
||||||
also passed to the config constructor at which point it becomes
|
name is also passed to the config factory at which point it
|
||||||
:attr:`wuttjamaican.conf.WuttaConfig.appname`.
|
becomes :attr:`~wuttjamaican.conf.WuttaConfig.appname`.
|
||||||
|
|
||||||
:param usedb: Passed to the :class:`WuttaConfig` constructor.
|
:param usedb: Passed to the config factory; becomes
|
||||||
|
:attr:`~wuttjamaican.conf.WuttaConfig.usedb`.
|
||||||
|
|
||||||
:param preferdb: Passed to the :class:`WuttaConfig` constructor.
|
:param preferdb: Passed to the config factory; becomes
|
||||||
|
:attr:`~wuttjamaican.conf.WuttaConfig.preferdb`.
|
||||||
|
|
||||||
|
:param factory: Optional factory to use when making the object.
|
||||||
|
Default factory is :class:`WuttaConfig`.
|
||||||
|
|
||||||
:param extend: Whether to "auto-extend" the config with all
|
:param extend: Whether to "auto-extend" the config with all
|
||||||
registered extensions.
|
registered extensions.
|
||||||
|
@ -813,11 +874,15 @@ def make_config(
|
||||||
env_files_name=env_files_name,
|
env_files_name=env_files_name,
|
||||||
env_plus_files_name=env_plus_files_name,
|
env_plus_files_name=env_plus_files_name,
|
||||||
env=env,
|
env=env,
|
||||||
default_files=default_files)
|
default_files=default_files,
|
||||||
|
winsvc=winsvc)
|
||||||
|
|
||||||
# make config object
|
# make config object
|
||||||
config = WuttaConfig(files, appname=appname,
|
if not factory:
|
||||||
usedb=usedb, preferdb=preferdb)
|
factory = WuttaConfig
|
||||||
|
config = factory(files, appname=appname,
|
||||||
|
usedb=usedb, preferdb=preferdb,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
# maybe extend config object
|
# maybe extend config object
|
||||||
if extend:
|
if extend:
|
||||||
|
|
|
@ -417,6 +417,18 @@ class TestGenericDefaultFiles(TestCase):
|
||||||
self.assertEqual(len(files), 0)
|
self.assertEqual(len(files), 0)
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetConfigPaths(FileConfigTestCase):
|
||||||
|
|
||||||
|
def test_winsvc(self):
|
||||||
|
myconf = self.write_file('my.conf', """
|
||||||
|
[wutta.config]
|
||||||
|
winsvc.RattailFileMonitor = /path/to/other/file
|
||||||
|
""")
|
||||||
|
|
||||||
|
files = conf.get_config_paths(files=[myconf], winsvc='RattailFileMonitor')
|
||||||
|
self.assertEqual(files, ['/path/to/other/file'])
|
||||||
|
|
||||||
|
|
||||||
class TestMakeConfig(FileConfigTestCase):
|
class TestMakeConfig(FileConfigTestCase):
|
||||||
|
|
||||||
# nb. we use appname='wuttatest' in this suite to avoid any
|
# nb. we use appname='wuttatest' in this suite to avoid any
|
||||||
|
|
Loading…
Reference in a new issue