In Python, attributes that are declared at class toplevel but are uninitialized there cannot be directly accessed from the class itself at runtime. For instance,
class Foo:
x: int
Foo.x # Runtime crash! type object 'Foo' has no attribute 'x'
This makes sense because at runtime, the bare x: int “declaration” on Foo toplevel is just an annotated assignment statement without a RHS, which semantically is a no-op. Nothing actually gets added to the class Foo. So attribute-accessing x from class Foo directly is almost always a runtime crash.
But if we try to assign an initial value to the attribute at class toplevel, x will be there:
class Bar:
x: int = 42
Bar.x # OK!
Currnetly, neither mypy and pyright checks this kind of issue. But in pyrefly (and in ty according to Alex), we are trying to emit type errors when we detect that the user tries to access uninitialized attributes from class names directly. Our experience has been that this check rarely misfires for classes defined in user-written .py source files, but it misfires every now and then for classes that are defined in stub files – since stub files don’t quite pay much attention to differentiating between the initialized and uninitialized cases. In particular, Typeshed currently follows the following convention, according to Sebastian:
So far in typeshed, we’ve treated
x: intandx: int = ...not only as identical, but the latter form even as outdated.
As an example, builtins.object is declared to have 4 uninitialized class-level attributes, but at runtime all these 4 attributes are always initialized on the object class. This means that every time someone attribute-accesses __doc__ or __dict__ etc. on any classes, Pyrefly is going to complain that these attributes are not initialized:
Such typeshed convention quite limits the usability of Pyrefly’s uninitialized-class-attribute check at the moment so I’m inclined to change it. But before I make my attempt I’d also like to see what folks think about this idea: is differentiating between initialized and uninitialized class-level attribute considered beneficial enough? What’s the chance of elevating the behavior/convention to the typing spec?