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

PEP 695 syntax breaks parsing of forward type reference #762

Open
ncanceill opened this issue Nov 24, 2024 · 2 comments
Open

PEP 695 syntax breaks parsing of forward type reference #762

ncanceill opened this issue Nov 24, 2024 · 2 comments
Labels

Comments

@ncanceill
Copy link

Problem Description

Python 3.12 introduced PEP 695 Type Parameter Syntax. This seems to break type parsing for a forward type reference to a generic class in a method of another generic class:

class Foo[T]:
    def foo(self) -> "Bar[T]":  # this breaks!
        ...

class Bar[T]:
    def bar(self, _: T) -> None:
        ...

That is a valid Python 3.12 module, but running pdoc on it will result in:
Error parsing type annotation Bar[T] for package.module.Foo.foo. Import of T failed: name 'T' is not defined

The generated HTML therefore does not have a link:

<span class="return-annotation">) -&gt; <span class="s1">'Bar[T]'</span>:</span>

Steps to reproduce the behavior:

Run pdoc on a package containing the example module above.

Note that using the old syntax does not break parsing, probably because it requires a TypeVar to be defined:

from typing import Generic, TypeVar

T = TypeVar("T")

class Foo(Generic[T]):
    def foo(self) -> "Bar[T]":  # this is fine
        ...

class Bar(Generic[T]):
    def bar(self, _: T) -> None:
        ...

Note also that the problem only occurs with a forward reference, insofar as the following example does not break parsing either:

class Foo[T]:
    def foo(self, _: T) -> None:
        ...

class Bar[T]:
    def bar(self) -> Foo[T]:  # this is fine
        ...

System Information

pdoc: 15.0.0
Python: 3.12.7
Platform: Linux-6.1.0-21-amd64-x86_64-with-glibc2.36
@ncanceill ncanceill added the bug label Nov 24, 2024
@mhils
Copy link
Member

mhils commented Nov 25, 2024

This already breaks in stdlib:

class Foo[T]:
    def foo(self) -> "Bar[T]":
        ...

class Bar[T]:
    def bar(self, _: T) -> None:
        ...

if __name__ == "__main__":
    import typing
    typing.get_type_hints(Foo.foo)  # NameError: name 'T' is not defined

Contributions are welcome, I won't have capacity to look into this anytime soon. :)

@ncanceill
Copy link
Author

Thanks for checking!

Indeed, we get the same exception even with a specific type:

>>> get_type_hints(Foo[int].foo)
Traceback (most recent call last):
  ...
NameError: name 'T' is not defined

This seems part of a broader issue between PEP563 and PEP695: python/cpython#124089

That should be fixed by the implementation of PEP649 in Python 3.14, which would bring new attributes to help with TypeVar and PEP695. See section Deferred evaluation of PEP 695 and 696 objects of PEP749 for more details.

This issue can be closed since Python 3.12 or 3.13 do not seem to support this typing style.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants