We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add mypy plugin for strawberry.union
We have a function to create union types and also add name and description that are used when generating the GraphQL schema[1].

Unfortunately MyPy complains when using the annotation, since it doesn't recognise it as a type, here's an example:

```python
ExampleUnion = strawberry.union(
    "ExampleUnion",
    types=(
        ABC,
        CDE,
    ),
)

@strawberry.mutation
def abc(phone_number: str) -> ExampleUnion:
    # ...
```

Error:

```
Variable "api.mutations.abc.ExampleUnion" is not valid as a type
```

[1] This is why we can't use typing.Union directly, as we can't pass arguments to it

--- 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/ext/mypy_plugin.py`
Content:
```
1 from typing import Callable, Optional
2 
3 from mypy.plugin import AnalyzeTypeContext, ClassDefContext, Plugin
4 from mypy.plugins import dataclasses
5 from mypy.types import Type
6 
7 
8 def lazy_type_analyze_callback(ctx: AnalyzeTypeContext) -> Type:
9     type_name = ctx.type.args[0]
10     type_ = ctx.api.analyze_type(type_name)
11 
12     return type_
13 
14 
15 def private_type_analyze_callback(ctx: AnalyzeTypeContext) -> Type:
16     type_name = ctx.type.args[0]
17     type_ = ctx.api.analyze_type(type_name)
18 
19     return type_
20 
21 
22 class StrawberryPlugin(Plugin):
23     def get_type_analyze_hook(self, fullname: str):
24         if fullname == "strawberry.lazy_type.LazyType":
25             return lazy_type_analyze_callback
26 
27         if any(
28             name in fullname
29             for name in {"strawberry.private.Private", "strawberry.Private"}
30         ):
31             return private_type_analyze_callback
32 
33         return None
34 
35     def get_class_decorator_hook(
36         self, fullname: str
37     ) -> Optional[Callable[[ClassDefContext], None]]:
38         if any(
39             strawberry_decorator in fullname
40             for strawberry_decorator in {
41                 "strawberry.type",
42                 "strawberry.federation.type",
43                 "strawberry.input",
44                 "strawberry.interface",
45             }
46         ):
47             return dataclasses.dataclass_class_maker_callback
48         return None
49 
50 
51 def plugin(version: str):
52     return StrawberryPlugin
53
```
--- 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/ext/mypy_plugin.py b/strawberry/ext/mypy_plugin.py
--- a/strawberry/ext/mypy_plugin.py
+++ b/strawberry/ext/mypy_plugin.py
@@ -1,8 +1,23 @@
 from typing import Callable, Optional
 
-from mypy.plugin import AnalyzeTypeContext, ClassDefContext, Plugin
+from mypy.nodes import (
+    GDEF,
+    Expression,
+    IndexExpr,
+    NameExpr,
+    SymbolTableNode,
+    TupleExpr,
+    TypeAlias,
+)
+from mypy.plugin import (
+    AnalyzeTypeContext,
+    ClassDefContext,
+    DynamicClassDefContext,
+    Plugin,
+    SemanticAnalyzerPluginInterface,
+)
 from mypy.plugins import dataclasses
-from mypy.types import Type
+from mypy.types import Type, UnionType
 
 
 def lazy_type_analyze_callback(ctx: AnalyzeTypeContext) -> Type:
@@ -19,7 +34,48 @@
     return type_
 
 
+def _get_type_for_expr(expr: Expression, api: SemanticAnalyzerPluginInterface):
+    if isinstance(expr, NameExpr):
+        return api.named_type(expr.name)
+
+    if isinstance(expr, IndexExpr):
+        type_ = _get_type_for_expr(expr.base, api)
+        type_.args = [_get_type_for_expr(expr.index, api)]
+
+        return type_
+
+    raise ValueError(f"Unsupported expression f{type(expr)}")
+
+
+def union_hook(ctx: DynamicClassDefContext) -> None:
+    types = ctx.call.args[1]
+
+    if isinstance(types, TupleExpr):
+        type_ = UnionType(tuple(_get_type_for_expr(x, ctx.api) for x in types.items))
+
+        type_alias = TypeAlias(
+            type_,
+            fullname=ctx.api.qualified_name(ctx.name),
+            line=ctx.call.line,
+            column=ctx.call.column,
+        )
+
+        ctx.api.add_symbol_table_node(
+            ctx.name, SymbolTableNode(GDEF, type_alias, plugin_generated=False)
+        )
+
+
 class StrawberryPlugin(Plugin):
+    def get_dynamic_class_hook(
+        self, fullname: str
+    ) -> Optional[Callable[[DynamicClassDefContext], None]]:
+        # TODO: investigate why we need this instead of `strawberry.union.union` on CI
+        # we have the same issue in the other hooks
+        if "strawberry.union" in fullname:
+            return union_hook
+
+        return None
+
     def get_type_analyze_hook(self, fullname: str):
         if fullname == "strawberry.lazy_type.LazyType":
             return lazy_type_analyze_callback

{"golden_diff": "diff --git a/strawberry/ext/mypy_plugin.py b/strawberry/ext/mypy_plugin.py\n--- a/strawberry/ext/mypy_plugin.py\n+++ b/strawberry/ext/mypy_plugin.py\n@@ -1,8 +1,23 @@\n from typing import Callable, Optional\n \n-from mypy.plugin import AnalyzeTypeContext, ClassDefContext, Plugin\n+from mypy.nodes import (\n+    GDEF,\n+    Expression,\n+    IndexExpr,\n+    NameExpr,\n+    SymbolTableNode,\n+    TupleExpr,\n+    TypeAlias,\n+)\n+from mypy.plugin import (\n+    AnalyzeTypeContext,\n+    ClassDefContext,\n+    DynamicClassDefContext,\n+    Plugin,\n+    SemanticAnalyzerPluginInterface,\n+)\n from mypy.plugins import dataclasses\n-from mypy.types import Type\n+from mypy.types import Type, UnionType\n \n \n def lazy_type_analyze_callback(ctx: AnalyzeTypeContext) -> Type:\n@@ -19,7 +34,48 @@\n     return type_\n \n \n+def _get_type_for_expr(expr: Expression, api: SemanticAnalyzerPluginInterface):\n+    if isinstance(expr, NameExpr):\n+        return api.named_type(expr.name)\n+\n+    if isinstance(expr, IndexExpr):\n+        type_ = _get_type_for_expr(expr.base, api)\n+        type_.args = [_get_type_for_expr(expr.index, api)]\n+\n+        return type_\n+\n+    raise ValueError(f\"Unsupported expression f{type(expr)}\")\n+\n+\n+def union_hook(ctx: DynamicClassDefContext) -> None:\n+    types = ctx.call.args[1]\n+\n+    if isinstance(types, TupleExpr):\n+        type_ = UnionType(tuple(_get_type_for_expr(x, ctx.api) for x in types.items))\n+\n+        type_alias = TypeAlias(\n+            type_,\n+            fullname=ctx.api.qualified_name(ctx.name),\n+            line=ctx.call.line,\n+            column=ctx.call.column,\n+        )\n+\n+        ctx.api.add_symbol_table_node(\n+            ctx.name, SymbolTableNode(GDEF, type_alias, plugin_generated=False)\n+        )\n+\n+\n class StrawberryPlugin(Plugin):\n+    def get_dynamic_class_hook(\n+        self, fullname: str\n+    ) -> Optional[Callable[[DynamicClassDefContext], None]]:\n+        # TODO: investigate why we need this instead of `strawberry.union.union` on CI\n+        # we have the same issue in the other hooks\n+        if \"strawberry.union\" in fullname:\n+            return union_hook\n+\n+        return None\n+\n     def get_type_analyze_hook(self, fullname: str):\n         if fullname == \"strawberry.lazy_type.LazyType\":\n             return lazy_type_analyze_callback\n", "issue": "Add mypy plugin for strawberry.union\nWe have a function to create union types and also add name and description that are used when generating the GraphQL schema[1].\r\n\r\nUnfortunately MyPy complains when using the annotation, since it doesn't recognise it as a type, here's an example:\r\n\r\n```python\r\nExampleUnion = strawberry.union(\r\n    \"ExampleUnion\",\r\n    types=(\r\n        ABC,\r\n        CDE,\r\n    ),\r\n)\r\n\r\n@strawberry.mutation\r\ndef abc(phone_number: str) -> ExampleUnion:\r\n    # ...\r\n```\r\n\r\nError:\r\n\r\n```\r\nVariable \"api.mutations.abc.ExampleUnion\" is not valid as a type\r\n```\r\n\r\n[1] This is why we can't use typing.Union directly, as we can't pass arguments to it\n", "before_files": [{"content": "from typing import Callable, Optional\n\nfrom mypy.plugin import AnalyzeTypeContext, ClassDefContext, Plugin\nfrom mypy.plugins import dataclasses\nfrom mypy.types import Type\n\n\ndef lazy_type_analyze_callback(ctx: AnalyzeTypeContext) -> Type:\n    type_name = ctx.type.args[0]\n    type_ = ctx.api.analyze_type(type_name)\n\n    return type_\n\n\ndef private_type_analyze_callback(ctx: AnalyzeTypeContext) -> Type:\n    type_name = ctx.type.args[0]\n    type_ = ctx.api.analyze_type(type_name)\n\n    return type_\n\n\nclass StrawberryPlugin(Plugin):\n    def get_type_analyze_hook(self, fullname: str):\n        if fullname == \"strawberry.lazy_type.LazyType\":\n            return lazy_type_analyze_callback\n\n        if any(\n            name in fullname\n            for name in {\"strawberry.private.Private\", \"strawberry.Private\"}\n        ):\n            return private_type_analyze_callback\n\n        return None\n\n    def get_class_decorator_hook(\n        self, fullname: str\n    ) -> Optional[Callable[[ClassDefContext], None]]:\n        if any(\n            strawberry_decorator in fullname\n            for strawberry_decorator in {\n                \"strawberry.type\",\n                \"strawberry.federation.type\",\n                \"strawberry.input\",\n                \"strawberry.interface\",\n            }\n        ):\n            return dataclasses.dataclass_class_maker_callback\n        return None\n\n\ndef plugin(version: str):\n    return StrawberryPlugin\n", "path": "strawberry/ext/mypy_plugin.py"}], "after_files": [{"content": "from typing import Callable, Optional\n\nfrom mypy.nodes import (\n    GDEF,\n    Expression,\n    IndexExpr,\n    NameExpr,\n    SymbolTableNode,\n    TupleExpr,\n    TypeAlias,\n)\nfrom mypy.plugin import (\n    AnalyzeTypeContext,\n    ClassDefContext,\n    DynamicClassDefContext,\n    Plugin,\n    SemanticAnalyzerPluginInterface,\n)\nfrom mypy.plugins import dataclasses\nfrom mypy.types import Type, UnionType\n\n\ndef lazy_type_analyze_callback(ctx: AnalyzeTypeContext) -> Type:\n    type_name = ctx.type.args[0]\n    type_ = ctx.api.analyze_type(type_name)\n\n    return type_\n\n\ndef private_type_analyze_callback(ctx: AnalyzeTypeContext) -> Type:\n    type_name = ctx.type.args[0]\n    type_ = ctx.api.analyze_type(type_name)\n\n    return type_\n\n\ndef _get_type_for_expr(expr: Expression, api: SemanticAnalyzerPluginInterface):\n    if isinstance(expr, NameExpr):\n        return api.named_type(expr.name)\n\n    if isinstance(expr, IndexExpr):\n        type_ = _get_type_for_expr(expr.base, api)\n        type_.args = [_get_type_for_expr(expr.index, api)]\n\n        return type_\n\n    raise ValueError(f\"Unsupported expression f{type(expr)}\")\n\n\ndef union_hook(ctx: DynamicClassDefContext) -> None:\n    types = ctx.call.args[1]\n\n    if isinstance(types, TupleExpr):\n        type_ = UnionType(tuple(_get_type_for_expr(x, ctx.api) for x in types.items))\n\n        type_alias = TypeAlias(\n            type_,\n            fullname=ctx.api.qualified_name(ctx.name),\n            line=ctx.call.line,\n            column=ctx.call.column,\n        )\n\n        ctx.api.add_symbol_table_node(\n            ctx.name, SymbolTableNode(GDEF, type_alias, plugin_generated=False)\n        )\n\n\nclass StrawberryPlugin(Plugin):\n    def get_dynamic_class_hook(\n        self, fullname: str\n    ) -> Optional[Callable[[DynamicClassDefContext], None]]:\n        # TODO: investigate why we need this instead of `strawberry.union.union` on CI\n        # we have the same issue in the other hooks\n        if \"strawberry.union\" in fullname:\n            return union_hook\n\n        return None\n\n    def get_type_analyze_hook(self, fullname: str):\n        if fullname == \"strawberry.lazy_type.LazyType\":\n            return lazy_type_analyze_callback\n\n        if any(\n            name in fullname\n            for name in {\"strawberry.private.Private\", \"strawberry.Private\"}\n        ):\n            return private_type_analyze_callback\n\n        return None\n\n    def get_class_decorator_hook(\n        self, fullname: str\n    ) -> Optional[Callable[[ClassDefContext], None]]:\n        if any(\n            strawberry_decorator in fullname\n            for strawberry_decorator in {\n                \"strawberry.type\",\n                \"strawberry.federation.type\",\n                \"strawberry.input\",\n                \"strawberry.interface\",\n            }\n        ):\n            return dataclasses.dataclass_class_maker_callback\n        return None\n\n\ndef plugin(version: str):\n    return StrawberryPlugin\n", "path": "strawberry/ext/mypy_plugin.py"}]}