Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Features:
* introduce Y033 (always use annotations in stubs, rather than type comments).
* introduce Y034 (detect common errors where return types are hardcoded, but they
should use `TypeVar`s instead).
* introduce Y035 (`__all__` in a stub has the same semantics as at runtime).

## 22.1.0

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ currently emitted:
| Y032 | The second argument of an `__eq__` or `__ne__` method should usually be annotated with `object` rather than `Any`.
| Y033 | Do not use type comments (e.g. `x = ... # type: int`) in stubs, even if the stub supports Python 2. Always use annotations instead (e.g. `x: int`).
| Y034 | Y034 detects common errors where certain methods are annotated as having a fixed return type, despite returning `self` at runtime. Such methods should be annotated with `_typeshed.Self`.<br><br>This check looks for `__new__`, `__enter__` and `__aenter__` methods that return the class's name unparameterised. It also looks for `__iter__` methods that return `Iterator`, even if the class inherits directly from `Iterator`, and for `__aiter__` methods that return `AsyncIterator`, even if the class inherits directly from `AsyncIterator`. The check excludes methods decorated with `@overload` or `@abstractmethod`.
| Y035 | The value of `__all__` in a stub file should be identical to the value of `__all__` at runtime, as `__all__` has identical semantics in `.pyi` files. E.g. write `__all__ = ["foo", "bar"]` instead of `__all__: list[str]`.

Many error codes enforce modern conventions, and some cannot yet be used in
all cases:
Expand Down
7 changes: 7 additions & 0 deletions pyi.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,12 @@ def visit_Expr(self, node: ast.Expr) -> None:
self.generic_visit(node)

def visit_AnnAssign(self, node: ast.AnnAssign) -> None:
if _is_name(node.target, "__all__") and not self.in_class.active:
with self.string_literals_allowed.enabled():
self.generic_visit(node)
if node.value is None:
self.error(node, Y035)
return
self.generic_visit(node)
if _is_TypeAlias(node.annotation):
return
Expand Down Expand Up @@ -1258,3 +1264,4 @@ def parse_options(cls, optmanager, options, extra_args) -> None:
)
Y033 = 'Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")'
Y034 = 'Y034 {methods} usually return "self" at runtime. Consider using "_typeshed.Self" in "{method_name}", e.g. "{suggested_syntax}"'
Y035 = 'Y035 "__all__" in a stub file should be identical to "__all__" at runtime'
7 changes: 7 additions & 0 deletions tests/__all__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
__all__: list[str] # Y035 "__all__" in a stub file should be identical to "__all__" at runtime
__all__: list[str] = ["foo", "bar", "baz"]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not really much point in annotating __all__ like this, but I don't really see a good reason to disallow it either.

__all__ = ["foo", "bar", "baz"]

foo: int = ...
bar: str = ...
baz: list[set[bytes]] = ...