Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions tests/typing/aggregate.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from dependency_injector import providers
from typing_extensions import assert_type, Any


class Animal: ...
Expand All @@ -8,29 +9,36 @@ class Cat(Animal): ...


# Test 1: to check Aggregate provider
provider1: providers.Aggregate[str] = providers.Aggregate(
provider1 = providers.Aggregate(
a=providers.Object("str1"),
b=providers.Object("str2"),
)
provider_a_1: providers.Provider[str] = provider1.a
provider_a_1 = provider1.a
provider_b_1: providers.Provider[str] = provider1.b
val1: str = provider1("a")
val1 = provider1("a")
assert_type(provider1, providers.Aggregate[str])
assert_type(provider_a_1, providers.Provider[str])
assert_type(provider_b_1, providers.Provider[str])
assert_type(val1, str)

provider1_set_non_string_keys: providers.Aggregate[str] = providers.Aggregate()
provider1_set_non_string_keys = providers.Aggregate[str]()
provider1_set_non_string_keys.set_providers({Cat: providers.Object("str")})
provider_set_non_string_1: providers.Provider[str] = (
provider1_set_non_string_keys.providers[Cat]
)
provider_set_non_string_1 = provider1_set_non_string_keys.providers[Cat]
assert_type(provider_set_non_string_1, providers.Provider[str])


provider1_new_non_string_keys: providers.Aggregate[str] = providers.Aggregate(
# TODO: Change providers.Aggregate to accept Mapping? Then remove explicit typing here
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current stub:

class Aggregate(Provider[T]): def __init__( self, provider_dict: Optional[_Dict[Any, Provider[T]]] = None, **provider_kwargs: Provider[T], ): ...

I think we should accept collections.abc.Mapping here

class Aggregate(Provider[T]): def __init__( self, provider_dict: Optional[Mapping[Any, Provider[T]]] = None, **provider_kwargs: Provider[T], ): ...

Because Dict is invariant in both key and value, so providers.Aggregate cannot infer its own typevar without explicit typing

provider1_new_non_string_keys = providers.Aggregate( {Cat: providers.Object("str")}, ) # This raises mypy error
provider1_new_non_string_keys = providers.Aggregate[str](
{Cat: providers.Object("str")},
)
factory_new_non_string_1: providers.Provider[str] = (
provider1_new_non_string_keys.providers[Cat]
)
factory_new_non_string_1 = provider1_new_non_string_keys.providers[Cat]
assert_type(provider1_new_non_string_keys, providers.Aggregate[str])
assert_type(factory_new_non_string_1, providers.Provider[str])


provider1_no_explicit_typing = providers.Aggregate(a=providers.Object("str"))
provider1_no_explicit_typing_factory: providers.Provider[str] = (
provider1_no_explicit_typing.providers["a"]
)
provider1_no_explicit_typing_object: str = provider1_no_explicit_typing("a")
provider1_no_explicit_typing_factory = provider1_no_explicit_typing.providers["a"]
provider1_no_explicit_typing_object = provider1_no_explicit_typing("a")

assert_type(provider1_no_explicit_typing_factory, providers.Provider[str])
assert_type(provider1_no_explicit_typing_object, str)
53 changes: 34 additions & 19 deletions tests/typing/callable.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Any, Callable, Dict, Optional, Tuple, Type
from typing import Any, Callable, Dict, Optional, Tuple
from typing_extensions import assert_type

from dependency_injector import providers

Expand All @@ -7,19 +8,20 @@ class Animal: ...


class Cat(Animal):

@classmethod
def create(cls) -> Animal:
return cls()


# Test 1: to check the return type (class)
provider1 = providers.Callable(Cat)
animal1: Animal = provider1(1, 2, 3, b="1", c=2, e=0.0)
cat1 = provider1(1, 2, 3, b="1", c=2, e=0.0)
assert_type(cat1, Cat)

# Test 2: to check the return type (class factory method)
provider2 = providers.Callable(Cat.create)
animal2: Animal = provider2()
animal2 = provider2()
assert_type(animal2, Animal)

# Test 3: to check the .override() method
provider3 = providers.Callable(Animal)
Expand All @@ -28,24 +30,34 @@ def create(cls) -> Animal:

# Test 4: to check the .args & .kwargs attributes
provider4 = providers.Callable(Animal)
args4: Tuple[Any] = provider4.args
kwargs4: Dict[str, Any] = provider4.kwargs
args4 = provider4.args
kwargs4 = provider4.kwargs
assert_type(args4, Tuple[Any])
# TODO: Change Callable.kwargs to Dict[str, Any]? Then adjust test back to Dict[str, Any]
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stub actually declares provider4.kwargs to return Dict[Any, Any], not Dict[str, Any] like the previous test probably intended to check.

But I think we can safely change it to return Dict[str, Any] in the stub.

assert_type(kwargs4, Dict[Any, Any])

# Test 5: to check the provided instance interface
provider5 = providers.Callable(Animal)
provided5: Animal = provider5.provided()
attr_getter5: providers.AttributeGetter = provider5.provided.attr
item_getter5: providers.ItemGetter = provider5.provided["item"]
method_caller: providers.MethodCaller = provider5.provided.method.call(123, arg=324)
provided_val5 = provider5.provided()
attr_getter5 = provider5.provided.attr
item_getter5 = provider5.provided["item"]
method_caller5 = provider5.provided.method.call(123, arg=324)
# TODO: Remove explicit typing of Provider.provided return type
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stub is this

 @property def provided(self) -> ProvidedInstance[T]: ...

But ProvidedInstance is not declared to be generic

class ProvidedInstance(Provider, ProvidedInstanceFluentInterface): def __init__(self, provides: Optional[Provider] = None) -> None: ...

I think we can make the quick fix to

 @property def provided(self) -> ProvidedInstance: ...
assert_type(provided_val5, Any)
assert_type(attr_getter5, providers.AttributeGetter)
assert_type(item_getter5, providers.ItemGetter)
assert_type(method_caller5, providers.MethodCaller)

# Test 6: to check the DelegatedCallable
provider6 = providers.DelegatedCallable(Cat)
animal6: Animal = provider6(1, 2, 3, b="1", c=2, e=0.0)
cat6 = provider6(1, 2, 3, b="1", c=2, e=0.0)
assert_type(cat6, Cat)

# Test 7: to check the AbstractCallable
provider7 = providers.AbstractCallable(Animal)
provider7.override(providers.Callable(Cat))
animal7: Animal = provider7(1, 2, 3, b="1", c=2, e=0.0)
animal7 = provider7(1, 2, 3, b="1", c=2, e=0.0)
assert_type(animal7, Animal)

# Test 8: to check the CallableDelegate __init__
provider8 = providers.CallableDelegate(providers.Callable(lambda: None))
Expand All @@ -55,20 +67,23 @@ def create(cls) -> Animal:


async def _async9() -> None:
animal1: Animal = await provider9(1, 2, 3, b="1", c=2, e=0.0) # type: ignore
animal2: Animal = await provider9.async_(1, 2, 3, b="1", c=2, e=0.0)
await provider9(1, 2, 3, b="1", c=2, e=0.0) # type: ignore[misc]
cat9 = await provider9.async_(1, 2, 3, b="1", c=2, e=0.0)
assert_type(cat9, Cat)


# Test 10: to check the .provides
provider10 = providers.Callable(Cat)
provides10: Optional[Callable[..., Cat]] = provider10.provides
assert provides10 is Cat
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these assert statements are not doing anything

provides10 = provider10.provides
assert_type(provides10, Optional[Callable[..., Cat]])

# Test 11: to check the .provides for explicit typevar
provider11 = providers.Callable[Animal](Cat)
provides11: Optional[Callable[..., Animal]] = provider11.provides
assert provides11 is Cat
provides11 = provider11.provides
assert_type(provides11, Optional[Callable[..., Animal]])


# Test 12: to check string imports
provider12: providers.Callable[Dict[Any, Any]] = providers.Callable("builtins.dict")
# TODO: Use T_Any as Callable typevar? Then remove type-ignore
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't infer typevar without explicit typing, mypy raises error here, but we can change it to typevar with default Any to fix it

provider12 = providers.Callable("builtins.dict") # type: ignore[var-annotated]
provider12.set_provides("builtins.dict")