feat: add WuttaConfigProfile base class
convenience for use with various configurable features/services etc.
This commit is contained in:
parent
a721e63275
commit
ad6a3377ab
2 changed files with 105 additions and 1 deletions
|
@ -1013,3 +1013,89 @@ def make_config(
|
||||||
extension.startup(config)
|
extension.startup(config)
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
class WuttaConfigProfile:
|
||||||
|
"""
|
||||||
|
Base class to represent a configured "profile" in the context of
|
||||||
|
some service etc.
|
||||||
|
|
||||||
|
:param config: App :term:`config object`.
|
||||||
|
|
||||||
|
:param key: Config key for the profile.
|
||||||
|
|
||||||
|
Generally each subclass will represent a certain type of config
|
||||||
|
profile, and each instance will represent a single profile
|
||||||
|
(identified by the ``key``).
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, config, key):
|
||||||
|
self.config = config
|
||||||
|
self.app = self.config.get_app()
|
||||||
|
self.key = key
|
||||||
|
self.load()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def section(self):
|
||||||
|
"""
|
||||||
|
The primary config section under which profiles may be
|
||||||
|
defined.
|
||||||
|
|
||||||
|
There is no default; each subclass must declare it.
|
||||||
|
|
||||||
|
This corresponds to the typical INI file section, for instance
|
||||||
|
a section of ``wutta.telemetry`` assumes file contents like:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[wutta.telemetry]
|
||||||
|
default.submit_url = /nodes/telemetry
|
||||||
|
special.submit_url = /nodes/telemetry-special
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
"""
|
||||||
|
Read all relevant settings from config, and assign attributes
|
||||||
|
on the profile instance accordingly.
|
||||||
|
|
||||||
|
There is no default logic but subclass will generally override.
|
||||||
|
|
||||||
|
While a caller can use :meth:`get_str()` to obtain arbitrary
|
||||||
|
config values dynamically, it is often useful for the profile
|
||||||
|
to pre-load some config values. This allows "smarter"
|
||||||
|
interpretation of config values in some cases, and at least
|
||||||
|
ensures common/shared logic.
|
||||||
|
|
||||||
|
There is no constraint or other guidance in terms of which
|
||||||
|
profile attributes might be set by this method. Subclass
|
||||||
|
should document if necessary.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_str(self, option, **kwargs):
|
||||||
|
"""
|
||||||
|
Get a string value for the profile, from config.
|
||||||
|
|
||||||
|
:param option: Name of config option for which to return value.
|
||||||
|
|
||||||
|
This just calls :meth:`~WuttaConfig.get()` on the config
|
||||||
|
object, but for a particular setting name which it composes
|
||||||
|
dynamically.
|
||||||
|
|
||||||
|
Assuming a config file like:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[wutta.telemetry]
|
||||||
|
default.submit_url = /nodes/telemetry
|
||||||
|
|
||||||
|
Then a ``default`` profile under the ``wutta.telemetry``
|
||||||
|
section would effectively have a ``submit_url`` option::
|
||||||
|
|
||||||
|
class TelemetryProfile(WuttaConfigProfile):
|
||||||
|
section = "wutta.telemetry"
|
||||||
|
|
||||||
|
profile = TelemetryProfile("default")
|
||||||
|
url = profile.get_str("submit_url")
|
||||||
|
"""
|
||||||
|
return self.config.get(f'{self.section}.{self.key}.{option}', **kwargs)
|
||||||
|
|
|
@ -12,7 +12,7 @@ from wuttjamaican import conf as mod
|
||||||
from wuttjamaican import conf
|
from wuttjamaican import conf
|
||||||
from wuttjamaican.exc import ConfigurationError
|
from wuttjamaican.exc import ConfigurationError
|
||||||
from wuttjamaican.app import AppHandler
|
from wuttjamaican.app import AppHandler
|
||||||
from wuttjamaican.testing import FileTestCase
|
from wuttjamaican.testing import FileTestCase, ConfigTestCase
|
||||||
|
|
||||||
|
|
||||||
class TestWuttaConfig(FileTestCase):
|
class TestWuttaConfig(FileTestCase):
|
||||||
|
@ -867,3 +867,21 @@ class TestMakeConfig(FileTestCase):
|
||||||
foo_cls.assert_called_once_with()
|
foo_cls.assert_called_once_with()
|
||||||
foo_obj.configure.assert_called_once_with(testconfig)
|
foo_obj.configure.assert_called_once_with(testconfig)
|
||||||
foo_obj.startup.assert_called_once_with(testconfig)
|
foo_obj.startup.assert_called_once_with(testconfig)
|
||||||
|
|
||||||
|
|
||||||
|
class TestWuttaConfigProfile(ConfigTestCase):
|
||||||
|
|
||||||
|
def make_profile(self, key):
|
||||||
|
return mod.WuttaConfigProfile(self.config, key)
|
||||||
|
|
||||||
|
def test_section(self):
|
||||||
|
profile = self.make_profile('default')
|
||||||
|
self.assertRaises(NotImplementedError, getattr, profile, 'section')
|
||||||
|
|
||||||
|
def test_get_str(self):
|
||||||
|
self.config.setdefault('wutta.telemetry.default.submit_url', '/nodes/telemetry')
|
||||||
|
with patch.object(mod.WuttaConfigProfile, 'section', new='wutta.telemetry'):
|
||||||
|
profile = self.make_profile('default')
|
||||||
|
self.assertEqual(profile.section, 'wutta.telemetry')
|
||||||
|
url = profile.get_str('submit_url')
|
||||||
|
self.assertEqual(url, '/nodes/telemetry')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue