python-dependency-injector/src/dependency_injector/providers.pxd
Roman Mogylatov 07d4f7e74f
Develop 4.0 (#298)
* 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
2020-10-09 15:16:27 -04:00

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