We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Allow using tuple (and/or iterable) as an alias to the GraphQL type
## Feature Request Type

Alteration (enhancement/optimization) of existing feature(s)

## Description

Returning a `tuple` when the attribute is hinted as `list` [works](https://play.strawberry.rocks/?gist=0815d1a1f0c58a613bd356cbeb45c8a1).

But hinting the return type _correctly as a tuple_ causes an error:

```python
@strawberry.type
class Dictionary:
    entries: tuple[Entry]
    sources: tuple[Source]
```

```
TypeError: Unexpected type tuple[Entry]
```

Our code uses tuples and iterables whenever appropriate for robustness, efficiency, and documentation. We also use strict type hinting. It'd be great for these read-only sequences to be explicitly supported.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `strawberry/annotation.py`
Content:
```
1 import sys
2 import typing
3 from collections import abc
4 from enum import Enum
5 from typing import (  # type: ignore[attr-defined]
6     TYPE_CHECKING,
7     Any,
8     Dict,
9     List,
10     Optional,
11     TypeVar,
12     Union,
13     _eval_type,
14 )
15 
16 from typing_extensions import Annotated, get_args, get_origin
17 
18 from strawberry.private import is_private
19 
20 
21 try:
22     from typing import ForwardRef
23 except ImportError:  # pragma: no cover
24     # ForwardRef is private in python 3.6 and 3.7
25     from typing import _ForwardRef as ForwardRef  # type: ignore
26 
27 from strawberry.custom_scalar import ScalarDefinition
28 from strawberry.enum import EnumDefinition
29 from strawberry.lazy_type import LazyType, StrawberryLazyReference
30 from strawberry.type import (
31     StrawberryList,
32     StrawberryOptional,
33     StrawberryType,
34     StrawberryTypeVar,
35 )
36 from strawberry.types.types import TypeDefinition
37 from strawberry.unset import UNSET
38 from strawberry.utils.typing import is_generic, is_list, is_type_var, is_union
39 
40 
41 if TYPE_CHECKING:
42     from strawberry.union import StrawberryUnion
43 
44 
45 ASYNC_TYPES = (
46     abc.AsyncGenerator,
47     abc.AsyncIterable,
48     abc.AsyncIterator,
49     typing.AsyncContextManager,
50     typing.AsyncGenerator,
51     typing.AsyncIterable,
52     typing.AsyncIterator,
53 )
54 
55 
56 class StrawberryAnnotation:
57     def __init__(
58         self, annotation: Union[object, str], *, namespace: Optional[Dict] = None
59     ):
60         self.annotation = annotation
61         self.namespace = namespace
62 
63     def __eq__(self, other: object) -> bool:
64         if not isinstance(other, StrawberryAnnotation):
65             return NotImplemented
66 
67         return self.resolve() == other.resolve()
68 
69     @staticmethod
70     def parse_annotated(annotation: object) -> object:
71         from strawberry.auto import StrawberryAuto
72 
73         if get_origin(annotation) is Annotated:
74             annotated_args = get_args(annotation)
75             annotation_type = annotated_args[0]
76 
77             for arg in annotated_args[1:]:
78                 if isinstance(arg, StrawberryLazyReference):
79                     assert isinstance(annotation_type, ForwardRef)
80 
81                     return arg.resolve_forward_ref(annotation_type)
82 
83                 if isinstance(arg, StrawberryAuto):
84                     return arg
85 
86             return StrawberryAnnotation.parse_annotated(annotation_type)
87 
88         if is_union(annotation):
89             return Union[
90                 tuple(
91                     StrawberryAnnotation.parse_annotated(arg)
92                     for arg in get_args(annotation)
93                 )  # pyright: ignore
94             ]  # pyright: ignore
95 
96         if is_list(annotation):
97             return List[StrawberryAnnotation.parse_annotated(get_args(annotation)[0])]  # type: ignore  # noqa: E501
98 
99         return annotation
100 
101     def resolve(self) -> Union[StrawberryType, type]:
102         annotation = self.parse_annotated(self.annotation)
103 
104         if isinstance(self.annotation, str):
105             annotation = ForwardRef(self.annotation)
106 
107         evaled_type = _eval_type(annotation, self.namespace, None)
108 
109         if is_private(evaled_type):
110             return evaled_type
111         if self._is_async_type(evaled_type):
112             evaled_type = self._strip_async_type(evaled_type)
113         if self._is_lazy_type(evaled_type):
114             return evaled_type
115 
116         if self._is_generic(evaled_type):
117             if any(is_type_var(type_) for type_ in evaled_type.__args__):
118                 return evaled_type
119             return self.create_concrete_type(evaled_type)
120 
121         # Simply return objects that are already StrawberryTypes
122         if self._is_strawberry_type(evaled_type):
123             return evaled_type
124 
125         # Everything remaining should be a raw annotation that needs to be turned into
126         # a StrawberryType
127         if self._is_enum(evaled_type):
128             return self.create_enum(evaled_type)
129         if self._is_list(evaled_type):
130             return self.create_list(evaled_type)
131         elif self._is_optional(evaled_type):
132             return self.create_optional(evaled_type)
133         elif self._is_union(evaled_type):
134             return self.create_union(evaled_type)
135         elif is_type_var(evaled_type):
136             return self.create_type_var(evaled_type)
137 
138         # TODO: Raise exception now, or later?
139         # ... raise NotImplementedError(f"Unknown type {evaled_type}")
140         return evaled_type
141 
142     def create_concrete_type(self, evaled_type: type) -> type:
143         if _is_object_type(evaled_type):
144             type_definition: TypeDefinition
145             type_definition = evaled_type._type_definition  # type: ignore
146             return type_definition.resolve_generic(evaled_type)
147 
148         raise ValueError(f"Not supported {evaled_type}")
149 
150     def create_enum(self, evaled_type: Any) -> EnumDefinition:
151         return evaled_type._enum_definition
152 
153     def create_list(self, evaled_type: Any) -> StrawberryList:
154         of_type = StrawberryAnnotation(
155             annotation=evaled_type.__args__[0],
156             namespace=self.namespace,
157         ).resolve()
158 
159         return StrawberryList(of_type)
160 
161     def create_optional(self, evaled_type: Any) -> StrawberryOptional:
162         types = evaled_type.__args__
163         non_optional_types = tuple(
164             filter(
165                 lambda x: x is not type(None) and x is not type(UNSET),  # noqa: E721
166                 types,
167             )
168         )
169 
170         # Note that passing a single type to `Union` is equivalent to not using `Union`
171         # at all. This allows us to not di any checks for how many types have been
172         # passed as we can safely use `Union` for both optional types
173         # (e.g. `Optional[str]`) and optional unions (e.g.
174         # `Optional[Union[TypeA, TypeB]]`)
175         child_type = Union[non_optional_types]  # type: ignore
176 
177         of_type = StrawberryAnnotation(
178             annotation=child_type,
179             namespace=self.namespace,
180         ).resolve()
181 
182         return StrawberryOptional(of_type)
183 
184     def create_type_var(self, evaled_type: TypeVar) -> StrawberryTypeVar:
185         return StrawberryTypeVar(evaled_type)
186 
187     def create_union(self, evaled_type) -> "StrawberryUnion":
188         # Prevent import cycles
189         from strawberry.union import StrawberryUnion
190 
191         # TODO: Deal with Forward References/origin
192         if isinstance(evaled_type, StrawberryUnion):
193             return evaled_type
194 
195         types = evaled_type.__args__
196         union = StrawberryUnion(
197             type_annotations=tuple(StrawberryAnnotation(type_) for type_ in types),
198         )
199         return union
200 
201     @classmethod
202     def _is_async_type(cls, annotation: type) -> bool:
203         origin = getattr(annotation, "__origin__", None)
204         return origin in ASYNC_TYPES
205 
206     @classmethod
207     def _is_enum(cls, annotation: Any) -> bool:
208         # Type aliases are not types so we need to make sure annotation can go into
209         # issubclass
210         if not isinstance(annotation, type):
211             return False
212         return issubclass(annotation, Enum)
213 
214     @classmethod
215     def _is_generic(cls, annotation: Any) -> bool:
216         if hasattr(annotation, "__origin__"):
217             return is_generic(annotation.__origin__)
218 
219         return False
220 
221     @classmethod
222     def _is_lazy_type(cls, annotation: Any) -> bool:
223         return isinstance(annotation, LazyType)
224 
225     @classmethod
226     def _is_optional(cls, annotation: Any) -> bool:
227         """Returns True if the annotation is Optional[SomeType]"""
228 
229         # Optionals are represented as unions
230         if not cls._is_union(annotation):
231             return False
232 
233         types = annotation.__args__
234 
235         # A Union to be optional needs to have at least one None type
236         return any(x is type(None) for x in types)  # noqa: E721
237 
238     @classmethod
239     def _is_list(cls, annotation: Any) -> bool:
240         """Returns True if annotation is a List"""
241 
242         annotation_origin = getattr(annotation, "__origin__", None)
243 
244         return annotation_origin == list
245 
246     @classmethod
247     def _is_strawberry_type(cls, evaled_type: Any) -> bool:
248         # Prevent import cycles
249         from strawberry.union import StrawberryUnion
250 
251         if isinstance(evaled_type, EnumDefinition):
252             return True
253         elif _is_input_type(evaled_type):  # TODO: Replace with StrawberryInputObject
254             return True
255         # TODO: add support for StrawberryInterface when implemented
256         elif isinstance(evaled_type, StrawberryList):
257             return True
258         elif _is_object_type(evaled_type):  # TODO: Replace with StrawberryObject
259             return True
260         elif isinstance(evaled_type, TypeDefinition):
261             return True
262         elif isinstance(evaled_type, StrawberryOptional):
263             return True
264         elif isinstance(
265             evaled_type, ScalarDefinition
266         ):  # TODO: Replace with StrawberryScalar
267             return True
268         elif isinstance(evaled_type, StrawberryUnion):
269             return True
270 
271         return False
272 
273     @classmethod
274     def _is_union(cls, annotation: Any) -> bool:
275         """Returns True if annotation is a Union"""
276 
277         # this check is needed because unions declared with the new syntax `A | B`
278         # don't have a `__origin__` property on them, but they are instances of
279         # `UnionType`, which is only available in Python 3.10+
280         if sys.version_info >= (3, 10):
281             from types import UnionType
282 
283             if isinstance(annotation, UnionType):
284                 return True
285 
286         # unions declared as Union[A, B] fall through to this check, even on python 3.10+
287 
288         annotation_origin = getattr(annotation, "__origin__", None)
289 
290         return annotation_origin is typing.Union
291 
292     @classmethod
293     def _strip_async_type(cls, annotation) -> type:
294         return annotation.__args__[0]
295 
296     @classmethod
297     def _strip_lazy_type(cls, annotation: LazyType) -> type:
298         return annotation.resolve_type()
299 
300 
301 ################################################################################
302 # Temporary functions to be removed with new types
303 ################################################################################
304 
305 
306 def _is_input_type(type_: Any) -> bool:
307     if not _is_object_type(type_):
308         return False
309 
310     return type_._type_definition.is_input
311 
312 
313 def _is_object_type(type_: Any) -> bool:
314     # isinstance(type_, StrawberryObjectType)  # noqa: E800
315     return hasattr(type_, "_type_definition")
316
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/strawberry/annotation.py b/strawberry/annotation.py
--- a/strawberry/annotation.py
+++ b/strawberry/annotation.py
@@ -241,7 +241,11 @@
 
         annotation_origin = getattr(annotation, "__origin__", None)
 
-        return annotation_origin == list
+        return (
+            annotation_origin == list
+            or annotation_origin == tuple
+            or annotation_origin is abc.Sequence
+        )
 
     @classmethod
     def _is_strawberry_type(cls, evaled_type: Any) -> bool:

{"golden_diff": "diff --git a/strawberry/annotation.py b/strawberry/annotation.py\n--- a/strawberry/annotation.py\n+++ b/strawberry/annotation.py\n@@ -241,7 +241,11 @@\n \n         annotation_origin = getattr(annotation, \"__origin__\", None)\n \n-        return annotation_origin == list\n+        return (\n+            annotation_origin == list\n+            or annotation_origin == tuple\n+            or annotation_origin is abc.Sequence\n+        )\n \n     @classmethod\n     def _is_strawberry_type(cls, evaled_type: Any) -> bool:\n", "issue": "Allow using tuple (and/or iterable) as an alias to the GraphQL type\n## Feature Request Type\r\n\r\nAlteration (enhancement/optimization) of existing feature(s)\r\n\r\n## Description\r\n\r\nReturning a `tuple` when the attribute is hinted as `list` [works](https://play.strawberry.rocks/?gist=0815d1a1f0c58a613bd356cbeb45c8a1).\r\n\r\nBut hinting the return type _correctly as a tuple_ causes an error:\r\n\r\n```python\r\n@strawberry.type\r\nclass Dictionary:\r\n    entries: tuple[Entry]\r\n    sources: tuple[Source]\r\n```\r\n\r\n```\r\nTypeError: Unexpected type tuple[Entry]\r\n```\r\n\r\nOur code uses tuples and iterables whenever appropriate for robustness, efficiency, and documentation. We also use strict type hinting. It'd be great for these read-only sequences to be explicitly supported.\n", "before_files": [{"content": "import sys\nimport typing\nfrom collections import abc\nfrom enum import Enum\nfrom typing import (  # type: ignore[attr-defined]\n    TYPE_CHECKING,\n    Any,\n    Dict,\n    List,\n    Optional,\n    TypeVar,\n    Union,\n    _eval_type,\n)\n\nfrom typing_extensions import Annotated, get_args, get_origin\n\nfrom strawberry.private import is_private\n\n\ntry:\n    from typing import ForwardRef\nexcept ImportError:  # pragma: no cover\n    # ForwardRef is private in python 3.6 and 3.7\n    from typing import _ForwardRef as ForwardRef  # type: ignore\n\nfrom strawberry.custom_scalar import ScalarDefinition\nfrom strawberry.enum import EnumDefinition\nfrom strawberry.lazy_type import LazyType, StrawberryLazyReference\nfrom strawberry.type import (\n    StrawberryList,\n    StrawberryOptional,\n    StrawberryType,\n    StrawberryTypeVar,\n)\nfrom strawberry.types.types import TypeDefinition\nfrom strawberry.unset import UNSET\nfrom strawberry.utils.typing import is_generic, is_list, is_type_var, is_union\n\n\nif TYPE_CHECKING:\n    from strawberry.union import StrawberryUnion\n\n\nASYNC_TYPES = (\n    abc.AsyncGenerator,\n    abc.AsyncIterable,\n    abc.AsyncIterator,\n    typing.AsyncContextManager,\n    typing.AsyncGenerator,\n    typing.AsyncIterable,\n    typing.AsyncIterator,\n)\n\n\nclass StrawberryAnnotation:\n    def __init__(\n        self, annotation: Union[object, str], *, namespace: Optional[Dict] = None\n    ):\n        self.annotation = annotation\n        self.namespace = namespace\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, StrawberryAnnotation):\n            return NotImplemented\n\n        return self.resolve() == other.resolve()\n\n    @staticmethod\n    def parse_annotated(annotation: object) -> object:\n        from strawberry.auto import StrawberryAuto\n\n        if get_origin(annotation) is Annotated:\n            annotated_args = get_args(annotation)\n            annotation_type = annotated_args[0]\n\n            for arg in annotated_args[1:]:\n                if isinstance(arg, StrawberryLazyReference):\n                    assert isinstance(annotation_type, ForwardRef)\n\n                    return arg.resolve_forward_ref(annotation_type)\n\n                if isinstance(arg, StrawberryAuto):\n                    return arg\n\n            return StrawberryAnnotation.parse_annotated(annotation_type)\n\n        if is_union(annotation):\n            return Union[\n                tuple(\n                    StrawberryAnnotation.parse_annotated(arg)\n                    for arg in get_args(annotation)\n                )  # pyright: ignore\n            ]  # pyright: ignore\n\n        if is_list(annotation):\n            return List[StrawberryAnnotation.parse_annotated(get_args(annotation)[0])]  # type: ignore  # noqa: E501\n\n        return annotation\n\n    def resolve(self) -> Union[StrawberryType, type]:\n        annotation = self.parse_annotated(self.annotation)\n\n        if isinstance(self.annotation, str):\n            annotation = ForwardRef(self.annotation)\n\n        evaled_type = _eval_type(annotation, self.namespace, None)\n\n        if is_private(evaled_type):\n            return evaled_type\n        if self._is_async_type(evaled_type):\n            evaled_type = self._strip_async_type(evaled_type)\n        if self._is_lazy_type(evaled_type):\n            return evaled_type\n\n        if self._is_generic(evaled_type):\n            if any(is_type_var(type_) for type_ in evaled_type.__args__):\n                return evaled_type\n            return self.create_concrete_type(evaled_type)\n\n        # Simply return objects that are already StrawberryTypes\n        if self._is_strawberry_type(evaled_type):\n            return evaled_type\n\n        # Everything remaining should be a raw annotation that needs to be turned into\n        # a StrawberryType\n        if self._is_enum(evaled_type):\n            return self.create_enum(evaled_type)\n        if self._is_list(evaled_type):\n            return self.create_list(evaled_type)\n        elif self._is_optional(evaled_type):\n            return self.create_optional(evaled_type)\n        elif self._is_union(evaled_type):\n            return self.create_union(evaled_type)\n        elif is_type_var(evaled_type):\n            return self.create_type_var(evaled_type)\n\n        # TODO: Raise exception now, or later?\n        # ... raise NotImplementedError(f\"Unknown type {evaled_type}\")\n        return evaled_type\n\n    def create_concrete_type(self, evaled_type: type) -> type:\n        if _is_object_type(evaled_type):\n            type_definition: TypeDefinition\n            type_definition = evaled_type._type_definition  # type: ignore\n            return type_definition.resolve_generic(evaled_type)\n\n        raise ValueError(f\"Not supported {evaled_type}\")\n\n    def create_enum(self, evaled_type: Any) -> EnumDefinition:\n        return evaled_type._enum_definition\n\n    def create_list(self, evaled_type: Any) -> StrawberryList:\n        of_type = StrawberryAnnotation(\n            annotation=evaled_type.__args__[0],\n            namespace=self.namespace,\n        ).resolve()\n\n        return StrawberryList(of_type)\n\n    def create_optional(self, evaled_type: Any) -> StrawberryOptional:\n        types = evaled_type.__args__\n        non_optional_types = tuple(\n            filter(\n                lambda x: x is not type(None) and x is not type(UNSET),  # noqa: E721\n                types,\n            )\n        )\n\n        # Note that passing a single type to `Union` is equivalent to not using `Union`\n        # at all. This allows us to not di any checks for how many types have been\n        # passed as we can safely use `Union` for both optional types\n        # (e.g. `Optional[str]`) and optional unions (e.g.\n        # `Optional[Union[TypeA, TypeB]]`)\n        child_type = Union[non_optional_types]  # type: ignore\n\n        of_type = StrawberryAnnotation(\n            annotation=child_type,\n            namespace=self.namespace,\n        ).resolve()\n\n        return StrawberryOptional(of_type)\n\n    def create_type_var(self, evaled_type: TypeVar) -> StrawberryTypeVar:\n        return StrawberryTypeVar(evaled_type)\n\n    def create_union(self, evaled_type) -> \"StrawberryUnion\":\n        # Prevent import cycles\n        from strawberry.union import StrawberryUnion\n\n        # TODO: Deal with Forward References/origin\n        if isinstance(evaled_type, StrawberryUnion):\n            return evaled_type\n\n        types = evaled_type.__args__\n        union = StrawberryUnion(\n            type_annotations=tuple(StrawberryAnnotation(type_) for type_ in types),\n        )\n        return union\n\n    @classmethod\n    def _is_async_type(cls, annotation: type) -> bool:\n        origin = getattr(annotation, \"__origin__\", None)\n        return origin in ASYNC_TYPES\n\n    @classmethod\n    def _is_enum(cls, annotation: Any) -> bool:\n        # Type aliases are not types so we need to make sure annotation can go into\n        # issubclass\n        if not isinstance(annotation, type):\n            return False\n        return issubclass(annotation, Enum)\n\n    @classmethod\n    def _is_generic(cls, annotation: Any) -> bool:\n        if hasattr(annotation, \"__origin__\"):\n            return is_generic(annotation.__origin__)\n\n        return False\n\n    @classmethod\n    def _is_lazy_type(cls, annotation: Any) -> bool:\n        return isinstance(annotation, LazyType)\n\n    @classmethod\n    def _is_optional(cls, annotation: Any) -> bool:\n        \"\"\"Returns True if the annotation is Optional[SomeType]\"\"\"\n\n        # Optionals are represented as unions\n        if not cls._is_union(annotation):\n            return False\n\n        types = annotation.__args__\n\n        # A Union to be optional needs to have at least one None type\n        return any(x is type(None) for x in types)  # noqa: E721\n\n    @classmethod\n    def _is_list(cls, annotation: Any) -> bool:\n        \"\"\"Returns True if annotation is a List\"\"\"\n\n        annotation_origin = getattr(annotation, \"__origin__\", None)\n\n        return annotation_origin == list\n\n    @classmethod\n    def _is_strawberry_type(cls, evaled_type: Any) -> bool:\n        # Prevent import cycles\n        from strawberry.union import StrawberryUnion\n\n        if isinstance(evaled_type, EnumDefinition):\n            return True\n        elif _is_input_type(evaled_type):  # TODO: Replace with StrawberryInputObject\n            return True\n        # TODO: add support for StrawberryInterface when implemented\n        elif isinstance(evaled_type, StrawberryList):\n            return True\n        elif _is_object_type(evaled_type):  # TODO: Replace with StrawberryObject\n            return True\n        elif isinstance(evaled_type, TypeDefinition):\n            return True\n        elif isinstance(evaled_type, StrawberryOptional):\n            return True\n        elif isinstance(\n            evaled_type, ScalarDefinition\n        ):  # TODO: Replace with StrawberryScalar\n            return True\n        elif isinstance(evaled_type, StrawberryUnion):\n            return True\n\n        return False\n\n    @classmethod\n    def _is_union(cls, annotation: Any) -> bool:\n        \"\"\"Returns True if annotation is a Union\"\"\"\n\n        # this check is needed because unions declared with the new syntax `A | B`\n        # don't have a `__origin__` property on them, but they are instances of\n        # `UnionType`, which is only available in Python 3.10+\n        if sys.version_info >= (3, 10):\n            from types import UnionType\n\n            if isinstance(annotation, UnionType):\n                return True\n\n        # unions declared as Union[A, B] fall through to this check, even on python 3.10+\n\n        annotation_origin = getattr(annotation, \"__origin__\", None)\n\n        return annotation_origin is typing.Union\n\n    @classmethod\n    def _strip_async_type(cls, annotation) -> type:\n        return annotation.__args__[0]\n\n    @classmethod\n    def _strip_lazy_type(cls, annotation: LazyType) -> type:\n        return annotation.resolve_type()\n\n\n################################################################################\n# Temporary functions to be removed with new types\n################################################################################\n\n\ndef _is_input_type(type_: Any) -> bool:\n    if not _is_object_type(type_):\n        return False\n\n    return type_._type_definition.is_input\n\n\ndef _is_object_type(type_: Any) -> bool:\n    # isinstance(type_, StrawberryObjectType)  # noqa: E800\n    return hasattr(type_, \"_type_definition\")\n", "path": "strawberry/annotation.py"}], "after_files": [{"content": "import sys\nimport typing\nfrom collections import abc\nfrom enum import Enum\nfrom typing import (  # type: ignore[attr-defined]\n    TYPE_CHECKING,\n    Any,\n    Dict,\n    List,\n    Optional,\n    TypeVar,\n    Union,\n    _eval_type,\n)\n\nfrom typing_extensions import Annotated, get_args, get_origin\n\nfrom strawberry.private import is_private\n\n\ntry:\n    from typing import ForwardRef\nexcept ImportError:  # pragma: no cover\n    # ForwardRef is private in python 3.6 and 3.7\n    from typing import _ForwardRef as ForwardRef  # type: ignore\n\nfrom strawberry.custom_scalar import ScalarDefinition\nfrom strawberry.enum import EnumDefinition\nfrom strawberry.lazy_type import LazyType, StrawberryLazyReference\nfrom strawberry.type import (\n    StrawberryList,\n    StrawberryOptional,\n    StrawberryType,\n    StrawberryTypeVar,\n)\nfrom strawberry.types.types import TypeDefinition\nfrom strawberry.unset import UNSET\nfrom strawberry.utils.typing import is_generic, is_list, is_type_var, is_union\n\n\nif TYPE_CHECKING:\n    from strawberry.union import StrawberryUnion\n\n\nASYNC_TYPES = (\n    abc.AsyncGenerator,\n    abc.AsyncIterable,\n    abc.AsyncIterator,\n    typing.AsyncContextManager,\n    typing.AsyncGenerator,\n    typing.AsyncIterable,\n    typing.AsyncIterator,\n)\n\n\nclass StrawberryAnnotation:\n    def __init__(\n        self, annotation: Union[object, str], *, namespace: Optional[Dict] = None\n    ):\n        self.annotation = annotation\n        self.namespace = namespace\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, StrawberryAnnotation):\n            return NotImplemented\n\n        return self.resolve() == other.resolve()\n\n    @staticmethod\n    def parse_annotated(annotation: object) -> object:\n        from strawberry.auto import StrawberryAuto\n\n        if get_origin(annotation) is Annotated:\n            annotated_args = get_args(annotation)\n            annotation_type = annotated_args[0]\n\n            for arg in annotated_args[1:]:\n                if isinstance(arg, StrawberryLazyReference):\n                    assert isinstance(annotation_type, ForwardRef)\n\n                    return arg.resolve_forward_ref(annotation_type)\n\n                if isinstance(arg, StrawberryAuto):\n                    return arg\n\n            return StrawberryAnnotation.parse_annotated(annotation_type)\n\n        if is_union(annotation):\n            return Union[\n                tuple(\n                    StrawberryAnnotation.parse_annotated(arg)\n                    for arg in get_args(annotation)\n                )  # pyright: ignore\n            ]  # pyright: ignore\n\n        if is_list(annotation):\n            return List[StrawberryAnnotation.parse_annotated(get_args(annotation)[0])]  # type: ignore  # noqa: E501\n\n        return annotation\n\n    def resolve(self) -> Union[StrawberryType, type]:\n        annotation = self.parse_annotated(self.annotation)\n\n        if isinstance(self.annotation, str):\n            annotation = ForwardRef(self.annotation)\n\n        evaled_type = _eval_type(annotation, self.namespace, None)\n\n        if is_private(evaled_type):\n            return evaled_type\n        if self._is_async_type(evaled_type):\n            evaled_type = self._strip_async_type(evaled_type)\n        if self._is_lazy_type(evaled_type):\n            return evaled_type\n\n        if self._is_generic(evaled_type):\n            if any(is_type_var(type_) for type_ in evaled_type.__args__):\n                return evaled_type\n            return self.create_concrete_type(evaled_type)\n\n        # Simply return objects that are already StrawberryTypes\n        if self._is_strawberry_type(evaled_type):\n            return evaled_type\n\n        # Everything remaining should be a raw annotation that needs to be turned into\n        # a StrawberryType\n        if self._is_enum(evaled_type):\n            return self.create_enum(evaled_type)\n        if self._is_list(evaled_type):\n            return self.create_list(evaled_type)\n        elif self._is_optional(evaled_type):\n            return self.create_optional(evaled_type)\n        elif self._is_union(evaled_type):\n            return self.create_union(evaled_type)\n        elif is_type_var(evaled_type):\n            return self.create_type_var(evaled_type)\n\n        # TODO: Raise exception now, or later?\n        # ... raise NotImplementedError(f\"Unknown type {evaled_type}\")\n        return evaled_type\n\n    def create_concrete_type(self, evaled_type: type) -> type:\n        if _is_object_type(evaled_type):\n            type_definition: TypeDefinition\n            type_definition = evaled_type._type_definition  # type: ignore\n            return type_definition.resolve_generic(evaled_type)\n\n        raise ValueError(f\"Not supported {evaled_type}\")\n\n    def create_enum(self, evaled_type: Any) -> EnumDefinition:\n        return evaled_type._enum_definition\n\n    def create_list(self, evaled_type: Any) -> StrawberryList:\n        of_type = StrawberryAnnotation(\n            annotation=evaled_type.__args__[0],\n            namespace=self.namespace,\n        ).resolve()\n\n        return StrawberryList(of_type)\n\n    def create_optional(self, evaled_type: Any) -> StrawberryOptional:\n        types = evaled_type.__args__\n        non_optional_types = tuple(\n            filter(\n                lambda x: x is not type(None) and x is not type(UNSET),  # noqa: E721\n                types,\n            )\n        )\n\n        # Note that passing a single type to `Union` is equivalent to not using `Union`\n        # at all. This allows us to not di any checks for how many types have been\n        # passed as we can safely use `Union` for both optional types\n        # (e.g. `Optional[str]`) and optional unions (e.g.\n        # `Optional[Union[TypeA, TypeB]]`)\n        child_type = Union[non_optional_types]  # type: ignore\n\n        of_type = StrawberryAnnotation(\n            annotation=child_type,\n            namespace=self.namespace,\n        ).resolve()\n\n        return StrawberryOptional(of_type)\n\n    def create_type_var(self, evaled_type: TypeVar) -> StrawberryTypeVar:\n        return StrawberryTypeVar(evaled_type)\n\n    def create_union(self, evaled_type) -> \"StrawberryUnion\":\n        # Prevent import cycles\n        from strawberry.union import StrawberryUnion\n\n        # TODO: Deal with Forward References/origin\n        if isinstance(evaled_type, StrawberryUnion):\n            return evaled_type\n\n        types = evaled_type.__args__\n        union = StrawberryUnion(\n            type_annotations=tuple(StrawberryAnnotation(type_) for type_ in types),\n        )\n        return union\n\n    @classmethod\n    def _is_async_type(cls, annotation: type) -> bool:\n        origin = getattr(annotation, \"__origin__\", None)\n        return origin in ASYNC_TYPES\n\n    @classmethod\n    def _is_enum(cls, annotation: Any) -> bool:\n        # Type aliases are not types so we need to make sure annotation can go into\n        # issubclass\n        if not isinstance(annotation, type):\n            return False\n        return issubclass(annotation, Enum)\n\n    @classmethod\n    def _is_generic(cls, annotation: Any) -> bool:\n        if hasattr(annotation, \"__origin__\"):\n            return is_generic(annotation.__origin__)\n\n        return False\n\n    @classmethod\n    def _is_lazy_type(cls, annotation: Any) -> bool:\n        return isinstance(annotation, LazyType)\n\n    @classmethod\n    def _is_optional(cls, annotation: Any) -> bool:\n        \"\"\"Returns True if the annotation is Optional[SomeType]\"\"\"\n\n        # Optionals are represented as unions\n        if not cls._is_union(annotation):\n            return False\n\n        types = annotation.__args__\n\n        # A Union to be optional needs to have at least one None type\n        return any(x is type(None) for x in types)  # noqa: E721\n\n    @classmethod\n    def _is_list(cls, annotation: Any) -> bool:\n        \"\"\"Returns True if annotation is a List\"\"\"\n\n        annotation_origin = getattr(annotation, \"__origin__\", None)\n\n        return (\n            annotation_origin == list\n            or annotation_origin == tuple\n            or annotation_origin is abc.Sequence\n        )\n\n    @classmethod\n    def _is_strawberry_type(cls, evaled_type: Any) -> bool:\n        # Prevent import cycles\n        from strawberry.union import StrawberryUnion\n\n        if isinstance(evaled_type, EnumDefinition):\n            return True\n        elif _is_input_type(evaled_type):  # TODO: Replace with StrawberryInputObject\n            return True\n        # TODO: add support for StrawberryInterface when implemented\n        elif isinstance(evaled_type, StrawberryList):\n            return True\n        elif _is_object_type(evaled_type):  # TODO: Replace with StrawberryObject\n            return True\n        elif isinstance(evaled_type, TypeDefinition):\n            return True\n        elif isinstance(evaled_type, StrawberryOptional):\n            return True\n        elif isinstance(\n            evaled_type, ScalarDefinition\n        ):  # TODO: Replace with StrawberryScalar\n            return True\n        elif isinstance(evaled_type, StrawberryUnion):\n            return True\n\n        return False\n\n    @classmethod\n    def _is_union(cls, annotation: Any) -> bool:\n        \"\"\"Returns True if annotation is a Union\"\"\"\n\n        # this check is needed because unions declared with the new syntax `A | B`\n        # don't have a `__origin__` property on them, but they are instances of\n        # `UnionType`, which is only available in Python 3.10+\n        if sys.version_info >= (3, 10):\n            from types import UnionType\n\n            if isinstance(annotation, UnionType):\n                return True\n\n        # unions declared as Union[A, B] fall through to this check, even on python 3.10+\n\n        annotation_origin = getattr(annotation, \"__origin__\", None)\n\n        return annotation_origin is typing.Union\n\n    @classmethod\n    def _strip_async_type(cls, annotation) -> type:\n        return annotation.__args__[0]\n\n    @classmethod\n    def _strip_lazy_type(cls, annotation: LazyType) -> type:\n        return annotation.resolve_type()\n\n\n################################################################################\n# Temporary functions to be removed with new types\n################################################################################\n\n\ndef _is_input_type(type_: Any) -> bool:\n    if not _is_object_type(type_):\n        return False\n\n    return type_._type_definition.is_input\n\n\ndef _is_object_type(type_: Any) -> bool:\n    # isinstance(type_, StrawberryObjectType)  # noqa: E800\n    return hasattr(type_, \"_type_definition\")\n", "path": "strawberry/annotation.py"}]}