Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash when using type comments inside a generic class with constrained type variables. #16649

Closed
picnixz opened this issue Dec 11, 2023 · 3 comments · Fixed by #16849
Closed
Labels

Comments

@picnixz
Copy link
Contributor

picnixz commented Dec 11, 2023

I've encountered something really weird which is quite close to all issues related to AttributeError: attribute '_fullname' of 'TypeInfo' undefined but where I could reproduce the bug.

More precisely, the following crashes

from typing import Generic, TypeVar
NT = TypeVar('NT', int, float)
class Foo(Generic[NT]):
    def bar(self) -> None:
        p, q = 1, 2.0  # type: (int, float)

with a "AttributeError: attribute '_fullname' of 'TypeInfo' undefined". Obviously, the following succeeds:

from typing import Generic, TypeVar
NT = TypeVar('NT', int, float)
class Foo(Generic[NT]):
    def bar(self) -> None:
        p, q = 1, 2.0  # no type comment

So I thought that the issue was because of the type comment. However (!), I was surprised to see that the following also doesn't crash:

from typing import Generic, TypeVar
NT = TypeVar('NT', bound=int)  # here I have a bound and not a constraint !
class Foo(Generic[NT]):
    def bar(self) -> None:
        p, q = 1, 2.0  # type: (int, float)

Or even the following is fine:

from typing import Generic, TypeVar
NT = TypeVar('NT', int, float)  # here I have a constraint
class Foo(Generic[NT]):
    def bar(self) -> None:
        # but here I only have a single annotated object and not two on the same line
        p = 1  # type: int

Now, we could have thought that the issue stems from "constrained TypeVar" + "type comment with more than 2 objects". But actually, it's not entirely the case because the following actually works (!!):

from typing import Generic, TypeVar
NT = TypeVar('NT', int, float)
class Foo(Generic[NT]):
    p, q = 1, 2.0  # type: (int, float)

Also, if I do not inherit from Generic, then the original bug disappears. So I think the issue stems from the fact that I inherit from Generic, uses a constrainted TypeVar (although I don't understand why the type comment outside a method wouldn't produce a bug as well) and a type comment for two objects (note that this is allowed according to PEP 484).

Full traceback

Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "mypy/checker.py", line 591, in accept
  File "mypy/nodes.py", line 785, in accept
  File "mypy/checker.py", line 1000, in visit_func_def
  File "mypy/checker.py", line 1004, in _visit_func_def
  File "mypy/checker.py", line 1077, in check_func_item
  File "mypy/checker.py", line 1104, in check_func_def
  File "mypy/checker.py", line 1867, in expand_typevars
  File "mypy/checker.py", line 7628, in expand_func
  File "mypy/treetransform.py", line 696, in node
  File "mypy/nodes.py", line 785, in accept
  File "mypy/treetransform.py", line 194, in visit_func_def
  File "mypy/treetransform.py", line 735, in block
  File "mypy/treetransform.py", line 279, in visit_block
  File "mypy/treetransform.py", line 746, in statements
  File "mypy/treetransform.py", line 713, in stmt
  File "mypy/nodes.py", line 1402, in accept
  File "mypy/treetransform.py", line 344, in visit_for_stmt
  File "mypy/treetransform.py", line 777, in optional_type
  File "mypy/checker.py", line 7639, in type
  File "mypy/expandtype.py", line 71, in expand_type
  File "mypy/types.py", line 2394, in accept
  File "mypy/expandtype.py", line 413, in visit_tuple_type
  File "mypy/types.py", line 1429, in accept
  File "mypy/expandtype.py", line 215, in visit_instance
  File "mypy/nodes.py", line 3099, in fullname
AttributeError: attribute '_fullname' of 'TypeInfo' undefined

Environment

Platform:              linux; (Linux-5.3.18-lp152.106-default-x86_64-with-glibc2.26)
Python version:        3.11.6 (main, Nov 29 2023, 14:46:32) [GCC 7.5.0])
Python implementation: CPython
MyPy version:          1.7.1 (compiled: yes)
Command:               python3.11 -m mypy -c "$code" --no-incremental

Here "$code" is a string containing any of the above programs, e.g.,

$ read -r -d '' code <<EOF
from typing import Generic, TypeVar
NT = TypeVar('NT', int, float)
class Foo(Generic[NT]):
    def bar(self) -> None:
        p, q = 1, 2.0  # type: (int, float)
EOF
$ python3.11 -m mypy -c "$code" --no-incremental --show-traceback
Traceback (most recent call last):
  ...
AttributeError: attribute '_fullname' of 'TypeInfo' undefined
@picnixz picnixz added the crash label Dec 11, 2023
@picnixz picnixz changed the title Crash when using type comments inside a generic classes with constrained type variables. Crash when using type comments inside a generic class with constrained type variables. Dec 12, 2023
picnixz added a commit to picnixz/mypy that referenced this issue Feb 3, 2024
@amprew
Copy link

amprew commented Mar 15, 2024

I am having the same issue but with the package: from typing import AnyStr. I have noticed that AnyStr under the hood is pretty much the same: TypeVar('AnyStr', bytes, str). Weirdly it fails on some functions but not others. I am not using any generics, just using the type as an argument to a classmethod.

@picnixz
Copy link
Contributor Author

picnixz commented Mar 15, 2024

I'll update my PR to check if the patch also works for your case. Can you give me an example of function that fails?

@amprew
Copy link

amprew commented Mar 15, 2024

Trying to track down the exact line that fails as it is kind of a function as a file/function as a whole that fails. As you mention above there a lot of edge cases I will post when I find it

Unfortunately my traceback is the same but it only gives me the line of the function and not the argument that is failing

picnixz added a commit to picnixz/mypy that referenced this issue Mar 17, 2024
picnixz added a commit to picnixz/mypy that referenced this issue May 21, 2024
picnixz added a commit to picnixz/mypy that referenced this issue Jun 23, 2024
hauntsaninja pushed a commit that referenced this issue Jul 1, 2024
Closes #16649

It's the first time I am contributing to mypy so I am not very familiar
with how it works entirely behind the scene. The issue that I had is
that a crash happens when using tuple type comments inside
functions/classes that depend on a *constrained* type variable.

After investigation, the reason is that the type checker generates all
possible definitions (since constraints are known) and expands the
functions definitions and bodies accordingly. However, by doing so, a
tuple type comment ('# type: (int, float)') would have a FakeInfo, so
`ExpandTypeVisitor` would fail since it queries `t.type.fullname`.

By the way, feel free to change where my test should lie.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants