Repository: strawberry-graphql/strawberry

Issue:
MyPy - Support for dynamic enums is broken at the moment
Annoyingly this bit of code doesn't work:

```python
import strawberry


Animal = Enum('Animal', 'ANT BEE CAT DOG')

AnimalEnum = strawberry.enum(Animal, name="Animal")


a: AnimalEnum
reveal_type(AnimalEnum)
reveal_type(a)
```

As it raises the following error:

```
➜ poetry run mypy demo_types.py --show-traceback
demo_types.py:6: error: INTERNAL ERROR -- Please try using mypy master on Github:
https://mypy.rtfd.io/en/latest/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 0.790
Traceback (most recent call last):
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/bin/mypy", line 8, in <module>
    sys.exit(console_entry())
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/__main__.py", line 8, in console_entry
    main(None, sys.stdout, sys.stderr)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/main.py", line 90, in main
    res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/build.py", line 180, in build
    result = _build(
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/build.py", line 254, in _build
    graph = dispatch(sources, manager, stdout)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/build.py", line 2630, in dispatch
    process_graph(graph, manager)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/build.py", line 2953, in process_graph
    process_stale_scc(graph, scc, manager)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/build.py", line 3045, in process_stale_scc
    mypy.semanal_main.semantic_analysis_for_scc(graph, scc, manager.errors)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/semanal_main.py", line 78, in semantic_analysis_for_scc
    process_top_levels(graph, scc, patches)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/semanal_main.py", line 199, in process_top_levels
    deferred, incomplete, progress = semantic_analyze_target(next_id, state,
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/semanal_main.py", line 326, in semantic_analyze_target
    analyzer.refresh_partial(refresh_node,
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/semanal.py", line 357, in refresh_partial
    self.refresh_top_level(node)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/semanal.py", line 368, in refresh_top_level
    self.accept(d)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/semanal.py", line 4700, in accept
    node.accept(self)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/nodes.py", line 1063, in accept
    return visitor.visit_assignment_stmt(self)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/semanal.py", line 1943, in visit_assignment_stmt
    self.apply_dynamic_class_hook(s)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/semanal.py", line 2194, in apply_dynamic_class_hook
    hook(DynamicClassDefContext(call, lval.name, self))
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/strawberry/ext/mypy_plugin.py", line 69, in enum_hook
    enum_type = _get_type_for_expr(ctx.call.args[0], ctx.api)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/strawberry/ext/mypy_plugin.py", line 39, in _get_type_for_expr
    return api.named_type(expr.name)
  File "/Users/patrick/Documents/github/strawberry-graphql/strawberry/.venv/lib/python3.9/site-packages/mypy/semanal.py", line 4155, in named_type
    assert isinstance(node, TypeInfo)
AssertionError:
demo_types.py:6: : note: use --pdb to drop into pdb
```

I'm not sure how to fix, since this error is deep inside mypy, and it seems to fail because the node we send to it is not a TypeInfo (it is a var node if I understood correctly). I wonder if we can check the type of node we have and then do something based on that 🤔 


Discussion:

Resolving patch:
diff --git a/.github/release-check-action/config.py b/.github/release-check-action/config.py
--- a/.github/release-check-action/config.py
+++ b/.github/release-check-action/config.py
@@ -5,4 +5,4 @@
 GITHUB_SHA = os.environ["GITHUB_SHA"]
 GITHUB_EVENT_PATH = os.environ["GITHUB_EVENT_PATH"]
 GITHUB_WORKSPACE = os.environ["GITHUB_WORKSPACE"]
-API_URL = "https://gentle-beach-72400.herokuapp.com/graphql"
+API_URL = "https://strawberry-github-bot.herokuapp.com/graphql"
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
@@ -8,6 +8,7 @@
     SymbolTableNode,
     TupleExpr,
     TypeAlias,
+    Var,
 )
 from mypy.plugin import (
     AnalyzeTypeContext,
@@ -17,7 +18,7 @@
     SemanticAnalyzerPluginInterface,
 )
 from mypy.plugins import dataclasses
-from mypy.types import Type, UnionType
+from mypy.types import AnyType, Type, TypeOfAny, UnionType
 
 
 def lazy_type_analyze_callback(ctx: AnalyzeTypeContext) -> Type:
@@ -66,7 +67,32 @@ def union_hook(ctx: DynamicClassDefContext) -> None:
 
 
 def enum_hook(ctx: DynamicClassDefContext) -> None:
-    enum_type = _get_type_for_expr(ctx.call.args[0], ctx.api)
+    first_argument = ctx.call.args[0]
+
+    if isinstance(first_argument, NameExpr):
+        if not first_argument.node:
+            ctx.api.defer()
+
+            return
+
+        if isinstance(first_argument.node, Var):
+            var_type = first_argument.node.type or AnyType(
+                TypeOfAny.implementation_artifact
+            )
+
+            type_alias = TypeAlias(
+                var_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)
+            )
+            return
+
+    enum_type = _get_type_for_expr(first_argument, ctx.api)
 
     type_alias = TypeAlias(
         enum_type,


Test patch:
diff --git a/tests/mypy/test_enum.yml b/tests/mypy/test_enum.yml
--- a/tests/mypy/test_enum.yml
+++ b/tests/mypy/test_enum.yml
@@ -1,4 +1,4 @@
-- case: test_union
+- case: test_enum
   main: |
     from enum import Enum
 
@@ -17,3 +17,29 @@
   out: |
     main:13: note: Revealed type is 'def (value: builtins.object) -> main.IceCreamFlavour'
     main:14: note: Revealed type is 'main.IceCreamFlavour'
+
+- case: test_enum_from_var
+  main: |
+    from typing import Type
+    from enum import Enum
+
+    import strawberry
+
+    def get_enum() -> Type[Enum]:
+        class I(Enum):
+            VANILLA = "vanilla"
+            STRAWBERRY = "strawberry"
+            CHOCOLATE = "chocolate"
+
+        return I
+
+    IceCreamFlavour = get_enum()
+
+    Flavour = strawberry.enum(IceCreamFlavour)
+
+    a: Flavour
+    reveal_type(Flavour)
+    reveal_type(a)
+  out: |
+    main:19: note: Revealed type is 'Any'
+    main:20: note: Revealed type is 'Any'