mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-02-20 13:30:54 +03:00
* Add wiring (#294) * Add wiring module * Fix code style * Fix package test * Add version fix * Try spike for 3.6 * Try another fix with metaclass * Downsample required version to 3.6 * Introduce concept with annotations * Fix bugs * Add debug message * Add extra tests * Add extra debugging * Update config resolving * Remove 3.6 generic meta fix * Fix Flake8 * Add spike for 3.6 * Add Python 3.6 spike * Add unwire functionality * Add support of corouting functions * Bump version to 4.0 * Updaet demo example * Add pydocstyle ignore for demo * Add flake8 ignore for demo * Update aiohttp example * Update flask example * Rename aiohttp example directory * Rename views module to handlers in aiohttp example * Add sanic example * Remove not needed images * Update demo * Implement wiring for Provide[foo.provider] * Implement Provide[foo.provided.bar.baz.call()] * Make flake8 happy * Wiring refactoring (#296) * Refactor wiring * Add todos to wiring * Implement wiring of config invariant * Implement sub containers wiring + add tests * Add test for wiring config invariant * Add container.unwire() typing stub * Deprecate ext package modules and remove types module * Deprecate provider.delegate() method * Add __all__ for wiring module * Add protection for wiring only declarative container instances * Bump version to 4.0.0a2 * Add wiring docs * Add wiring of class methods * Remove unused import * Add a note on individuals import to wiring docs * Add minor improvement to wiring doc * Update DI in Python page * Update key features * Update README concep and FAQ * Add files via upload * Update README.rst * Update README.rst * Update README.rst * Update docs index page * Update README * Remove API docs for flask and aiohttp ext * Add wiring API docs * Update docs index * Update README * Update readme and docs index * Change wording in README * Django example (#297) * Add rough django example * Remove sqlite db * Add gitignore * Fix flake8 and pydocstyle errors * Add tests * Refactor settings * Move web app to to the root of the project * Add bootstrap 4 * Add doc blocks for web app * Add coverage * Fix typo in flask * Remove not needed newlines * Add screenshot * Update django app naming * Add django example to the docs * Update changelog * Update Aiohttp example * Add sanic example to the docs * Make a little fix in django example docs page * Add flask example to the docs * Add aiohttp example to the docs * Update installation docs page * Fix .delegate() deprecation * Refactor movie lister to use wiring * Make micro cosmetic changes to flask, aiohttp & sanic examples * Refactor single container example to use wiring * Refactor multiple container example to use wiring * Add return type to main() in application examples * Refactor decoupled packages example to use wiring * Refactor code layout for DI demo example * Update wiring feature message * Add more links to the examples * Change code layout in miniapps * Update sanic example * Update miniapp READMEs * Update wiring docs * Refactor part of cli tutorial * Refactor CLI app tutorial * Update test coverage results in movie lister example and tutorial * Make some minor updates to aiohttp and cli tutorials * Refactor flask tutorial * Make cosmetic fix in flask example * Refactor Flask tutorial: Connect to the GitHub * Refactor Flask tutorial: Search service * Refactor Flask tutorial: Inject search service into view * Refactor Flask tutorial: Make some refactoring * Finish flask tutorial refactoring * Update tutorials * Refactor asyncio monitoring daemon example application * Fix tutorial links * Rename asyncio miniapp * Rename tutorial image dirs * Rename api docs tol-level page * Refactor initial sections of asyncio daemon tutorial * Refactor asyncio tutorial till Example.com monitor section * Refactor asyncio tutorial example.com monitor section * Refactor asyncio tutorial httpbin.org monitor tutorial * Refactor tests section of asyncio daemon tutorial * Update conclusion of asyncio daemon tutorial * Rename tutorial images * Make cosmetic update to flask tutorial * Refactor aiohttp tutorial: Minimal application section * Refactor aiohttp tutorial: Giphy API client secion * Refactor aiohttp tutorial secion: Make the search work * Refactor aiohttp tutorial tests section * Refactor aiohttp tutorial conclusion * Upgrade Cython to 0.29.21 * Update changelog * Update demo example * Update wording on index pages * Update changelog * Update code layout for main demo
436 lines
9.0 KiB
Cython
436 lines
9.0 KiB
Cython
"""Providers module."""
|
|
|
|
cimport cython
|
|
|
|
|
|
# Base providers
|
|
cdef class Provider(object):
|
|
cdef tuple __overridden
|
|
cdef Provider __last_overriding
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
cpdef void _copy_overridings(self, Provider copied, dict memo)
|
|
|
|
|
|
cdef class Object(Provider):
|
|
cdef object __provides
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class Delegate(Provider):
|
|
cdef object __provides
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class Dependency(Provider):
|
|
cdef object __instance_of
|
|
|
|
|
|
cdef class ExternalDependency(Dependency):
|
|
pass
|
|
|
|
|
|
cdef class DependenciesContainer(Object):
|
|
cdef dict __providers
|
|
|
|
cpdef object _override_providers(self, object container)
|
|
|
|
|
|
cdef class OverridingContext(object):
|
|
cdef Provider __overridden
|
|
cdef Provider __overriding
|
|
|
|
|
|
# Callable providers
|
|
cdef class Callable(Provider):
|
|
cdef object __provides
|
|
|
|
cdef tuple __args
|
|
cdef int __args_len
|
|
|
|
cdef tuple __kwargs
|
|
cdef int __kwargs_len
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class DelegatedCallable(Callable):
|
|
pass
|
|
|
|
|
|
cdef class AbstractCallable(Callable):
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class CallableDelegate(Delegate):
|
|
pass
|
|
|
|
|
|
# Coroutine providers
|
|
cdef class Coroutine(Callable):
|
|
pass
|
|
|
|
|
|
cdef class DelegatedCoroutine(Coroutine):
|
|
pass
|
|
|
|
|
|
cdef class AbstractCoroutine(Coroutine):
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class CoroutineDelegate(Delegate):
|
|
pass
|
|
|
|
|
|
# Configuration providers
|
|
cdef class ConfigurationOption(Provider):
|
|
cdef tuple __name
|
|
cdef object __root_ref
|
|
cdef dict __children
|
|
cdef object __cache
|
|
|
|
|
|
cdef class TypedConfigurationOption(Callable):
|
|
pass
|
|
|
|
|
|
cdef class Configuration(Object):
|
|
cdef str __name
|
|
cdef dict __children
|
|
cdef object __weakref__
|
|
|
|
|
|
# Factory providers
|
|
cdef class Factory(Provider):
|
|
cdef Callable __instantiator
|
|
|
|
cdef tuple __attributes
|
|
cdef int __attributes_len
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class DelegatedFactory(Factory):
|
|
pass
|
|
|
|
|
|
cdef class AbstractFactory(Factory):
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class FactoryDelegate(Delegate):
|
|
pass
|
|
|
|
|
|
cdef class FactoryAggregate(Provider):
|
|
cdef dict __factories
|
|
|
|
cdef Factory __get_factory(self, str factory_name)
|
|
|
|
|
|
# Singleton providers
|
|
cdef class BaseSingleton(Provider):
|
|
cdef Factory __instantiator
|
|
|
|
|
|
cdef class Singleton(BaseSingleton):
|
|
cdef object __storage
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class DelegatedSingleton(Singleton):
|
|
pass
|
|
|
|
|
|
cdef class ThreadSafeSingleton(BaseSingleton):
|
|
cdef object __storage
|
|
cdef object __storage_lock
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
|
|
pass
|
|
|
|
|
|
cdef class ThreadLocalSingleton(BaseSingleton):
|
|
cdef object __storage
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
|
|
pass
|
|
|
|
|
|
cdef class AbstractSingleton(BaseSingleton):
|
|
pass
|
|
|
|
|
|
cdef class SingletonDelegate(Delegate):
|
|
pass
|
|
|
|
|
|
# Miscellaneous providers
|
|
|
|
cdef class List(Provider):
|
|
cdef tuple __args
|
|
cdef int __args_len
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class Container(Provider):
|
|
cdef object __container_cls
|
|
cdef dict __overriding_providers
|
|
cdef object __container
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class Selector(Provider):
|
|
cdef object __selector
|
|
cdef dict __providers
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
# Provided instance
|
|
|
|
cdef class ProvidedInstance(Provider):
|
|
cdef Provider __provider
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class AttributeGetter(Provider):
|
|
cdef Provider __provider
|
|
cdef object __attribute
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class ItemGetter(Provider):
|
|
cdef Provider __provider
|
|
cdef object __item
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
cdef class MethodCaller(Provider):
|
|
cdef Provider __provider
|
|
cdef tuple __args
|
|
cdef int __args_len
|
|
cdef tuple __kwargs
|
|
cdef int __kwargs_len
|
|
|
|
cpdef object _provide(self, tuple args, dict kwargs)
|
|
|
|
|
|
# Injections
|
|
cdef class Injection(object):
|
|
cdef object __value
|
|
cdef int __is_provider
|
|
cdef int __is_delegated
|
|
cdef int __call
|
|
|
|
|
|
cdef class PositionalInjection(Injection):
|
|
pass
|
|
|
|
|
|
cdef class NamedInjection(Injection):
|
|
cdef object __name
|
|
|
|
|
|
cpdef tuple parse_positional_injections(tuple args)
|
|
|
|
|
|
cpdef tuple parse_named_injections(dict kwargs)
|
|
|
|
|
|
# Utils
|
|
cdef object CLASS_TYPES
|
|
|
|
|
|
cpdef bint is_provider(object instance)
|
|
|
|
|
|
cpdef object ensure_is_provider(object instance)
|
|
|
|
|
|
cpdef bint is_delegated(object instance)
|
|
|
|
|
|
cpdef str represent_provider(object provider, object provides)
|
|
|
|
|
|
cpdef object deepcopy(object instance, dict memo=*)
|
|
|
|
|
|
# Inline helper functions
|
|
cdef inline object __get_name(NamedInjection self):
|
|
return self.__name
|
|
|
|
|
|
cdef inline object __get_value(Injection self):
|
|
if self.__call == 0:
|
|
return self.__value
|
|
return self.__value()
|
|
|
|
|
|
cdef inline object __get_value_kwargs(Injection self, dict kwargs):
|
|
if self.__call == 0:
|
|
return self.__value
|
|
return self.__value(**kwargs)
|
|
|
|
|
|
cdef inline tuple __separate_prefixed_kwargs(dict kwargs):
|
|
cdef dict plain_kwargs = {}
|
|
cdef dict prefixed_kwargs = {}
|
|
|
|
for key, value in kwargs.items():
|
|
if '__' not in key:
|
|
plain_kwargs[key] = value
|
|
continue
|
|
|
|
index = key.index('__')
|
|
prefix, name = key[:index], key[index+2:]
|
|
|
|
if prefix not in prefixed_kwargs:
|
|
prefixed_kwargs[prefix] = {}
|
|
prefixed_kwargs[prefix][name] = value
|
|
|
|
return plain_kwargs, prefixed_kwargs
|
|
|
|
|
|
@cython.boundscheck(False)
|
|
@cython.wraparound(False)
|
|
cdef inline tuple __provide_positional_args(
|
|
tuple args,
|
|
tuple inj_args,
|
|
int inj_args_len,
|
|
):
|
|
cdef int index
|
|
cdef list positional_args
|
|
cdef PositionalInjection injection
|
|
|
|
if inj_args_len == 0:
|
|
return args
|
|
|
|
positional_args = list()
|
|
for index in range(inj_args_len):
|
|
injection = <PositionalInjection>inj_args[index]
|
|
positional_args.append(__get_value(injection))
|
|
positional_args.extend(args)
|
|
|
|
return tuple(positional_args)
|
|
|
|
|
|
@cython.boundscheck(False)
|
|
@cython.wraparound(False)
|
|
cdef inline dict __provide_keyword_args(
|
|
dict kwargs,
|
|
tuple inj_kwargs,
|
|
int inj_kwargs_len,
|
|
):
|
|
cdef int index
|
|
cdef object name
|
|
cdef object value
|
|
cdef dict prefixed
|
|
cdef NamedInjection kw_injection
|
|
|
|
if len(kwargs) == 0:
|
|
for index in range(inj_kwargs_len):
|
|
kw_injection = <NamedInjection>inj_kwargs[index]
|
|
name = __get_name(kw_injection)
|
|
kwargs[name] = __get_value(kw_injection)
|
|
else:
|
|
kwargs, prefixed = __separate_prefixed_kwargs(kwargs)
|
|
|
|
|
|
for index in range(inj_kwargs_len):
|
|
kw_injection = <NamedInjection>inj_kwargs[index]
|
|
name = __get_name(kw_injection)
|
|
|
|
if name in kwargs:
|
|
continue
|
|
|
|
if name in prefixed:
|
|
value = __get_value_kwargs(kw_injection, prefixed[name])
|
|
else:
|
|
value = __get_value(kw_injection)
|
|
|
|
kwargs[name] = value
|
|
|
|
return kwargs
|
|
|
|
|
|
@cython.boundscheck(False)
|
|
@cython.wraparound(False)
|
|
cdef inline object __inject_attributes(
|
|
object instance,
|
|
tuple attributes,
|
|
int attributes_len,
|
|
):
|
|
cdef NamedInjection attr_injection
|
|
for index in range(attributes_len):
|
|
attr_injection = <NamedInjection>attributes[index]
|
|
setattr(instance,
|
|
__get_name(attr_injection),
|
|
__get_value(attr_injection))
|
|
|
|
|
|
cdef inline object __call(
|
|
object call,
|
|
tuple context_args,
|
|
tuple injection_args,
|
|
int injection_args_len,
|
|
dict kwargs,
|
|
tuple injection_kwargs,
|
|
int injection_kwargs_len,
|
|
):
|
|
cdef tuple positional_args
|
|
cdef dict keyword_args
|
|
|
|
positional_args = __provide_positional_args(
|
|
context_args,
|
|
injection_args,
|
|
injection_args_len,
|
|
)
|
|
keyword_args = __provide_keyword_args(
|
|
kwargs,
|
|
injection_kwargs,
|
|
injection_kwargs_len,
|
|
)
|
|
|
|
return call(*positional_args, **keyword_args)
|
|
|
|
|
|
cdef inline object __callable_call(Callable self, tuple args, dict kwargs):
|
|
return __call(
|
|
self.__provides,
|
|
args,
|
|
self.__args,
|
|
self.__args_len,
|
|
kwargs,
|
|
self.__kwargs,
|
|
self.__kwargs_len,
|
|
)
|
|
|
|
|
|
cdef inline object __factory_call(Factory self, tuple args, dict kwargs):
|
|
cdef object instance
|
|
|
|
instance = __callable_call(self.__instantiator, args, kwargs)
|
|
|
|
if self.__attributes_len > 0:
|
|
__inject_attributes(instance,
|
|
self.__attributes,
|
|
self.__attributes_len)
|
|
|
|
return instance
|