mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 02:53:56 +03:00
Merge branch 'release/4.10.2' into master
This commit is contained in:
commit
9f7dbe89f6
|
@ -7,6 +7,20 @@ 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
|
||||||
|
-------------------
|
||||||
|
- Fix a bug in the ``Configuration`` provider: strict mode didn't work when provider
|
||||||
|
is overridden by ``None``.
|
||||||
|
See issue: `#358#issuecomment-761607432 <https://github.com/ets-labs/python-dependency-injector/issues/358#issuecomment-761607432>`_.
|
||||||
|
Many thanks to `Stefano Frazzetto <https://github.com/StefanoFrazzetto>`_ for reporting the issue.
|
||||||
|
|
||||||
|
4.10.2
|
||||||
|
------
|
||||||
|
- Fix a bug in ``Resource`` that cause failure when async resource depends on
|
||||||
|
another async resource.
|
||||||
|
See issue `#361 <https://github.com/ets-labs/python-dependency-injector/issues/361>`_.
|
||||||
|
Thanks `@kolypto <https://github.com/kolypto>`_ for the bug report.
|
||||||
|
|
||||||
4.10.1
|
4.10.1
|
||||||
------
|
------
|
||||||
- Fix a Python 3.9 specific bug in ``wiring`` module: introspection doesn't work for
|
- Fix a Python 3.9 specific bug in ``wiring`` module: introspection doesn't work for
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Top-level package."""
|
"""Top-level package."""
|
||||||
|
|
||||||
__version__ = '4.10.1'
|
__version__ = '4.10.2'
|
||||||
"""Version number.
|
"""Version number.
|
||||||
|
|
||||||
:type: str
|
:type: str
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1471,12 +1471,14 @@ cdef class Configuration(Object):
|
||||||
:return: Option value.
|
:return: Option value.
|
||||||
:rtype: Any
|
:rtype: Any
|
||||||
"""
|
"""
|
||||||
keys = selector.split('.')
|
|
||||||
value = self.__call__()
|
value = self.__call__()
|
||||||
|
|
||||||
if value is None:
|
if value is None:
|
||||||
|
if self.__strict or required:
|
||||||
|
raise Error('Undefined configuration option "{0}.{1}"'.format(self.__name, selector))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
keys = selector.split('.')
|
||||||
while len(keys) > 0:
|
while len(keys) > 0:
|
||||||
key = keys.pop(0)
|
key = keys.pop(0)
|
||||||
value = value.get(key, self.UNDEFINED)
|
value = value.get(key, self.UNDEFINED)
|
||||||
|
@ -1500,9 +1502,9 @@ cdef class Configuration(Object):
|
||||||
:return: Overriding context.
|
:return: Overriding context.
|
||||||
:rtype: :py:class:`OverridingContext`
|
:rtype: :py:class:`OverridingContext`
|
||||||
"""
|
"""
|
||||||
keys = selector.split('.')
|
|
||||||
original_value = current_value = deepcopy(self.__call__())
|
original_value = current_value = deepcopy(self.__call__())
|
||||||
|
|
||||||
|
keys = selector.split('.')
|
||||||
while len(keys) > 0:
|
while len(keys) > 0:
|
||||||
key = keys.pop(0)
|
key = keys.pop(0)
|
||||||
if len(keys) == 0:
|
if len(keys) == 0:
|
||||||
|
@ -2967,7 +2969,7 @@ cdef class Resource(Provider):
|
||||||
self.__kwargs_len,
|
self.__kwargs_len,
|
||||||
)
|
)
|
||||||
self.__initialized = True
|
self.__initialized = True
|
||||||
return self._create_init_future(initializer.__anext__(), initializer.asend)
|
return self._create_async_gen_init_future(initializer)
|
||||||
elif callable(self.__initializer):
|
elif callable(self.__initializer):
|
||||||
self.__resource = __call(
|
self.__resource = __call(
|
||||||
self.__initializer,
|
self.__initializer,
|
||||||
|
@ -2995,6 +2997,18 @@ cdef class Resource(Provider):
|
||||||
|
|
||||||
return future
|
return future
|
||||||
|
|
||||||
|
def _create_async_gen_init_future(self, initializer):
|
||||||
|
if inspect.isasyncgen(initializer):
|
||||||
|
return self._create_init_future(initializer.__anext__(), initializer.asend)
|
||||||
|
|
||||||
|
future = asyncio.Future()
|
||||||
|
|
||||||
|
create_initializer = asyncio.ensure_future(initializer)
|
||||||
|
create_initializer.add_done_callback(functools.partial(self._async_create_gen_callback, future))
|
||||||
|
self.__resource = future
|
||||||
|
|
||||||
|
return future
|
||||||
|
|
||||||
def _async_init_callback(self, initializer, shutdowner=None):
|
def _async_init_callback(self, initializer, shutdowner=None):
|
||||||
try:
|
try:
|
||||||
resource = initializer.result()
|
resource = initializer.result()
|
||||||
|
@ -3005,6 +3019,14 @@ cdef class Resource(Provider):
|
||||||
self.__resource = resource
|
self.__resource = resource
|
||||||
self.__shutdowner = shutdowner
|
self.__shutdowner = shutdowner
|
||||||
|
|
||||||
|
def _async_create_gen_callback(self, future, initializer_future):
|
||||||
|
initializer = initializer_future.result()
|
||||||
|
init_future = self._create_init_future(initializer.__anext__(), initializer.asend)
|
||||||
|
init_future.add_done_callback(functools.partial(self._async_trigger_result, future))
|
||||||
|
|
||||||
|
def _async_trigger_result(self, future, future_result):
|
||||||
|
future.set_result(future_result.result())
|
||||||
|
|
||||||
def _create_shutdown_future(self, shutdown_future):
|
def _create_shutdown_future(self, shutdown_future):
|
||||||
future = asyncio.Future()
|
future = asyncio.Future()
|
||||||
shutdown_future = asyncio.ensure_future(shutdown_future)
|
shutdown_future = asyncio.ensure_future(shutdown_future)
|
||||||
|
|
|
@ -214,6 +214,12 @@ class ConfigTests(unittest.TestCase):
|
||||||
with self.assertRaisesRegex(errors.Error, 'Undefined configuration option "config.a"'):
|
with self.assertRaisesRegex(errors.Error, 'Undefined configuration option "config.a"'):
|
||||||
self.config.a()
|
self.config.a()
|
||||||
|
|
||||||
|
def test_value_of_undefined_option_with_root_none_in_strict_mode(self):
|
||||||
|
self.config = providers.Configuration(strict=True)
|
||||||
|
self.config.override(None)
|
||||||
|
with self.assertRaisesRegex(errors.Error, 'Undefined configuration option "config.a"'):
|
||||||
|
self.config.a()
|
||||||
|
|
||||||
def test_value_of_defined_none_option_in_strict_mode(self):
|
def test_value_of_defined_none_option_in_strict_mode(self):
|
||||||
self.config = providers.Configuration(strict=True)
|
self.config = providers.Configuration(strict=True)
|
||||||
self.config.from_dict({'a': None})
|
self.config.from_dict({'a': None})
|
||||||
|
|
|
@ -461,6 +461,43 @@ class AsyncResourceTest(AsyncTestCase):
|
||||||
self.assertFalse(provider.initialized)
|
self.assertFalse(provider.initialized)
|
||||||
self.assertTrue(provider.is_async_mode_enabled())
|
self.assertTrue(provider.is_async_mode_enabled())
|
||||||
|
|
||||||
|
def test_init_with_dependency_to_other_resource(self):
|
||||||
|
# See: https://github.com/ets-labs/python-dependency-injector/issues/361
|
||||||
|
async def init_db_connection(db_url: str):
|
||||||
|
await asyncio.sleep(0.001)
|
||||||
|
yield {'connection': 'ok', 'url': db_url}
|
||||||
|
|
||||||
|
async def init_user_session(db):
|
||||||
|
await asyncio.sleep(0.001)
|
||||||
|
yield {'session': 'ok', 'db': db}
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
config = providers.Configuration()
|
||||||
|
|
||||||
|
db_connection = providers.Resource(
|
||||||
|
init_db_connection,
|
||||||
|
db_url=config.db_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
user_session = providers.Resource(
|
||||||
|
init_user_session,
|
||||||
|
db=db_connection
|
||||||
|
)
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
container = Container(config={'db_url': 'postgres://...'})
|
||||||
|
try:
|
||||||
|
return await container.user_session()
|
||||||
|
finally:
|
||||||
|
await container.shutdown_resources()
|
||||||
|
|
||||||
|
result = self._run(main())
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
result,
|
||||||
|
{'session': 'ok', 'db': {'connection': 'ok', 'url': 'postgres://...'}},
|
||||||
|
)
|
||||||
|
|
||||||
def test_init_and_shutdown_methods(self):
|
def test_init_and_shutdown_methods(self):
|
||||||
async def _init():
|
async def _init():
|
||||||
await asyncio.sleep(0.001)
|
await asyncio.sleep(0.001)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user