Add prototype

This commit is contained in:
Roman Mogylatov 2020-10-22 22:33:49 -04:00
parent b54bcb7b31
commit 79df45ff48
8 changed files with 10494 additions and 5792 deletions

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,8 @@ class Container:
def resolve_provider_name(self, provider_to_resolve: Provider) -> Optional[str]: ... def resolve_provider_name(self, provider_to_resolve: Provider) -> Optional[str]: ...
def wire(self, modules: Optional[Iterable[ModuleType]] = None, packages: Optional[Iterable[ModuleType]] = None) -> None: ... def wire(self, modules: Optional[Iterable[ModuleType]] = None, packages: Optional[Iterable[ModuleType]] = None) -> None: ...
def unwire(self) -> None: ... def unwire(self) -> None: ...
def init_resources(self) -> None: ...
def shutdown_resources(self) -> None: ...
class DynamicContainer(Container): ... class DynamicContainer(Container): ...

View File

@ -7,6 +7,7 @@ import six
from .errors import Error from .errors import Error
from .providers cimport ( from .providers cimport (
Provider, Provider,
Resource,
deepcopy, deepcopy,
) )
@ -213,6 +214,19 @@ class DynamicContainer(object):
self.wired_to_modules.clear() self.wired_to_modules.clear()
self.wired_to_packages.clear() self.wired_to_packages.clear()
def init_resources(self):
"""Initialize all container resources."""
for provider in self.providers.values():
if not isinstance(provider, Resource):
continue
provider.init()
def shutdown_resources(self):
"""Shutdown all container resources."""
for provider in self.providers.values():
if not isinstance(provider, Resource):
continue
provider.shutdown()
class DeclarativeContainerMetaClass(type): class DeclarativeContainerMetaClass(type):

File diff suppressed because it is too large Load Diff

View File

@ -191,6 +191,21 @@ cdef class Dict(Provider):
cpdef object _provide(self, tuple args, dict kwargs) cpdef object _provide(self, tuple args, dict kwargs)
cdef class Resource(Provider):
cdef object __initializer
cdef bint __initialized
cdef object __shutdowner
cdef object __resource
cdef tuple __args
cdef int __args_len
cdef tuple __kwargs
cdef int __kwargs_len
cpdef object _provide(self, tuple args, dict kwargs)
cdef class Container(Provider): cdef class Container(Provider):
cdef object __container_cls cdef object __container_cls
cdef dict __overriding_providers cdef dict __overriding_providers

View File

@ -13,8 +13,11 @@ from typing import (
Optional, Optional,
Union, Union,
Coroutine as _Coroutine, Coroutine as _Coroutine,
Generator as _Generator,
) )
from . import resources
Injection = Any Injection = Any
T = TypeVar('T') T = TypeVar('T')
@ -274,6 +277,34 @@ class Dict(Provider):
def clear_kwargs(self) -> Dict: ... def clear_kwargs(self) -> Dict: ...
class Resource(Provider, Generic[T]):
def __init__(
self,
initializer: Union[
resources.Resource,
_Generator[T, ..., ...],
_Callable[..., T],
],
*args: Injection,
**kwargs: Injection,
): ...
def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
@property
def args(self) -> Tuple[Injection]: ...
def add_args(self, *args: Injection) -> Resource: ...
def set_args(self, *args: Injection) -> Resource: ...
def clear_args(self) -> Resource: ...
@property
def kwargs(self) -> _Dict[Any, Injection]: ...
def add_kwargs(self, **kwargs: Injection) -> Resource: ...
def set_kwargs(self, **kwargs: Injection) -> Resource: ...
def clear_kwargs(self) -> Resource: ...
@property
def initialized(self) -> bool: ...
def init(self) -> T: ...
def shutdown(self) -> None: ...
class Container(Provider): class Container(Provider):
def __init__(self, container_cls: Type[T], container: Optional[T] = None, **overriding_providers: Provider) -> None: ... def __init__(self, container_cls: Type[T], container: Optional[T] = None, **overriding_providers: Provider) -> None: ...

View File

