While trying to pass the conformance tests for Zuban, I have encountered a few fundamental issues, this is #4 of 4.
String reference annotations (forward references) in class scopes behave in weird ways in the conformance tests. I’m not saying it’s wrong, but it is not specified as far as I know.
The only part of the spec that mentions forward annotations is this:
The string literal should contain a valid Python expression (i.e., compile(lit, ‘’, ‘eval’) should be a valid code object) and it should evaluate without errors once the module has been fully loaded. The local and global namespace in which it is evaluated should be the same namespaces in which default arguments to the same function would be evaluated.
class ClassC:
...
class ClassD:
ClassC: "ClassC" # OK
ClassF: "ClassF" # E: circular reference
str: "str" = "" # OK
def int(self) -> None: # OK
...
x: "int" = 0 # OK
y: int = 0 # E: Refers to local int, which isn't a legal type expression
def __init__(self) -> None:
self.ClassC = ClassC()
assert_type(ClassD.str, str)
assert_type(ClassD.x, int)
Ideally a specification will arrive after or at least in conformance with PEP 749 (Deferred evaluations of annotations), but I haven’t gotten anything of value out of 3.14:
>>> class X:
... def int(self) -> None: ...
... x: "int" = 0
... y: int = 0
...
>>> import annotationlib
>>> annotationlib.get_annotations(X, format=annotationlib.Format.VALUE)
{'x': 'int', 'y': <function X.int at 0x75ce1e260300>}
The problem here for me is how “int” and “str” are resolved. Mypy/Zuban do this in a different way than Pyright. The conformance tests are currently mirroring Pyright’s behavior. I propose to allow both ways for now. My gut tells me that PEP 749 will sway into the direction of Zuban, but if it does not that’s also fine. I just don’t want to implement something that will be changed again. Maybe the PEP 749 implementors can have a word here as well (maybe @Jelle?), this might even have been implemented, I just don’t have an easy way to run the cpython master branch here.
If people agree with this proposal, I will add a PR to the typing repository and allow both behaviors in the conformance tests for now. Once the deferred evaluation of annotations is done, we can use that logic to implement that logic in the conformance tests.