Repository: reagento/dishka
Pull request #199 (2024-08-07 21:22:19)

add tests and fix check object is GenericAlias


Patch:
diff --git a/src/dishka/entities/with_parents.py b/src/dishka/entities/with_parents.py
index b4c5a7d..d2b133c 100644
--- a/src/dishka/entities/with_parents.py
+++ b/src/dishka/entities/with_parents.py
@@ -1,6 +1,5 @@
 from abc import ABC, ABCMeta
 from enum import Enum
-from types import GenericAlias
 from typing import (
     TYPE_CHECKING,
     Final,
@@ -15,7 +14,7 @@ from dishka._adaptix.feature_requirement import HAS_PY_311
 from dishka._adaptix.type_tools import (
     get_generic_args,
     get_type_vars,
-    is_generic,
+    is_parametrized,
     strip_alias,
 )
 from dishka.entities.provides_marker import ProvideMultiple
@@ -92,15 +91,17 @@ def create_type_vars_map(obj: TypeHint) -> TypeVarsMap:
     return type_vars_map
 
 
-def create_generic_class(
-    origin_obj: TypeHint,
+def create_type(
+    obj: TypeHint,
     type_vars_map: TypeVarsMap,
-) -> TypeHint | None:
-    if not is_generic(origin_obj):
-        return None
+) -> TypeHint:
+    origin_obj = strip_alias(obj)
+    type_vars = get_type_vars(origin_obj) or get_type_vars(obj)
+    if not type_vars:
+        return origin_obj
 
     generic_args = []
-    for type_var in get_type_vars(origin_obj):
+    for type_var in type_vars:
         arg = type_vars_map[type_var]
         if isinstance(arg, list):
             generic_args.extend(arg)
@@ -115,9 +116,6 @@ def recursion_get_parents_for_generic_class(
     type_vars_map: TypeVarsMap,
 ) -> None:
     origin_obj = strip_alias(obj)
-    if is_ignored_type(origin_obj):
-        return
-
     if not has_orig_bases(origin_obj):
         parents.extend(get_parents_for_mro(origin_obj))
         return
@@ -128,7 +126,7 @@ def recursion_get_parents_for_generic_class(
             continue
 
         type_vars_map.update(create_type_vars_map(obj_))
-        parents.append(create_generic_class(origin_obj, type_vars_map) or obj_)
+        parents.append(create_type(obj_, type_vars_map))
         recursion_get_parents_for_generic_class(
             obj_,
             parents,
@@ -147,13 +145,13 @@ def get_parents(obj: TypeHint) -> list[TypeHint]:
     if is_ignored_type(strip_alias(obj)):
         raise ValueError(f"The starting class {obj!r} is in ignored types")
 
-    if isinstance(obj, GenericAlias):
+    if is_parametrized(obj):
         type_vars_map = create_type_vars_map(obj)
         parents = [
-            create_generic_class(
-                origin_obj=strip_alias(obj),
+            create_type(
+                obj=obj,
                 type_vars_map=type_vars_map,
-            ) or obj,
+            ),
         ]
         recursion_get_parents_for_generic_class(
             obj=obj,


Test patch:
diff --git a/tests/unit/container/test_with_parents.py b/tests/unit/container/test_with_parents.py
index abb3e40..eb24e50 100644
--- a/tests/unit/container/test_with_parents.py
+++ b/tests/unit/container/test_with_parents.py
@@ -11,7 +11,12 @@ from dishka import (
     make_container,
 )
 from dishka._adaptix.feature_requirement import HAS_PY_311
-from dishka.entities.with_parents import WithParents
+from dishka.entities.with_parents import (
+    WithParents,
+    get_filled_arguments,
+    get_parents,
+    is_type_var_tuple,
+)
 from dishka.exceptions import NoFactoryError
 
 if HAS_PY_311:
@@ -23,6 +28,14 @@ T = TypeVar("T")
 B = TypeVar("B")
 
 
+@pytest.mark.skipif(
+    not HAS_PY_311,
+    reason="test for python >= 3.11",
+)
+def test_is_type_var_tuple() -> None:
+    assert is_type_var_tuple(Unpack[Ts])
+
+
 def test_simple_inheritance() -> None:
     class A1: ...
     class A2(A1): ...
@@ -60,7 +73,7 @@ def test_ignore_parent_type(obj: Any, value: Any, component: Any) -> None:
 
 
 def test_type_var() -> None:
-    class A1(Generic[T]): ...
+    class A1(Protocol[T]): ...
     class A2(A1[str]): ...
 
     provider = Provider(scope=Scope.APP)
@@ -116,7 +129,7 @@ else:
 )
 @pytest.mark.skipif(
     not HAS_PY_311,
-reason="test for python >= 3.11",
+    reason="test for python >= 3.11",
 )
 def test_type_var_and_type_var_tuple(
     obj: Any,
@@ -159,3 +172,31 @@ def test_deep_inheritance() -> None:
         is container.get(B1)
         is container.get(D1)
     )
+
+
+def test_get_parents_by_generic_alias() -> None:
+    class A1(Generic[T], float): ...
+    class A2(A1[T], Generic[T]): ...
+
+    provider = Provider(scope=Scope.APP)
+    provider.provide(lambda: A2(), provides=WithParents[A2[int]])
+    container = make_container(provider)
+
+    assert (
+        container.get(A2[int])
+        is container.get(A1[int])
+        is container.get(float)
+    )
+
+def test_using_ignoring_type() -> None:
+    with pytest.raises(ValueError):  # noqa: PT011
+        get_parents(object)
+
+@pytest.mark.skipif(
+    not HAS_PY_311,
+    reason="test for python >= 3.11",
+)
+def test_ignore_get_filled_arguments() -> None:
+    class Test(Generic[T, Unpack[Ts]]): ...
+
+    assert not get_filled_arguments(Test[T, Unpack[Ts]])