@ -3,6 +3,8 @@
from __future__ import absolute_import from __future__ import absolute_import
import copy import copy
import contextlib
import inspect
import os import os
import re import re
import sys import sys
@ -37,6 +39,7 @@ from .errors import (
Error, Error,
NoSuchProviderError, NoSuchProviderError,
) )
from . import resources
cimport cython cimport cython
@ -2551,6 +2554,200 @@ cdef class Dict(Provider):
return __provide_keyword_args(kwargs, self.__kwargs, self.__kwargs_len) return __provide_keyword_args(kwargs, self.__kwargs, self.__kwargs_len)
cdef class Resource(Provider):
"""Resource provider provides a component with initialization and shutdown."""
def __init__(self, initializer, *args, **kwargs):
self.__initializer = initializer
self.__initialized = False
self.__resource = None
self.__shutdowner = None
self.__args = tuple()
self.__args_len = 0
self.set_args(*args)
self.__kwargs = tuple()
self.__kwargs_len = 0
self.set_kwargs(**kwargs)
super().__init__()
def __deepcopy__(self, memo):
"""Create and return full copy of provider."""
copied = memo.get(id(self))
if copied is not None:
return copied
if self.__initialized:
raise Error('Can not copy initialized resource')
copied = self.__class__(
self.__initializer,
*deepcopy(self.args, memo),
**deepcopy(self.kwargs, memo),
)
self._copy_overridings(copied, memo)
return copied
def __repr__(self):
return (
f'{self.__class__.__name__}(\'{self.__initializer}\', '
f'initialized={self.__initialized})'
)
@property
def args(self):
"""Return positional argument injections."""
cdef int index
cdef PositionalInjection arg
cdef list args
args = list()
for index in range(self.__args_len):
arg = self.__args[index]
args.append(arg.__value)
return tuple(args)
def add_args(self, *args):
"""Add positional argument injections.
:return: Reference ``self``
"""
self.__args += parse_positional_injections(args)
self.__args_len = len(self.__args)
return self
def set_args(self, *args):
"""Set positional argument injections.
Existing positional argument injections are dropped.
:return: Reference ``self``
"""
self.__args = parse_positional_injections(args)
self.__args_len = len(self.__args)
return self
def clear_args(self):
"""Drop positional argument injections.
:return: Reference ``self``
"""
self.__args = tuple()
self.__args_len = len(self.__args)
return self
@property
def kwargs(self):
"""Return keyword argument injections."""
cdef int index
cdef NamedInjection kwarg
cdef dict kwargs
kwargs = dict()
for index in range(self.__kwargs_len):
kwarg = self.__kwargs[index]
kwargs[kwarg.__name] = kwarg.__value
return kwargs
def add_kwargs(self, **kwargs):
"""Add keyword argument injections.
:return: Reference ``self``
"""
self.__kwargs += parse_named_injections(kwargs)
self.__kwargs_len = len(self.__kwargs)
return self
def set_kwargs(self, **kwargs):
"""Set keyword argument injections.
Existing keyword argument injections are dropped.
:return: Reference ``self``
"""
self.__kwargs = parse_named_injections(kwargs)
self.__kwargs_len = len(self.__kwargs)
return self
def clear_kwargs(self):
"""Drop keyword argument injections.
:return: Reference ``self``
"""
self.__kwargs = tuple()
self.__kwargs_len = len(self.__kwargs)
return self
@property
def initialized(self):
"""Check if resource is initialized."""
return self.__initialized
def init(self):
"""Initialize resource."""
return self.__call__()
def shutdown(self):
"""Shutdown resource."""
if not self.__initialized:
return
if self.__shutdowner:
with contextlib.suppress(StopIteration):
self.__shutdowner(self.__resource)
self.__resource = None
self.__initialized = False
self.__shutdowner = None
cpdef object _provide(self, tuple args, dict kwargs):
if self.__initialized:
return self.__resource
if isinstance(self.__initializer, resources.Resource):
initializer = self.__initializer()
self.__resource = __call(
initializer.init,
args,
self.__args,
self.__args_len,
kwargs,
self.__kwargs,
self.__kwargs_len,
)
self.__shutdowner = initializer.shutdown
elif inspect.isgeneratorfunction(self.__initializer):
initializer = __call(
self.__initializer,
args,
self.__args,
self.__args_len,
kwargs,
self.__kwargs,
self.__kwargs_len,
)
self.__resource = initializer.__next__()
self.__shutdowner = initializer.send
elif callable(self.__initializer):
self.__resource = __call(
self.__initializer,
args,
self.__args,
self.__args_len,
kwargs,
self.__kwargs,
self.__kwargs_len,
)
else:
raise Error('Unknown type of resource initializer')
self.__initialized = True
return self.__resource
cdef class Container(Provider): cdef class Container(Provider):
"""Container provider provides an instance of declarative container. """Container provider provides an instance of declarative container.

View File

@ -0,0 +1,31 @@
"""Resources module."""
import abc
import sys
from typing import Generic, TypeVar
if sys.version_info < (3, 7):
from typing import GenericMeta
else:
class GenericMeta(type):
...
T = TypeVar('T')
class ResourceMeta(GenericMeta, abc.ABCMeta):
def __getitem__(cls, item):
# Spike for Python 3.6
return cls(item)
class Resource(Generic[T], metaclass=ResourceMeta):
@abc.abstractmethod
def init(self, *args, **kwargs) -> T:
...
@abc.abstractmethod
def shutdown(self, resource: T) -> None:
...