Skip to content

Commit 328f342

Browse files
authored
Remove F821 monkey patch (#530)
1 parent aafe0ae commit 328f342

File tree

7 files changed

+10
-212
lines changed

7 files changed

+10
-212
lines changed

.flake8

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ max-complexity = 12
3030
noqa-require-code = true
3131
per-file-ignores =
3232
*.py: B905, B907, B950, E203, E501, W503, W291, W293
33-
*.pyi: B, E301, E302, E305, E501, E701, E704, W503
33+
*.pyi: B, E301, E302, E305, E501, E701, E704, F821, W503

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Change Log
22

3+
## Unreleased
4+
5+
* **Breaking change:** Previously, flake8-pyi monkey patched flake8's F821
6+
(undefined name) check to avoid false positives in stub files. This monkey
7+
patch has been removed. Instead, we now recommend to disable F821 when running flake8
8+
on stub files.
9+
* Remove the now unnecessary `--no-pyi-aware-file-checker` option.
10+
311
New error codes:
412
* Introduce Y068: Don't use `@override` in stub files.
513

flake8_pyi/checker.py

Lines changed: 1 addition & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,18 @@
11
from __future__ import annotations
22

3-
import argparse
43
import ast
54
import logging
65
import re
76
from dataclasses import dataclass
8-
from typing import Any, ClassVar, Iterator, Literal
7+
from typing import ClassVar, Iterator
98

10-
from flake8 import checker
119
from flake8.options.manager import OptionManager
12-
from flake8.plugins.finder import LoadedPlugin
13-
from flake8.plugins.pyflakes import FlakesChecker
14-
from pyflakes.checker import ModuleScope
1510

1611
from . import errors, visitor
1712

1813
LOG = logging.getLogger("flake8.pyi")
1914

2015

21-
class PyflakesPreProcessor(ast.NodeTransformer):
22-
"""Transform AST prior to passing it to pyflakes.
23-
24-
This reduces false positives on recursive class definitions.
25-
"""
26-
27-
def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef:
28-
self.generic_visit(node)
29-
node.bases = [
30-
# Remove the subscript to prevent F821 errors from being emitted
31-
# for (valid) recursive definitions: Foo[Bar] --> Foo
32-
base.value if isinstance(base, ast.Subscript) else base
33-
for base in node.bases
34-
]
35-
return node
36-
37-
38-
class PyiAwareFlakesChecker(FlakesChecker):
39-
def __init__(self, tree: ast.AST, *args: Any, **kwargs: Any) -> None:
40-
super().__init__(PyflakesPreProcessor().visit(tree), *args, **kwargs)
41-
42-
@property
43-
def annotationsFutureEnabled(self) -> Literal[True]:
44-
"""Always allow forward references in `.pyi` files.
45-
46-
Pyflakes can already handle forward refs for annotations,
47-
but only via `from __future__ import annotations`.
48-
In a stub file, `from __future__ import annotations` is unnecessary,
49-
so we pretend to pyflakes that it's always present when linting a `.pyi` file.
50-
"""
51-
return True
52-
53-
@annotationsFutureEnabled.setter
54-
def annotationsFutureEnabled(self, value: bool) -> None:
55-
"""Does nothing, as we always want this property to be `True`."""
56-
57-
def ASSIGN(
58-
self, tree: ast.Assign, omit: str | tuple[str, ...] | None = None
59-
) -> None:
60-
"""Defer evaluation of assignments in the module scope.
61-
62-
This is a custom implementation of ASSIGN, originally derived from
63-
handleChildren() in pyflakes 1.3.0.
64-
65-
This reduces false positives for:
66-
- TypeVars bound or constrained to forward references
67-
- Assignments to forward references that are not explicitly
68-
demarcated as type aliases.
69-
"""
70-
if not isinstance(self.scope, ModuleScope):
71-
super().ASSIGN(tree)
72-
return
73-
74-
for target in tree.targets:
75-
self.handleNode(target, tree)
76-
77-
self.deferFunction(lambda: self.handleNode(tree.value, tree))
78-
79-
def handleNodeDelete(self, node: ast.AST) -> None:
80-
"""Null implementation.
81-
82-
Lets users use `del` in stubs to denote private names.
83-
"""
84-
return
85-
86-
87-
class PyiAwareFileChecker(checker.FileChecker):
88-
def run_check(self, plugin: LoadedPlugin, **kwargs: Any) -> Any:
89-
if plugin.obj is FlakesChecker:
90-
if self.filename == "-":
91-
filename = self.options.stdin_display_name
92-
else:
93-
filename = self.filename
94-
95-
if filename.endswith(".pyi"):
96-
LOG.info(
97-
f"Replacing FlakesChecker with PyiAwareFlakesChecker while "
98-
f"checking {filename!r}"
99-
)
100-
plugin = plugin._replace(obj=PyiAwareFlakesChecker)
101-
return super().run_check(plugin, **kwargs)
102-
103-
10416
_TYPE_COMMENT_REGEX = re.compile(r"#\s*type:\s*(?!\s?ignore)([^#]+)(\s*#.*?)?$")
10517

10618

@@ -136,18 +48,5 @@ def run(self) -> Iterator[errors.Error]:
13648

13749
@staticmethod
13850
def add_options(parser: OptionManager) -> None:
139-
"""This is brittle, there's multiple levels of caching of defaults."""
14051
parser.parser.set_defaults(filename="*.py,*.pyi")
14152
parser.extend_default_ignore(errors.DISABLED_BY_DEFAULT)
142-
parser.add_option(
143-
"--no-pyi-aware-file-checker",
144-
default=False,
145-
action="store_true",
146-
parse_from_config=True,
147-
help="don't patch flake8 with .pyi-aware file checker",
148-
)
149-
150-
@staticmethod
151-
def parse_options(options: argparse.Namespace) -> None:
152-
if not options.no_pyi_aware_file_checker:
153-
checker.FileChecker = PyiAwareFileChecker

tests/forward_refs.pyi

Lines changed: 0 additions & 40 deletions
This file was deleted.

tests/forward_refs_annassign.pyi

Lines changed: 0 additions & 56 deletions
This file was deleted.

tests/pep695_py312.pyi

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# Temporary workaround until pyflakes supports PEP 695:
2-
# flags: --extend-ignore=F821
3-
41
import typing
52
from collections.abc import Iterator
63
from typing import (

tests/vanilla_flake8_not_clean_forward_refs.pyi

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)