mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 12:54:11 +08:00
[inductor] Fix issue with set_linter, improve linter framework (#144620)
### `set_linter` only
* Fix gnarly [bug](dbed747aae/tools/test/set_linter_testdata/python_code.py.txt.python (L42)
) which would have garbled Python files involving sets contained in sets.
* Better handling of new Python3.12 token types
### Both linters.
* Recover from and report on unparseable Python files
* Remove `ParseError.check()` (it made it harder to read the code)
* FileLinter is now generic on `PythonFile`
### Notes
As I started working on new docstring features, I found a nasty bug and an edge case bug in set linter, and realized both the linters crash when there is a badly-formed Python file in the repo.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/144620
Approved by: https://github.com/amjames, https://github.com/jansel
This commit is contained in:
committed by
PyTorch MergeBot
parent
f4bffb7461
commit
d90f9e9a34
@ -12,29 +12,30 @@ from enum import Enum
|
||||
from functools import cached_property
|
||||
from pathlib import Path
|
||||
from tokenize import generate_tokens, TokenInfo
|
||||
from typing import Any, TYPE_CHECKING
|
||||
from typing_extensions import Never
|
||||
from typing import Any, Generic, get_args, TYPE_CHECKING
|
||||
from typing_extensions import Never, Self, TypeVar
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterator, Sequence
|
||||
|
||||
|
||||
FSTRING_START = getattr(token, "FSTRING_START", None) # py3.12+
|
||||
FSTRING_END = getattr(token, "FSTRING_END", None)
|
||||
EMPTY_TOKENS = dict.fromkeys(
|
||||
[
|
||||
token.COMMENT,
|
||||
token.DEDENT,
|
||||
token.ENCODING,
|
||||
token.INDENT,
|
||||
token.NEWLINE,
|
||||
token.NL,
|
||||
]
|
||||
# Python 3.12 and up have two new token types, FSTRING_START and FSTRING_END
|
||||
NO_TOKEN = -1
|
||||
FSTRING_START: int = getattr(token, "FSTRING_START", NO_TOKEN)
|
||||
FSTRING_END: int = getattr(token, "FSTRING_END", NO_TOKEN)
|
||||
|
||||
START_OF_LINE_TOKENS = dict.fromkeys((token.DEDENT, token.INDENT, token.NEWLINE))
|
||||
IGNORED_TOKENS = dict.fromkeys(
|
||||
(token.COMMENT, token.ENDMARKER, token.ENCODING, token.NL)
|
||||
)
|
||||
EMPTY_TOKENS = START_OF_LINE_TOKENS | IGNORED_TOKENS
|
||||
|
||||
BRACKETS = {"{": "}", "(": ")", "[": "]"}
|
||||
BRACKETS_INV = {j: i for i, j in BRACKETS.items()}
|
||||
|
||||
ROOT = Path(__file__).absolute().parents[3]
|
||||
|
||||
|
||||
def is_name(t: TokenInfo, *names: str) -> bool:
|
||||
return t.type == token.NAME and not names or t.string in names
|
||||
@ -107,21 +108,27 @@ class LintResult:
|
||||
def is_edit(self) -> bool:
|
||||
return None not in (self.char, self.length, self.line, self.replacement)
|
||||
|
||||
def apply(self, lines: list[str]) -> bool:
|
||||
if self.line is None:
|
||||
return False
|
||||
line = lines[self.line - 1]
|
||||
def apply(self, lines: list[str]) -> None:
|
||||
if not (
|
||||
self.char is None
|
||||
or self.length is None
|
||||
or self.line is None
|
||||
or self.replacement is None
|
||||
):
|
||||
line = lines[self.line - 1]
|
||||
before = line[: self.char]
|
||||
after = line[self.char + self.length :]
|
||||
lines[self.line - 1] = f"{before}{self.replacement}{after}"
|
||||
|
||||
if self.char is None:
|
||||
return False
|
||||
before = line[: self.char]
|
||||
def contains(self, r: LintResult) -> bool:
|
||||
assert self.char is not None and self.line is not None
|
||||
assert r.char is not None and r.line is not None
|
||||
return self.line == r.line and self.char <= r.char and self.end >= r.end
|
||||
|
||||
if self.length is None:
|
||||
return False
|
||||
after = line[self.char + self.length :]
|
||||
|
||||
lines[self.line - 1] = f"{before}{self.replacement}{after}"
|
||||
return True
|
||||
@property
|
||||
def end(self) -> int:
|
||||
assert self.char is not None and self.length is not None
|
||||
return self.char + self.length
|
||||
|
||||
def as_message(self, code: str, path: str) -> LintMessage:
|
||||
d = dc.asdict(self)
|
||||
@ -145,11 +152,6 @@ class ParseError(ValueError):
|
||||
super().__init__(*args)
|
||||
self.token = token
|
||||
|
||||
@classmethod
|
||||
def check(cls, cond: Any, token: TokenInfo, *args: str) -> None:
|
||||
if not cond:
|
||||
raise cls(token, *args)
|
||||
|
||||
|
||||
class ArgumentParser(argparse.ArgumentParser):
|
||||
"""
|
||||
@ -178,9 +180,6 @@ class ArgumentParser(argparse.ArgumentParser):
|
||||
help = "Run for lintrunner and print LintMessages which aren't edits"
|
||||
self.add_argument("-l", "--lintrunner", action="store_true", help=help)
|
||||
|
||||
help = "Run for test, print all LintMessages"
|
||||
self.add_argument("-t", "--test", action="store_true", help=help)
|
||||
|
||||
help = "Print more debug info"
|
||||
self.add_argument("-v", "--verbose", action="store_true", help=help)
|
||||
|
||||
@ -206,11 +205,18 @@ class OmittedLines:
|
||||
omitted = ((i, s.rstrip()) for i, s in enumerate(lines))
|
||||
self.omitted = {i + 1 for i, s in omitted if s.endswith(suffix)}
|
||||
|
||||
def __call__(self, tokens: Sequence[TokenInfo]) -> bool:
|
||||
def __call__(
|
||||
self, tokens: Sequence[TokenInfo], begin: int = 0, end: int = NO_TOKEN
|
||||
) -> bool:
|
||||
if end == NO_TOKEN:
|
||||
end = len(tokens)
|
||||
# A token_line might span multiple physical lines
|
||||
lines = sorted(i for t in tokens for i in (t.start[0], t.end[0]))
|
||||
lines_covered = list(range(lines[0], lines[-1] + 1)) if lines else []
|
||||
return bool(self.omitted.intersection(lines_covered))
|
||||
start = min((tokens[i].start[0] for i in range(begin, end)), default=0)
|
||||
end = max((tokens[i].end[0] for i in range(begin, end)), default=-1)
|
||||
return self.contains_lines(start, end)
|
||||
|
||||
def contains_lines(self, begin: int, end: int) -> bool:
|
||||
return bool(self.omitted.intersection(range(begin, end + 1)))
|
||||
|
||||
|
||||
class PythonFile:
|
||||
@ -226,7 +232,7 @@ class PythonFile:
|
||||
contents: str | None = None,
|
||||
) -> None:
|
||||
self.linter_name = linter_name
|
||||
self.path = path
|
||||
self.path = path and (path.relative_to(ROOT) if path.is_absolute() else path)
|
||||
if contents is None and path is not None:
|
||||
contents = path.read_text()
|
||||
|
||||
@ -234,13 +240,13 @@ class PythonFile:
|
||||
self.lines = self.contents.splitlines(keepends=True)
|
||||
|
||||
@classmethod
|
||||
def make(cls, linter_name: str, pc: Path | str | None = None) -> PythonFile:
|
||||
def make(cls, linter_name: str, pc: Path | str | None = None) -> Self:
|
||||
if isinstance(pc, Path):
|
||||
return cls(linter_name, path=pc)
|
||||
return cls(linter_name, contents=pc)
|
||||
|
||||
def with_contents(self, contents: str) -> PythonFile:
|
||||
return PythonFile(self.linter_name, self.path, contents)
|
||||
def with_contents(self, contents: str) -> Self:
|
||||
return self.__class__(self.linter_name, self.path, contents)
|
||||
|
||||
@cached_property
|
||||
def omitted(self) -> OmittedLines:
|
||||
@ -280,6 +286,12 @@ class PythonFile:
|
||||
|
||||
return [froms, imports]
|
||||
|
||||
@cached_property
|
||||
def opening_comment_lines(self) -> int:
|
||||
"""The number of comments at the very top of the file."""
|
||||
it = (i for i, s in enumerate(self.lines) if not s.startswith("#"))
|
||||
return next(it, 0)
|
||||
|
||||
|
||||
def bracket_pairs(tokens: Sequence[TokenInfo]) -> dict[int, int]:
|
||||
"""Returns a dictionary mapping opening to closing brackets"""
|
||||
@ -291,23 +303,23 @@ def bracket_pairs(tokens: Sequence[TokenInfo]) -> dict[int, int]:
|
||||
if t.string in BRACKETS:
|
||||
stack.append(i)
|
||||
elif inv := BRACKETS_INV.get(t.string):
|
||||
ParseError.check(stack, t, "Never opened")
|
||||
if not stack:
|
||||
raise ParseError(t, "Never opened")
|
||||
begin = stack.pop()
|
||||
|
||||
if not (stack and stack[-1] == FSTRING_START):
|
||||
braces[begin] = i
|
||||
|
||||
b = tokens[begin].string
|
||||
ParseError.check(b == inv, t, f"Mismatched braces '{b}' at {begin}")
|
||||
elif FSTRING_START and t.type == FSTRING_START:
|
||||
if b != inv:
|
||||
raise ParseError(t, f"Mismatched braces '{b}' at {begin}")
|
||||
elif t.type == FSTRING_START:
|
||||
stack.append(FSTRING_START)
|
||||
elif FSTRING_END and t.type == FSTRING_END:
|
||||
ParseError.check(
|
||||
stack.pop() == FSTRING_START, t, "Mismatched FSTRING_START/FSTRING_END"
|
||||
)
|
||||
|
||||
if tokens:
|
||||
ParseError.check(not stack, t, "Left open")
|
||||
elif t.type == FSTRING_END:
|
||||
if stack.pop() != FSTRING_START:
|
||||
raise ParseError(t, "Mismatched FSTRING_START/FSTRING_END")
|
||||
if stack:
|
||||
raise ParseError(t, "Left open")
|
||||
return braces
|
||||
|
||||
|
||||
@ -319,7 +331,10 @@ class ErrorLines:
|
||||
AFTER = WINDOW - BEFORE - 1
|
||||
|
||||
|
||||
class FileLinter(ABC):
|
||||
PythonFileT = TypeVar("PythonFileT", bound=PythonFile)
|
||||
|
||||
|
||||
class FileLinter(Generic[PythonFileT], ABC):
|
||||
"""The base class that all token-based linters inherit from"""
|
||||
|
||||
description: str
|
||||
@ -330,22 +345,21 @@ class FileLinter(ABC):
|
||||
report_column_numbers: bool = False
|
||||
|
||||
@abstractmethod
|
||||
def _lint(self, python_file: PythonFile) -> Iterator[LintResult]:
|
||||
def _lint(self, python_file: PythonFileT) -> Iterator[LintResult]:
|
||||
raise NotImplementedError
|
||||
|
||||
def __init__(self, argv: list[str] | None = None) -> None:
|
||||
def __init__(self, argv: Sequence[str] | None = None) -> None:
|
||||
self.argv = argv
|
||||
self.parser = ArgumentParser(
|
||||
is_fixer=self.is_fixer,
|
||||
description=self.description,
|
||||
epilog=self.epilog,
|
||||
)
|
||||
self.result_shown = False
|
||||
|
||||
@classmethod
|
||||
def run(cls) -> Never:
|
||||
linter = cls()
|
||||
success = linter.lint_all()
|
||||
sys.exit(not success)
|
||||
sys.exit(not cls().lint_all())
|
||||
|
||||
def lint_all(self) -> bool:
|
||||
if self.args.fix and self.args.lintrunner:
|
||||
@ -356,10 +370,16 @@ class FileLinter(ABC):
|
||||
success = self._lint_file(p) and success
|
||||
return self.args.lintrunner or success
|
||||
|
||||
@classmethod
|
||||
def make_file(cls, pc: Path | str | None = None) -> PythonFileT:
|
||||
c = cls.__orig_bases__[0] # type: ignore[attr-defined]
|
||||
# See https://github.com/microsoft/pyright/issues/3442
|
||||
actual_python_file_type: PythonFileT = get_args(c)[0]
|
||||
return actual_python_file_type.make(cls.linter_name, pc)
|
||||
|
||||
@cached_property
|
||||
def args(self) -> Namespace:
|
||||
args = self.parser.parse_args(self.argv)
|
||||
args.lintrunner = args.lintrunner or args.test
|
||||
|
||||
return args
|
||||
|
||||
@ -380,18 +400,22 @@ class FileLinter(ABC):
|
||||
|
||||
def _lint_file(self, p: Path) -> bool:
|
||||
if self.args.verbose:
|
||||
print(p, "Reading")
|
||||
print(p, "Reading", file=sys.stderr)
|
||||
|
||||
pf = PythonFile(self.linter_name, p)
|
||||
pf = self.make_file(p)
|
||||
replacement, results = self._replace(pf)
|
||||
|
||||
print(*self._display(pf, results), sep="\n")
|
||||
if display := list(self._display(pf, results)):
|
||||
print(*display, sep="\n")
|
||||
if results and self.args.fix and pf.path and pf.contents != replacement:
|
||||
pf.path.write_text(replacement)
|
||||
|
||||
return not results or self.args.fix and all(r.is_edit for r in results)
|
||||
|
||||
def _replace(self, pf: PythonFile) -> tuple[str, list[LintResult]]:
|
||||
def _error(self, pf: PythonFileT, result: LintResult) -> None:
|
||||
"""Called on files that are unparseable"""
|
||||
|
||||
def _replace(self, pf: PythonFileT) -> tuple[str, list[LintResult]]:
|
||||
# Because of recursive replacements, we need to repeat replacing and reparsing
|
||||
# from the inside out until all possible replacements are complete
|
||||
previous_result_count = float("inf")
|
||||
@ -400,21 +424,33 @@ class FileLinter(ABC):
|
||||
|
||||
while True:
|
||||
try:
|
||||
results = list(self._lint(pf))
|
||||
results = sorted(self._lint(pf), key=LintResult.sort_key)
|
||||
except IndentationError as e:
|
||||
error, (_name, lineno, column, _line) = e.args
|
||||
|
||||
results = [LintResult(error, lineno, column)]
|
||||
self._error(pf, *results)
|
||||
|
||||
if first_results is None:
|
||||
first_results = sorted(results, key=LintResult.sort_key)
|
||||
except ParseError as e:
|
||||
results = [LintResult(str(e), *e.token.start)]
|
||||
self._error(pf, *results)
|
||||
|
||||
for i, ri in enumerate(results):
|
||||
if not ri.is_recursive:
|
||||
for rj in results[i + 1 :]:
|
||||
if ri.contains(rj):
|
||||
rj.is_recursive = True
|
||||
else:
|
||||
break
|
||||
|
||||
first_results = first_results or results
|
||||
if not results or len(results) >= previous_result_count:
|
||||
break
|
||||
previous_result_count = len(results)
|
||||
|
||||
lines = pf.lines[:]
|
||||
for r in reversed(results):
|
||||
if not r.is_recursive:
|
||||
if r.is_edit and not r.is_recursive:
|
||||
r.apply(lines)
|
||||
replacement = "".join(lines)
|
||||
|
||||
@ -429,27 +465,23 @@ class FileLinter(ABC):
|
||||
|
||||
return replacement, first_results
|
||||
|
||||
def _display(self, pf: PythonFile, results: list[LintResult]) -> Iterator[str]:
|
||||
def _display(self, pf: PythonFileT, results: list[LintResult]) -> Iterator[str]:
|
||||
"""Emit a series of human-readable strings representing the results"""
|
||||
show_edits = not self.args.fix or self.args.verbose
|
||||
|
||||
first = True
|
||||
for r in results:
|
||||
if show_edits or r.is_edit:
|
||||
if self.args.test or self.args.lintrunner:
|
||||
msg = r.as_message(code=self.code, path=str(pf.path))
|
||||
yield json.dumps(msg.asdict(), sort_keys=True)
|
||||
continue
|
||||
if first:
|
||||
first = False
|
||||
else:
|
||||
if self.args.lintrunner:
|
||||
msg = r.as_message(code=self.code, path=str(pf.path))
|
||||
yield json.dumps(msg.asdict(), sort_keys=True)
|
||||
else:
|
||||
if self.result_shown:
|
||||
yield ""
|
||||
else:
|
||||
self.result_shown = True
|
||||
if r.line is None:
|
||||
yield f"{pf.path}: {r.name}"
|
||||
else:
|
||||
yield from (i.rstrip() for i in self._display_window(pf, r))
|
||||
|
||||
def _display_window(self, pf: PythonFile, r: LintResult) -> Iterator[str]:
|
||||
def _display_window(self, pf: PythonFileT, r: LintResult) -> Iterator[str]:
|
||||
"""Display a window onto the code with an error"""
|
||||
if r.char is None or not self.report_column_numbers:
|
||||
yield f"{pf.path}:{r.line}: {r.name}"
|
||||
|
@ -38,7 +38,7 @@ def _is_def(t: TokenInfo) -> bool:
|
||||
return t.type == token.NAME and t.string in ("class", "def")
|
||||
|
||||
|
||||
class DocstringLinter(_linter.FileLinter):
|
||||
class DocstringLinter(_linter.FileLinter[_linter.PythonFile]):
|
||||
linter_name = "docstring_linter"
|
||||
description = DESCRIPTION
|
||||
is_fixer = False
|
||||
@ -87,7 +87,7 @@ class DocstringLinter(_linter.FileLinter):
|
||||
for i in range(start, len(tokens)):
|
||||
if tokens[i].type == token_type:
|
||||
return i
|
||||
_linter.ParseError.check(False, tokens[-1], error)
|
||||
raise _linter.ParseError(tokens[-1], error)
|
||||
|
||||
for i in defs:
|
||||
name = next_token(i + 1, token.NAME, "Definition with no name")
|
||||
|
@ -22,7 +22,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
ERROR = "Builtin `set` is deprecated"
|
||||
IMPORT_LINE = "from torch.utils._ordered_set import OrderedSet\n"
|
||||
IMPORT_LINE = "from torch.utils._ordered_set import OrderedSet\n\n"
|
||||
|
||||
DESCRIPTION = """`set_linter` is a lintrunner linter which finds usages of the
|
||||
Python built-in class `set` in Python code, and optionally replaces them with
|
||||
@ -73,29 +73,8 @@ tuple is more time-efficient than an OrderedSet and also has less visual clutter
|
||||
"""
|
||||
|
||||
|
||||
class SetLinter(_linter.FileLinter):
|
||||
linter_name = "set_linter"
|
||||
description = DESCRIPTION
|
||||
epilog = EPILOG
|
||||
report_column_numbers = True
|
||||
|
||||
def _lint(self, pf: _linter.PythonFile) -> Iterator[_linter.LintResult]:
|
||||
pl = PythonLines(pf)
|
||||
for b in pl.braced_sets:
|
||||
yield _linter.LintResult(ERROR, *b[0].start, "OrderedSet([", 1)
|
||||
yield _linter.LintResult(ERROR, *b[-1].start, "])", 1)
|
||||
|
||||
for b in pl.sets:
|
||||
yield _linter.LintResult(ERROR, *b.start, "OrderedSet", 3)
|
||||
|
||||
if (pl.sets or pl.braced_sets) and (ins := pl.insert_import_line) is not None:
|
||||
yield _linter.LintResult(
|
||||
"Add import for OrderedSet", ins, 0, IMPORT_LINE, 0
|
||||
)
|
||||
|
||||
|
||||
@dc.dataclass
|
||||
class TokenLine:
|
||||
class LineWithSets:
|
||||
"""A logical line of Python tokens, terminated by a NEWLINE or the end of file"""
|
||||
|
||||
tokens: list[TokenInfo]
|
||||
@ -123,13 +102,11 @@ class TokenLine:
|
||||
after = i < len(self.tokens) - 1 and self.tokens[i + 1]
|
||||
if t.string == "Set" and t.type == token.NAME:
|
||||
return after and after.string == "[" and after.type == token.OP
|
||||
if not (t.string == "set" and t.type == token.NAME):
|
||||
return False
|
||||
if i and self.tokens[i - 1].string in ("def", "."):
|
||||
return False
|
||||
if after and after.string == "=" and after.type == token.OP:
|
||||
return False
|
||||
return True
|
||||
return (
|
||||
(t.string == "set" and t.type == token.NAME)
|
||||
and not (i and self.tokens[i - 1].string in ("def", "."))
|
||||
and not (after and after.string == "=" and after.type == token.OP)
|
||||
)
|
||||
|
||||
def is_braced_set(self, begin: int, end: int) -> bool:
|
||||
if begin + 1 == end or self.tokens[begin].string != "{":
|
||||
@ -151,43 +128,50 @@ class TokenLine:
|
||||
return not empty
|
||||
|
||||
|
||||
class PythonLines:
|
||||
"""A list of lines of Python code represented by strings"""
|
||||
class SetFile(_linter.PythonFile):
|
||||
@cached_property
|
||||
def braced_sets(self) -> list[Sequence[TokenInfo]]:
|
||||
lines = [t for tl in self._lines_with_sets for t in tl.braced_sets]
|
||||
return [s for s in lines if not self.omitted(s)]
|
||||
|
||||
braced_sets: list[Sequence[TokenInfo]]
|
||||
contents: str
|
||||
lines: list[str]
|
||||
path: Path | None
|
||||
sets: list[TokenInfo]
|
||||
token_lines: list[TokenLine]
|
||||
tokens: list[TokenInfo]
|
||||
@cached_property
|
||||
def sets(self) -> list[TokenInfo]:
|
||||
tokens = [t for tl in self._lines_with_sets for t in tl.sets]
|
||||
return [t for t in tokens if not self.omitted([t])]
|
||||
|
||||
def __init__(self, pf: _linter.PythonFile) -> None:
|
||||
self.contents = pf.contents
|
||||
self.lines = pf.lines
|
||||
self.path = pf.path
|
||||
self.tokens = pf.tokens
|
||||
self.omitted = pf.omitted
|
||||
|
||||
self.token_lines = [TokenLine(tl) for tl in pf.token_lines]
|
||||
|
||||
sets = [t for tl in self.token_lines for t in tl.sets]
|
||||
self.sets = [s for s in sets if not pf.omitted([s])]
|
||||
|
||||
braced_sets = [t for tl in self.token_lines for t in tl.braced_sets]
|
||||
self.braced_sets = [s for s in braced_sets if not pf.omitted(s)]
|
||||
|
||||
froms, imports = pf.import_lines
|
||||
@cached_property
|
||||
def insert_import_line(self) -> int | None:
|
||||
froms, imports = self.import_lines
|
||||
for i in froms + imports:
|
||||
tl = pf.token_lines[i]
|
||||
tl = self.token_lines[i]
|
||||
if any(i.type == token.NAME and i.string == "OrderedSet" for i in tl):
|
||||
self.insert_import_line = None
|
||||
return
|
||||
|
||||
return None
|
||||
if section := froms or imports:
|
||||
self.insert_import_line = pf.token_lines[section[-1]][-1].start[0] + 1
|
||||
else:
|
||||
self.insert_import_line = 0
|
||||
return self._lines_with_sets[section[-1]].tokens[-1].start[0] + 1
|
||||
return self.opening_comment_lines + 1
|
||||
|
||||
@cached_property
|
||||
def _lines_with_sets(self) -> list[LineWithSets]:
|
||||
return [LineWithSets(tl) for tl in self.token_lines]
|
||||
|
||||
|
||||
class SetLinter(_linter.FileLinter[SetFile]):
|
||||
linter_name = "set_linter"
|
||||
description = DESCRIPTION
|
||||
epilog = EPILOG
|
||||
report_column_numbers = True
|
||||
|
||||
def _lint(self, sf: SetFile) -> Iterator[_linter.LintResult]:
|
||||
if (sf.sets or sf.braced_sets) and (ins := sf.insert_import_line) is not None:
|
||||
yield _linter.LintResult(
|
||||
"Add import for OrderedSet", ins, 0, IMPORT_LINE, 0
|
||||
)
|
||||
for b in sf.braced_sets:
|
||||
yield _linter.LintResult(ERROR, *b[0].start, "OrderedSet([", 1)
|
||||
yield _linter.LintResult(ERROR, *b[-1].start, "])", 1)
|
||||
|
||||
for s in sf.sets:
|
||||
yield _linter.LintResult(ERROR, *s.start, "OrderedSet", 3)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -5,8 +5,6 @@ import os
|
||||
from pathlib import Path
|
||||
from unittest import mock, TestCase
|
||||
|
||||
from tools.linter.adapters._linter import PythonFile
|
||||
|
||||
|
||||
class LinterTestCase(TestCase):
|
||||
LinterClass = None
|
||||
@ -15,13 +13,13 @@ class LinterTestCase(TestCase):
|
||||
def assertExpected(self, path: Path, actual: str, suffix: str) -> None:
|
||||
expected_file = Path(f"{path}.{suffix}")
|
||||
if not self.rewrite_expected and expected_file.exists():
|
||||
self.assertEqual(actual, expected_file.read_text())
|
||||
self.assertEqual(expected_file.read_text(), actual)
|
||||
else:
|
||||
expected_file.write_text(actual)
|
||||
|
||||
def replace(self, s: str):
|
||||
linter = self.LinterClass("dummy")
|
||||
pf = PythonFile(linter.linter_name, contents=s)
|
||||
pf = self.LinterClass.make_file(contents=s)
|
||||
replacement, _results = linter._replace(pf)
|
||||
return replacement
|
||||
|
||||
@ -45,9 +43,10 @@ class LinterTestCase(TestCase):
|
||||
linter.lint_all()
|
||||
self.assertExpected(path, mock_stdout.getvalue(), "lintrunner")
|
||||
|
||||
replacement, results = "(no replacement)", "(no results)"
|
||||
with self.subTest("from-lintrunner"):
|
||||
linter = self.LinterClass(["--lintrunner", str(path), *args])
|
||||
pf = PythonFile(linter.linter_name, path)
|
||||
pf = self.LinterClass.make_file(path)
|
||||
replacement, results = linter._replace(pf)
|
||||
|
||||
actual = [json.loads(d) for d in linter._display(pf, results)]
|
||||
|
@ -29,7 +29,7 @@
|
||||
"name": "Suggested fixes for set_linter",
|
||||
"original": "# mypy: ignore-errors\n\nimport collections\nimport types\nfrom typing import Any, Dict, List, Optional, TYPE_CHECKING\n\nimport torch\nimport torch.fx\nfrom torch._guards import Source\n\nfrom ..utils import (\n namedtuple_fields,\n odict_values,\n # OrderedSet,\n set_example_value,\n)\nfrom .base import MutableLocal, VariableTracker, VariableTrackerContainer\n\nif TYPE_CHECKING:\n from torch._dynamo.codegen import PyCodegen\n\n\nclass BaseListVariable(VariableTrackerContainer):\n our_container = set\n",
|
||||
"path": "tools/test/set_linter_testdata/includes.py.txt",
|
||||
"replacement": "# mypy: ignore-errors\n\nimport collections\nimport types\nfrom typing import Any, Dict, List, Optional, TYPE_CHECKING\n\nimport torch\nimport torch.fx\nfrom torch._guards import Source\n\nfrom ..utils import (\n namedtuple_fields,\n odict_values,\n # OrderedSet,\n set_example_value,\n)\nfrom .base import MutableLocal, VariableTracker, VariableTrackerContainer\nfrom torch.utils._ordered_set import OrderedSet\n\nif TYPE_CHECKING:\n from torch._dynamo.codegen import PyCodegen\n\n\nclass BaseListVariable(VariableTrackerContainer):\n our_container = OrderedSet\n",
|
||||
"replacement": "# mypy: ignore-errors\n\nimport collections\nimport types\nfrom typing import Any, Dict, List, Optional, TYPE_CHECKING\n\nimport torch\nimport torch.fx\nfrom torch._guards import Source\n\nfrom ..utils import (\n namedtuple_fields,\n odict_values,\n # OrderedSet,\n set_example_value,\n)\nfrom .base import MutableLocal, VariableTracker, VariableTrackerContainer\nfrom torch.utils._ordered_set import OrderedSet\n\n\nif TYPE_CHECKING:\n from torch._dynamo.codegen import PyCodegen\n\n\nclass BaseListVariable(VariableTrackerContainer):\n our_container = OrderedSet\n",
|
||||
"severity": "error"
|
||||
}
|
||||
]
|
||||
|
@ -17,6 +17,7 @@ from ..utils import (
|
||||
from .base import MutableLocal, VariableTracker, VariableTrackerContainer
|
||||
from torch.utils._ordered_set import OrderedSet
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch._dynamo.codegen import PyCodegen
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
# Basic tests
|
||||
import tempfile
|
||||
|
||||
print(f"{tempfile.gettempdir()}/memory_snapshot.pickle")
|
||||
|
||||
ignored = set() # noqa: set_linter
|
||||
a = set()
|
||||
|
@ -3,7 +3,7 @@
|
||||
"char": 0,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 0,
|
||||
"line": 3,
|
||||
"name": "Add import for OrderedSet",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -14,7 +14,7 @@
|
||||
"char": 4,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 4,
|
||||
"line": 7,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -25,7 +25,7 @@
|
||||
"char": 4,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 6,
|
||||
"line": 9,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -36,7 +36,7 @@
|
||||
"char": 3,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 9,
|
||||
"line": 12,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -47,7 +47,7 @@
|
||||
"char": 7,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 32,
|
||||
"line": 35,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -58,7 +58,7 @@
|
||||
"char": 9,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 32,
|
||||
"line": 35,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -69,7 +69,7 @@
|
||||
"char": 7,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 33,
|
||||
"line": 36,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -80,7 +80,7 @@
|
||||
"char": 12,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 33,
|
||||
"line": 36,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -91,7 +91,7 @@
|
||||
"char": 15,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 35,
|
||||
"line": 38,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -102,7 +102,7 @@
|
||||
"char": 36,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 35,
|
||||
"line": 38,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -113,7 +113,7 @@
|
||||
"char": 17,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 38,
|
||||
"line": 41,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -124,7 +124,7 @@
|
||||
"char": 22,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 38,
|
||||
"line": 41,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -135,7 +135,7 @@
|
||||
"char": 30,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 38,
|
||||
"line": 41,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -146,7 +146,7 @@
|
||||
"char": 50,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 38,
|
||||
"line": 41,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -157,7 +157,7 @@
|
||||
"char": 10,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 41,
|
||||
"line": 44,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -168,7 +168,7 @@
|
||||
"char": 51,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 41,
|
||||
"line": 44,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -179,7 +179,7 @@
|
||||
"char": 75,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 41,
|
||||
"line": 44,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -190,7 +190,7 @@
|
||||
"char": 77,
|
||||
"code": "SET_LINTER",
|
||||
"description": null,
|
||||
"line": 41,
|
||||
"line": 44,
|
||||
"name": "Builtin `set` is deprecated",
|
||||
"original": null,
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
@ -203,9 +203,9 @@
|
||||
"description": null,
|
||||
"line": null,
|
||||
"name": "Suggested fixes for set_linter",
|
||||
"original": "# Basic tests\n\nignored = set() # noqa: set_linter\na = set()\nb = \"set()\"\nc = set\nd = c.set\nf = (\n set(\n )\n)\nignored = (\n set( # noqa: set_linter\n )\n)\n\n# Non-sets\n\nd = {}\nlong_string = \"\"\" set()\nset() set x.set set()\n\\\"\"\"\"\n\nclass A:\n def set(self, x):\n self.x = x\n\nset = A().set\n\n# Braced sets\n\nset1 = {1}\nset2 = {1, 2}\n\niterator_set = {i for i in range(10)}\n\n# A dict with two sets.\ndict_set = {\"a\": {2, 3}, \"b\": {i for i in range(3)}}\n\n# A set containing an object constructed with a dict and a set\nsos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}\n",
|
||||
"original": "# Basic tests\nimport tempfile\n\nprint(f\"{tempfile.gettempdir()}/memory_snapshot.pickle\")\n\nignored = set() # noqa: set_linter\na = set()\nb = \"set()\"\nc = set\nd = c.set\nf = (\n set(\n )\n)\nignored = (\n set( # noqa: set_linter\n )\n)\n\n# Non-sets\n\nd = {}\nlong_string = \"\"\" set()\nset() set x.set set()\n\\\"\"\"\"\n\nclass A:\n def set(self, x):\n self.x = x\n\nset = A().set\n\n# Braced sets\n\nset1 = {1}\nset2 = {1, 2}\n\niterator_set = {i for i in range(10)}\n\n# A dict with two sets.\ndict_set = {\"a\": {2, 3}, \"b\": {i for i in range(3)}}\n\n# A set containing an object constructed with a dict and a set\nsos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}\n",
|
||||
"path": "tools/test/set_linter_testdata/python_code.py.txt",
|
||||
"replacement": "# Basic tests\n\nignored = set() # noqa: set_linter\na = OrderedSet()\nb = \"set()\"\nc = OrderedSet\nd = c.set\nf = (\n OrderedSet(\n )\n)\nignored = (\n set( # noqa: set_linter\n )\n)\n\n# Non-sets\n\nd = {}\nlong_string = \"\"\" set()\nset() set x.set set()\n\\\"\"\"\"\n\nclass A:\n def set(self, x):\n self.x = x\n\nset = A().set\n\n# Braced sets\n\nset1 = OrderedSet([1])\nset2 = OrderedSet([1, 2])\n\niterator_set = OrderedSet([i for i in range(10)])\n\n# A dict with two sets.\ndict_set = {\"a\": OrderedSet([2, 3]), \"b\": OrderedSet([i for i in range(3)])}\n\n# A set containing an object constructed with a dict and a set\nfrom torchOrderedSet([utils._ordered_set import OrdOrderedSet([redSet\nsos_set = {Somet])ing({i: i + ]) for i in range(3)}, {i + 1 for i in range(3)})}\n",
|
||||
"replacement": "# Basic tests\nimport tempfile\nfrom torch.utils._ordered_set import OrderedSet\n\n\nprint(f\"{tempfile.gettempdir()}/memory_snapshot.pickle\")\n\nignored = set() # noqa: set_linter\na = OrderedSet()\nb = \"set()\"\nc = OrderedSet\nd = c.set\nf = (\n OrderedSet(\n )\n)\nignored = (\n set( # noqa: set_linter\n )\n)\n\n# Non-sets\n\nd = {}\nlong_string = \"\"\" set()\nset() set x.set set()\n\\\"\"\"\"\n\nclass A:\n def set(self, x):\n self.x = x\n\nset = A().set\n\n# Braced sets\n\nset1 = OrderedSet([1])\nset2 = OrderedSet([1, 2])\n\niterator_set = OrderedSet([i for i in range(10)])\n\n# A dict with two sets.\ndict_set = {\"a\": OrderedSet([2, 3]), \"b\": OrderedSet([i for i in range(3)])}\n\n# A set containing an object constructed with a dict and a set\nsos_set = OrderedSet([Something({i: i + 1 for i in range(3)}, OrderedSet([i + 1 for i in range(3)]))])\n",
|
||||
"severity": "error"
|
||||
}
|
||||
]
|
||||
|
@ -1,134 +1,135 @@
|
||||
tools/test/set_linter_testdata/python_code.py.txt:0:1: Add import for OrderedSet
|
||||
tools/test/set_linter_testdata/python_code.py.txt:3:1: Add import for OrderedSet
|
||||
1 | # Basic tests
|
||||
2 |
|
||||
3 | ignored = set() # noqa: set_linter
|
||||
4 | a = set()
|
||||
5 | b = "set()"
|
||||
2 | import tempfile
|
||||
3 |
|
||||
^
|
||||
4 | print(f"{tempfile.gettempdir()}/memory_snapshot.pickle")
|
||||
5 |
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:4:5: Builtin `set` is deprecated
|
||||
2 |
|
||||
3 | ignored = set() # noqa: set_linter
|
||||
4 | a = set()
|
||||
tools/test/set_linter_testdata/python_code.py.txt:7:5: Builtin `set` is deprecated
|
||||
5 |
|
||||
6 | ignored = set() # noqa: set_linter
|
||||
7 | a = set()
|
||||
^^^
|
||||
5 | b = "set()"
|
||||
6 | c = set
|
||||
8 | b = "set()"
|
||||
9 | c = set
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:6:5: Builtin `set` is deprecated
|
||||
4 | a = set()
|
||||
5 | b = "set()"
|
||||
6 | c = set
|
||||
tools/test/set_linter_testdata/python_code.py.txt:9:5: Builtin `set` is deprecated
|
||||
7 | a = set()
|
||||
8 | b = "set()"
|
||||
9 | c = set
|
||||
^^^
|
||||
7 | d = c.set
|
||||
8 | f = (
|
||||
10 | d = c.set
|
||||
11 | f = (
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:9:4: Builtin `set` is deprecated
|
||||
7 | d = c.set
|
||||
8 | f = (
|
||||
9 | set(
|
||||
tools/test/set_linter_testdata/python_code.py.txt:12:4: Builtin `set` is deprecated
|
||||
10 | d = c.set
|
||||
11 | f = (
|
||||
12 | set(
|
||||
^^^
|
||||
10 | )
|
||||
11 | )
|
||||
13 | )
|
||||
14 | )
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:32:8: Builtin `set` is deprecated
|
||||
30 | # Braced sets
|
||||
31 |
|
||||
32 | set1 = {1}
|
||||
^
|
||||
33 | set2 = {1, 2}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:35:8: Builtin `set` is deprecated
|
||||
33 | # Braced sets
|
||||
34 |
|
||||
35 | set1 = {1}
|
||||
^
|
||||
36 | set2 = {1, 2}
|
||||
37 |
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:32:10: Builtin `set` is deprecated
|
||||
30 | # Braced sets
|
||||
31 |
|
||||
32 | set1 = {1}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:35:10: Builtin `set` is deprecated
|
||||
33 | # Braced sets
|
||||
34 |
|
||||
35 | set1 = {1}
|
||||
^
|
||||
33 | set2 = {1, 2}
|
||||
34 |
|
||||
36 | set2 = {1, 2}
|
||||
37 |
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:33:8: Builtin `set` is deprecated
|
||||
31 |
|
||||
32 | set1 = {1}
|
||||
33 | set2 = {1, 2}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:36:8: Builtin `set` is deprecated
|
||||
34 |
|
||||
35 | set1 = {1}
|
||||
36 | set2 = {1, 2}
|
||||
^
|
||||
34 |
|
||||
35 | iterator_set = {i for i in range(10)}
|
||||
37 |
|
||||
38 | iterator_set = {i for i in range(10)}
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:33:13: Builtin `set` is deprecated
|
||||
31 |
|
||||
32 | set1 = {1}
|
||||
33 | set2 = {1, 2}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:36:13: Builtin `set` is deprecated
|
||||
34 |
|
||||
35 | set1 = {1}
|
||||
36 | set2 = {1, 2}
|
||||
^
|
||||
34 |
|
||||
35 | iterator_set = {i for i in range(10)}
|
||||
37 |
|
||||
38 | iterator_set = {i for i in range(10)}
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:35:16: Builtin `set` is deprecated
|
||||
33 | set2 = {1, 2}
|
||||
34 |
|
||||
35 | iterator_set = {i for i in range(10)}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:38:16: Builtin `set` is deprecated
|
||||
36 | set2 = {1, 2}
|
||||
37 |
|
||||
38 | iterator_set = {i for i in range(10)}
|
||||
^
|
||||
36 |
|
||||
37 | # A dict with two sets.
|
||||
39 |
|
||||
40 | # A dict with two sets.
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:35:37: Builtin `set` is deprecated
|
||||
33 | set2 = {1, 2}
|
||||
34 |
|
||||
35 | iterator_set = {i for i in range(10)}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:38:37: Builtin `set` is deprecated
|
||||
36 | set2 = {1, 2}
|
||||
37 |
|
||||
38 | iterator_set = {i for i in range(10)}
|
||||
^
|
||||
36 |
|
||||
37 | # A dict with two sets.
|
||||
39 |
|
||||
40 | # A dict with two sets.
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:38:18: Builtin `set` is deprecated
|
||||
36 |
|
||||
37 | # A dict with two sets.
|
||||
38 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:41:18: Builtin `set` is deprecated
|
||||
39 |
|
||||
40 | # A dict with two sets.
|
||||
41 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}}
|
||||
^
|
||||
39 |
|
||||
40 | # A set containing an object constructed with a dict and a set
|
||||
42 |
|
||||
43 | # A set containing an object constructed with a dict and a set
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:38:23: Builtin `set` is deprecated
|
||||
36 |
|
||||
37 | # A dict with two sets.
|
||||
38 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:41:23: Builtin `set` is deprecated
|
||||
39 |
|
||||
40 | # A dict with two sets.
|
||||
41 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}}
|
||||
^
|
||||
39 |
|
||||
40 | # A set containing an object constructed with a dict and a set
|
||||
42 |
|
||||
43 | # A set containing an object constructed with a dict and a set
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:38:31: Builtin `set` is deprecated
|
||||
36 |
|
||||
37 | # A dict with two sets.
|
||||
38 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:41:31: Builtin `set` is deprecated
|
||||
39 |
|
||||
40 | # A dict with two sets.
|
||||
41 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}}
|
||||
^
|
||||
39 |
|
||||
40 | # A set containing an object constructed with a dict and a set
|
||||
42 |
|
||||
43 | # A set containing an object constructed with a dict and a set
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:38:51: Builtin `set` is deprecated
|
||||
36 |
|
||||
37 | # A dict with two sets.
|
||||
38 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:41:51: Builtin `set` is deprecated
|
||||
39 |
|
||||
40 | # A dict with two sets.
|
||||
41 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}}
|
||||
^
|
||||
39 |
|
||||
40 | # A set containing an object constructed with a dict and a set
|
||||
42 |
|
||||
43 | # A set containing an object constructed with a dict and a set
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:41:11: Builtin `set` is deprecated
|
||||
39 |
|
||||
40 | # A set containing an object constructed with a dict and a set
|
||||
41 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:44:11: Builtin `set` is deprecated
|
||||
42 |
|
||||
43 | # A set containing an object constructed with a dict and a set
|
||||
44 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}
|
||||
^
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:41:52: Builtin `set` is deprecated
|
||||
39 |
|
||||
40 | # A set containing an object constructed with a dict and a set
|
||||
41 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:44:52: Builtin `set` is deprecated
|
||||
42 |
|
||||
43 | # A set containing an object constructed with a dict and a set
|
||||
44 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}
|
||||
^
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:41:76: Builtin `set` is deprecated
|
||||
39 |
|
||||
40 | # A set containing an object constructed with a dict and a set
|
||||
41 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:44:76: Builtin `set` is deprecated
|
||||
42 |
|
||||
43 | # A set containing an object constructed with a dict and a set
|
||||
44 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}
|
||||
^
|
||||
|
||||
tools/test/set_linter_testdata/python_code.py.txt:41:78: Builtin `set` is deprecated
|
||||
39 |
|
||||
40 | # A set containing an object constructed with a dict and a set
|
||||
41 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}
|
||||
tools/test/set_linter_testdata/python_code.py.txt:44:78: Builtin `set` is deprecated
|
||||
42 |
|
||||
43 | # A set containing an object constructed with a dict and a set
|
||||
44 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}
|
||||
^
|
||||
|
@ -1,4 +1,9 @@
|
||||
# Basic tests
|
||||
import tempfile
|
||||
from torch.utils._ordered_set import OrderedSet
|
||||
|
||||
|
||||
print(f"{tempfile.gettempdir()}/memory_snapshot.pickle")
|
||||
|
||||
ignored = set() # noqa: set_linter
|
||||
a = OrderedSet()
|
||||
@ -38,5 +43,4 @@ iterator_set = OrderedSet([i for i in range(10)])
|
||||
dict_set = {"a": OrderedSet([2, 3]), "b": OrderedSet([i for i in range(3)])}
|
||||
|
||||
# A set containing an object constructed with a dict and a set
|
||||
from torchOrderedSet([utils._ordered_set import OrdOrderedSet([redSet
|
||||
sos_set = {Somet])ing({i: i + ]) for i in range(3)}, {i + 1 for i in range(3)})}
|
||||
sos_set = OrderedSet([Something({i: i + 1 for i in range(3)}, OrderedSet([i + 1 for i in range(3)]))])
|
||||
|
@ -6,8 +6,7 @@ from pathlib import Path
|
||||
from token import NAME
|
||||
from tokenize import TokenInfo
|
||||
|
||||
from tools.linter.adapters._linter import PythonFile
|
||||
from tools.linter.adapters.set_linter import PythonLines, SetLinter
|
||||
from tools.linter.adapters.set_linter import SetLinter
|
||||
|
||||
|
||||
_PARENT = Path(__file__).parent.absolute()
|
||||
@ -27,21 +26,16 @@ INCLUDES_FILE2 = TESTDATA / "includes_doesnt_change.py.txt"
|
||||
FILES = TESTFILE, INCLUDES_FILE, INCLUDES_FILE2
|
||||
|
||||
|
||||
def python_lines(p: str | Path) -> PythonLines:
|
||||
pf = PythonFile.make(SetLinter.linter_name, p)
|
||||
return PythonLines(pf)
|
||||
|
||||
|
||||
class TestSetLinter(LinterTestCase):
|
||||
maxDiff = 10000000
|
||||
LinterClass = SetLinter
|
||||
|
||||
def test_get_all_tokens(self) -> None:
|
||||
self.assertEqual(EXPECTED_SETS, python_lines(TESTFILE).sets)
|
||||
self.assertEqual(EXPECTED_SETS, SetLinter.make_file(TESTFILE).sets)
|
||||
|
||||
def test_omitted_lines(self) -> None:
|
||||
actual = sorted(python_lines(TESTFILE).omitted.omitted)
|
||||
expected = [3, 13]
|
||||
actual = sorted(SetLinter.make_file(TESTFILE).omitted.omitted)
|
||||
expected = [6, 16]
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_linting(self) -> None:
|
||||
@ -62,13 +56,14 @@ class TestSetLinter(LinterTestCase):
|
||||
"{One({1: [2], 2: {3}, 3: {4: 5}})}",
|
||||
{0: 25, 2: 24, 3: 23, 6: 8, 12: 14, 18: 22},
|
||||
),
|
||||
("f'{a}'", {}),
|
||||
)
|
||||
for s, expected in TESTS:
|
||||
pl = python_lines(s)
|
||||
pf = SetLinter.make_file(s)
|
||||
if s:
|
||||
actual = pl.token_lines[0].bracket_pairs
|
||||
actual = pf._lines_with_sets[0].bracket_pairs
|
||||
else:
|
||||
self.assertEqual(pl.token_lines, [])
|
||||
self.assertEqual(pf._lines_with_sets, [])
|
||||
actual = {}
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@ -84,13 +79,13 @@ class TestSetLinter(LinterTestCase):
|
||||
("{One({'a': 1}), Two([{}, {2}, {1, 2}])}", 3),
|
||||
)
|
||||
for s, expected in TESTS:
|
||||
pl = python_lines(s)
|
||||
actual = pl.token_lines and pl.token_lines[0].braced_sets
|
||||
pf = SetLinter.make_file(s)
|
||||
actual = pf._lines_with_sets and pf._lines_with_sets[0].braced_sets
|
||||
self.assertEqual(len(actual), expected)
|
||||
|
||||
|
||||
EXPECTED_SETS = [
|
||||
TokenInfo(NAME, "set", (4, 4), (4, 7), "a = set()\n"),
|
||||
TokenInfo(NAME, "set", (6, 4), (6, 7), "c = set\n"),
|
||||
TokenInfo(NAME, "set", (9, 3), (9, 6), " set(\n"),
|
||||
TokenInfo(NAME, "set", (7, 4), (7, 7), "a = set()\n"),
|
||||
TokenInfo(NAME, "set", (9, 4), (9, 7), "c = set\n"),
|
||||
TokenInfo(NAME, "set", (12, 3), (12, 6), " set(\n"),
|
||||
]
|
||||
|
Reference in New Issue
Block a user