from _typeshed import Incomplete as Incomplete
from typing import Any, Awaitable, Callable, Hashable, Optional, Type, TypeVar, Union, overload

logger: Incomplete
Injectable = Union[object, Any]
T = TypeVar('T', bound=Injectable)
Binding = Union[Type[Injectable], Hashable]
Constructor = Callable[[], Injectable]
Provider = Constructor
BinderCallable: Incomplete

class ConstructorTypeError(TypeError):
    def __init__(self, constructor: Callable, previous_error: TypeError) -> None: ...

class Binder:
    def __init__(self) -> None: ...
    def install(self, config: BinderCallable) -> Binder: ...
    def bind(self, cls: Binding, instance: T) -> Binder: ...
    def bind_to_constructor(self, cls: Binding, constructor: Constructor) -> Binder: ...
    def bind_to_provider(self, cls: Binding, provider: Provider) -> Binder: ...

class Injector:
    def __init__(self, config: Optional[BinderCallable] = ..., bind_in_runtime: bool = ...) -> None: ...
    @overload
    def get_instance(self, cls: Type[T]) -> T: ...
    @overload
    def get_instance(self, cls: Hashable) -> Injectable: ...

class InjectorException(Exception): ...

class _ConstructorBinding:
    def __init__(self, constructor: Callable[[], T]) -> None: ...
    def __call__(self) -> T: ...

class _AttributeInjection:
    def __init__(self, cls: Binding) -> None: ...
    def __get__(self, obj: Any, owner: Any) -> Injectable: ...

class _AttributeInjectionDataclass:
    def __init__(self, cls: Binding) -> None: ...
    def __get__(self, instance, owner) -> T: ...

class _ParameterInjection:
    def __init__(self, name: str, cls: Optional[Binding] = ...) -> None: ...
    def __call__(self, func: Callable[..., Union[T, Awaitable[T]]]) -> Callable[..., Union[T, Awaitable[T]]]: ...

class _ParametersInjection:
    def __init__(self, **kwargs: Any) -> None: ...
    def __call__(self, func: Callable[..., Union[Awaitable[T], T]]) -> Callable[..., Union[Awaitable[T], T]]: ...

def configure(config: Optional[BinderCallable] = ..., bind_in_runtime: bool = ...) -> Injector: ...
def configure_once(config: Optional[BinderCallable] = ..., bind_in_runtime: bool = ...) -> Injector: ...
def clear_and_configure(config: Optional[BinderCallable] = ..., bind_in_runtime: bool = ...) -> Injector: ...
def is_configured() -> bool: ...
def clear() -> None: ...
@overload
def instance(cls) -> T: ...
@overload
def instance(cls) -> Injectable: ...
@overload
def attr(cls) -> T: ...
@overload
def attr(cls) -> Injectable: ...
@overload
def attr_dc(cls) -> T: ...
@overload
def attr_dc(cls) -> Injectable: ...
def param(name: str, cls: Optional[Binding] = ...) -> Callable: ...
def params(**args_to_classes: Binding) -> Callable: ...
def autoparams(*selected: str) -> Callable: ...
def get_injector() -> Optional[Injector]: ...
def get_injector_or_die() -> Injector: ...
