Repository: python/mypy

Issue:
AssertionError on version 0.960
**Bug Report**

We are using the [ddtrace](https://github.com/DataDog/dd-trace-py) Python package.
Consider the following file:
```python
# test.py
import ddtrace
```

Running `mypy test.py` passes without issues on version `0.950` but when run on version `0.960` the following is printed:

```python
Traceback (most recent call last):
  File ".../bin/mypy", line 8, in <module>
    sys.exit(console_entry())
  File ".../python3.10/site-packages/mypy/__main__.py", line 12, in console_entry
    main(None, sys.stdout, sys.stderr)
  File "mypy/main.py", line 96, in main
  File "mypy/main.py", line 173, in run_build
  File "mypy/build.py", line 154, in build
  File "mypy/build.py", line 230, in _build
  File "mypy/build.py", line 2729, in dispatch
  File "mypy/build.py", line 3087, in process_graph
  File "mypy/build.py", line 3179, in process_stale_scc
  File "mypy/semanal_main.py", line 88, in semantic_analysis_for_scc
  File "mypy/semanal_main.py", line 414, in apply_class_plugin_hooks
  File "mypy/semanal_main.py", line 434, in apply_hooks_to_class
  File "mypy/plugins/attrs.py", line 309, in attr_class_maker_callback
  File "mypy/plugins/attrs.py", line 372, in _analyze_class
  File "mypy/plugins/attrs.py", line 498, in _attributes_from_assignment
  File "mypy/plugins/attrs.py", line 594, in _attribute_from_attrib_maker
  File "mypy/semanal.py", line 5450, in anal_type
  File "mypy/types.py", line 765, in accept
  File "mypy/typeanal.py", line 172, in visit_unbound_type
  File "mypy/typeanal.py", line 263, in visit_unbound_type_nonoptional
  File "mypy/typeanal.py", line 1168, in anal_array
  File "mypy/typeanal.py", line 1177, in anal_type
  File "mypy/types.py", line 765, in accept
  File "mypy/typeanal.py", line 172, in visit_unbound_type
  File "mypy/typeanal.py", line 180, in visit_unbound_type_nonoptional
  File "mypy/semanal.py", line 4563, in lookup_qualified
  File "mypy/semanal.py", line 4458, in lookup
  File "mypy/semanal.py", line 4508, in is_active_symbol_in_class_body
AssertionError
```

I tried using the `--pdb` and `--tb` flags to get the traceback, or see which part of the library is causing this but was unable to do so.
I tried clearing the mypy cache, which didn't help as well.

Is this an issue with mypy, the library or both?

**Your Environment**

- Mypy version used: 0.960
- Python version used: 3.10
- Operating system and version: Ubuntu 22.04



Discussion:
Thanks for the report! I can reproduce this on the master branch, if I create a new virtual environment with just mypy's dependencies and `ddtrace` installed, and then run mypy on a file that only has `import ddtrace` inside it.

The crash bisects to 50a653e0714e303178c890854b9074fc030907f0 (PR #12772). Cc. @JukkaL.
I don't know if this could be related, but there seems to be issues with how `dataclasses` are handled too:

https://github.com/DataDog/riot/runs/6594827098?check_suite_focus=true

The logs show that the latest version of `mypy` has started complaining about attributes that are defined on the dataclass

https://github.com/DataDog/riot/blob/2f6ea2e7a128239c45d4771245f572095651436e/riot/riot.py#L177-L231
Thanks for reporting this! Getting this as well.
Here is a small reproducer for the attrs crash:
```py
import attr

@attr.s
class C:
    @attr.s
    class D:
        pass
    x = attr.ib(type=list[D])
```

As a workaround, moving the nested class to the module top level should fix the crash. I'm working on a fix.

Resolving patch:
diff --git a/mypy/semanal.py b/mypy/semanal.py
--- a/mypy/semanal.py
+++ b/mypy/semanal.py
@@ -4505,7 +4505,9 @@ class C:
         """
         # TODO: Forward reference to name imported in class body is not
         #       caught.
-        assert self.statement  # we are at class scope
+        if self.statement is None:
+            # Assume it's fine -- don't have enough context to check
+            return True
         return (node is None
                 or self.is_textually_before_statement(node)
                 or not self.is_defined_in_current_module(node.fullname)


Test patch:
diff --git a/test-data/unit/check-attr.test b/test-data/unit/check-attr.test
--- a/test-data/unit/check-attr.test
+++ b/test-data/unit/check-attr.test
@@ -1734,3 +1734,18 @@ class C:
         # E: Unsupported converter, only named functions and types are currently supported
     )
 [builtins fixtures/dict.pyi]
+
+[case testAttrsNestedClass]
+from typing import List
+import attr
+
+@attr.s
+class C:
+    @attr.s
+    class D:
+        pass
+    x = attr.ib(type=List[D])
+
+c = C(x=[C.D()])
+reveal_type(c.x)  # N: Revealed type is "builtins.list[__main__.C.D]"
+[builtins fixtures/list.pyi]