mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-22 09:36:48 +03:00
Configuration provider aliases (#397)
* Add implementation, typing stubs, and tests * Add docs and example * Update changelog
This commit is contained in:
parent
93fa37728b
commit
64d37efa37
|
@ -7,6 +7,12 @@ that were made in every particular version.
|
||||||
From version 0.7.6 *Dependency Injector* framework strictly
|
From version 0.7.6 *Dependency Injector* framework strictly
|
||||||
follows `Semantic versioning`_
|
follows `Semantic versioning`_
|
||||||
|
|
||||||
|
Development version
|
||||||
|
-------------------
|
||||||
|
- Add support of aliases for ``Configuration`` provider.
|
||||||
|
See issue: `#394 <https://github.com/ets-labs/python-dependency-injector/issues/394>`_.
|
||||||
|
Thanks to `@gtors <https://github.com/gtors>`_ for suggesting the feature.
|
||||||
|
|
||||||
4.22.1
|
4.22.1
|
||||||
------
|
------
|
||||||
- Pin ``sphinx`` version to hotfix docs build.
|
- Pin ``sphinx`` version to hotfix docs build.
|
||||||
|
|
|
@ -306,6 +306,25 @@ configuration provider to strict mode.
|
||||||
|
|
||||||
Modifier ``.required()`` should be specified before type modifier ``.as_*()``.
|
Modifier ``.required()`` should be specified before type modifier ``.as_*()``.
|
||||||
|
|
||||||
|
Aliases
|
||||||
|
-------
|
||||||
|
|
||||||
|
You can use ``Configuration`` provider with a context manager to create aliases.
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/providers/configuration/configuration_alias.py
|
||||||
|
:language: python
|
||||||
|
:lines: 3-
|
||||||
|
:emphasize-lines: 14,22
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Library ``environs`` is a 3rd party library. You need to install it
|
||||||
|
separately::
|
||||||
|
|
||||||
|
pip install environs
|
||||||
|
|
||||||
|
Documentation is available on GitHub: https://github.com/sloria/environs
|
||||||
|
|
||||||
Injecting invariants
|
Injecting invariants
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
|
36
examples/providers/configuration/configuration_alias.py
Normal file
36
examples/providers/configuration/configuration_alias.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
"""`Configuration` provider alias example."""
|
||||||
|
|
||||||
|
from dependency_injector import containers, providers
|
||||||
|
from environs import Env
|
||||||
|
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
config = providers.Configuration()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
env = Env()
|
||||||
|
container = Container()
|
||||||
|
|
||||||
|
with container.config.some_plugin_name as plugin:
|
||||||
|
plugin.some_interval_ms.override(
|
||||||
|
env.int(
|
||||||
|
'SOME_INTERVAL_MS',
|
||||||
|
default=30000,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
with plugin.kafka as kafka:
|
||||||
|
kafka.bootstrap_servers.override(
|
||||||
|
env.list(
|
||||||
|
'KAFKA_BOOTSTRAP_SERVERS',
|
||||||
|
default=['kafka1', 'kafka2'],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
kafka.security_protocol.override(
|
||||||
|
env.str(
|
||||||
|
'KAFKA_SECURITY_PROTOCOL',
|
||||||
|
default='SASL_SSL',
|
||||||
|
),
|
||||||
|
)
|
File diff suppressed because it is too large
Load Diff
|
@ -176,6 +176,8 @@ class CoroutineDelegate(Delegate):
|
||||||
class ConfigurationOption(Provider[Any]):
|
class ConfigurationOption(Provider[Any]):
|
||||||
UNDEFINED: object
|
UNDEFINED: object
|
||||||
def __init__(self, name: Tuple[str], root: Configuration) -> None: ...
|
def __init__(self, name: Tuple[str], root: Configuration) -> None: ...
|
||||||
|
def __enter__(self) -> ConfigurationOption: ...
|
||||||
|
def __exit__(self, *exc_info: Any) -> None: ...
|
||||||
def __getattr__(self, item: str) -> ConfigurationOption: ...
|
def __getattr__(self, item: str) -> ConfigurationOption: ...
|
||||||
def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ...
|
def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ...
|
||||||
@property
|
@property
|
||||||
|
@ -203,6 +205,8 @@ class TypedConfigurationOption(Callable[T]):
|
||||||
class Configuration(Object[Any]):
|
class Configuration(Object[Any]):
|
||||||
DEFAULT_NAME: str = 'config'
|
DEFAULT_NAME: str = 'config'
|
||||||
def __init__(self, name: str = DEFAULT_NAME, default: Optional[Any] = None, *, strict: bool = False) -> None: ...
|
def __init__(self, name: str = DEFAULT_NAME, default: Optional[Any] = None, *, strict: bool = False) -> None: ...
|
||||||
|
def __enter__(self) -> Configuration : ...
|
||||||
|
def __exit__(self, *exc_info: Any) -> None: ...
|
||||||
def __getattr__(self, item: str) -> ConfigurationOption: ...
|
def __getattr__(self, item: str) -> ConfigurationOption: ...
|
||||||
def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ...
|
def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ...
|
||||||
def get_name(self) -> str: ...
|
def get_name(self) -> str: ...
|
||||||
|
|
|
@ -1415,6 +1415,12 @@ cdef class ConfigurationOption(Provider):
|
||||||
|
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *exc_info):
|
||||||
|
pass
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return represent_provider(provider=self, provides=self.get_name())
|
return represent_provider(provider=self, provides=self.get_name())
|
||||||
|
|
||||||
|
@ -1740,6 +1746,12 @@ cdef class Configuration(Object):
|
||||||
|
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *exc_info):
|
||||||
|
pass
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return represent_provider(provider=self, provides=self.__name)
|
return represent_provider(provider=self, provides=self.__name)
|
||||||
|
|
||||||
|
|
|
@ -243,6 +243,33 @@ class ConfigTests(unittest.TestCase):
|
||||||
with self.assertRaises(AttributeError):
|
with self.assertRaises(AttributeError):
|
||||||
a.__name__
|
a.__name__
|
||||||
|
|
||||||
|
def test_context_manager_alias(self):
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
config = providers.Configuration()
|
||||||
|
|
||||||
|
container = Container()
|
||||||
|
|
||||||
|
with container.config as cfg:
|
||||||
|
cfg.override({'foo': 'foo', 'bar': 'bar'})
|
||||||
|
|
||||||
|
self.assertEqual(container.config(), {'foo': 'foo', 'bar': 'bar'})
|
||||||
|
self.assertEqual(cfg(), {'foo': 'foo', 'bar': 'bar'})
|
||||||
|
self.assertIs(container.config, cfg)
|
||||||
|
|
||||||
|
def test_option_context_manager_alias(self):
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
config = providers.Configuration()
|
||||||
|
|
||||||
|
container = Container()
|
||||||
|
|
||||||
|
with container.config.option as opt:
|
||||||
|
opt.override({'foo': 'foo', 'bar': 'bar'})
|
||||||
|
|
||||||
|
self.assertEqual(container.config(), {'option': {'foo': 'foo', 'bar': 'bar'}})
|
||||||
|
self.assertEqual(container.config.option(), {'foo': 'foo', 'bar': 'bar'})
|
||||||
|
self.assertEqual(opt(), {'foo': 'foo', 'bar': 'bar'})
|
||||||
|
self.assertIs(container.config.option, opt)
|
||||||
|
|
||||||
def test_missing_key(self):
|
def test_missing_key(self):
|
||||||
# See: https://github.com/ets-labs/python-dependency-injector/issues/358
|
# See: https://github.com/ets-labs/python-dependency-injector/issues/358
|
||||||
self.config.override(None)
|
self.config.override(None)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user