Skip to content

Commit 6f4ab6e

Browse files
committed
pythongh-104504: Run mypy on cases_generator
1 parent 02079b0 commit 6f4ab6e

File tree

9 files changed

+65
-65
lines changed

9 files changed

+65
-65
lines changed

.github/workflows/mypy.yml

+16-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ on:
88
pull_request:
99
paths:
1010
- "Tools/clinic/**"
11+
- "Tools/cases_generator/**"
1112
- ".github/workflows/mypy.yml"
1213
workflow_dispatch:
1314

@@ -24,7 +25,7 @@ concurrency:
2425
cancel-in-progress: true
2526

2627
jobs:
27-
mypy:
28+
mypy-clinic:
2829
name: Run mypy on Tools/clinic/
2930
runs-on: ubuntu-latest
3031
timeout-minutes: 10
@@ -37,3 +38,17 @@ jobs:
3738
cache-dependency-path: Tools/clinic/requirements-dev.txt
3839
- run: pip install -r Tools/clinic/requirements-dev.txt
3940
- run: mypy --config-file Tools/clinic/mypy.ini
41+
42+
mypy-cases-generator:
43+
name: Run mypy on Tools/cases_generator/
44+
runs-on: ubuntu-latest
45+
timeout-minutes: 10
46+
steps:
47+
- uses: actions/checkout@v3
48+
- uses: actions/setup-python@v4
49+
with:
50+
python-version: "3.x"
51+
cache: pip
52+
cache-dependency-path: Tools/cases_generator/requirements-dev.txt
53+
- run: pip install -r Tools/cases_generator/requirements-dev.txt
54+
- run: mypy --config-file Tools/cases_generator/mypy.ini

Tools/cases_generator/analysis.py

-4
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,6 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None:
171171
case parsing.Pseudo(name):
172172
self.pseudos[name] = thing
173173
self.everything.append(thing)
174-
case _:
175-
typing.assert_never(thing)
176174
if not psr.eof():
177175
raise psr.make_syntax_error(f"Extra stuff at the end of {filename}")
178176

@@ -408,6 +406,4 @@ def check_macro_components(
408406
components.append(self.instrs[name])
409407
case parsing.CacheEffect():
410408
components.append(uop)
411-
case _:
412-
typing.assert_never(uop)
413409
return components

Tools/cases_generator/flags.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ class InstructionFlags:
1616
HAS_FREE_FLAG: bool
1717
HAS_LOCAL_FLAG: bool
1818

19-
def __post_init__(self):
19+
def __post_init__(self) -> None:
2020
self.bitmask = {name: (1 << i) for i, name in enumerate(self.names())}
2121

2222
@staticmethod
23-
def fromInstruction(instr: parsing.Node):
23+
def fromInstruction(instr: parsing.Node) -> 'InstructionFlags':
2424

2525
has_free = (
2626
variable_used(instr, "PyCell_New")
@@ -41,15 +41,15 @@ def fromInstruction(instr: parsing.Node):
4141
)
4242

4343
@staticmethod
44-
def newEmpty():
44+
def newEmpty() -> 'InstructionFlags':
4545
return InstructionFlags(False, False, False, False, False, False)
4646

4747
def add(self, other: "InstructionFlags") -> None:
4848
for name, value in dataclasses.asdict(other).items():
4949
if value:
5050
setattr(self, name, value)
5151

52-
def names(self, value=None) -> list[str]:
52+
def names(self, value: bool|None = None) -> list[str]:
5353
if value is None:
5454
return list(dataclasses.asdict(self).keys())
5555
return [n for n, v in dataclasses.asdict(self).items() if v == value]
@@ -62,7 +62,7 @@ def bitmap(self) -> int:
6262
return flags
6363

6464
@classmethod
65-
def emit_macros(cls, out: Formatter):
65+
def emit_macros(cls, out: Formatter) -> None:
6666
flags = cls.newEmpty()
6767
for name, value in flags.bitmask.items():
6868
out.emit(f"#define {name} ({value})")

Tools/cases_generator/formatting.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,13 @@ def reset_lineno(self) -> None:
5858
self.set_lineno(self.lineno + 1, self.filename)
5959

6060
@contextlib.contextmanager
61-
def indent(self):
61+
def indent(self) -> typing.Iterator[None]:
6262
self.prefix += " "
6363
yield
6464
self.prefix = self.prefix[:-4]
6565

6666
@contextlib.contextmanager
67-
def block(self, head: str, tail: str = ""):
67+
def block(self, head: str, tail: str = "") -> typing.Iterator[None]:
6868
if head:
6969
self.emit(head + " {")
7070
else:
@@ -77,7 +77,7 @@ def stack_adjust(
7777
self,
7878
input_effects: list[StackEffect],
7979
output_effects: list[StackEffect],
80-
):
80+
) -> None:
8181
shrink, isym = list_effect_size(input_effects)
8282
grow, osym = list_effect_size(output_effects)
8383
diff = grow - shrink
@@ -90,7 +90,7 @@ def stack_adjust(
9090
if osym and osym != isym:
9191
self.emit(f"STACK_GROW({osym});")
9292

93-
def declare(self, dst: StackEffect, src: StackEffect | None):
93+
def declare(self, dst: StackEffect, src: StackEffect | None) -> None:
9494
if dst.name == UNUSED or dst.cond == "0":
9595
return
9696
typ = f"{dst.type}" if dst.type else "PyObject *"
@@ -107,7 +107,7 @@ def declare(self, dst: StackEffect, src: StackEffect | None):
107107
sepa = "" if typ.endswith("*") else " "
108108
self.emit(f"{typ}{sepa}{dst.name}{init};")
109109

110-
def assign(self, dst: StackEffect, src: StackEffect):
110+
def assign(self, dst: StackEffect, src: StackEffect) -> None:
111111
if src.name == UNUSED or dst.name == UNUSED:
112112
return
113113
cast = self.cast(dst, src)

Tools/cases_generator/generate_cases.py

+15-36
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
MacroInstruction,
2424
MacroParts,
2525
PseudoInstruction,
26-
StackEffect,
2726
OverriddenInstructionPlaceHolder,
2827
TIER_ONE,
2928
TIER_TWO,
@@ -183,17 +182,11 @@ def effect_str(effects: list[StackEffect]) -> str:
183182
assert target_instr
184183
target_popped = effect_str(target_instr.input_effects)
185184
target_pushed = effect_str(target_instr.output_effects)
186-
if popped is None and pushed is None:
187-
popped, pushed = target_popped, target_pushed
188-
else:
189-
assert popped == target_popped
190-
assert pushed == target_pushed
191-
case _:
192-
typing.assert_never(thing)
185+
popped, pushed = target_popped, target_pushed
193186
return instr, popped, pushed
194187

195188
@contextlib.contextmanager
196-
def metadata_item(self, signature, open, close):
189+
def metadata_item(self, signature: str, open: str, close: str) -> typing.Iterator[None]:
197190
self.out.emit("")
198191
self.out.emit(f"extern {signature};")
199192
self.out.emit("#ifdef NEED_OPCODE_METADATA")
@@ -243,21 +236,21 @@ def from_source_files(self) -> str:
243236
paths = f"\n{self.out.comment} ".join(filenames)
244237
return f"{self.out.comment} from:\n{self.out.comment} {paths}\n"
245238

246-
def write_provenance_header(self):
239+
def write_provenance_header(self) -> None:
247240
self.out.write_raw(f"{self.out.comment} This file is generated by {THIS}\n")
248241
self.out.write_raw(self.from_source_files())
249242
self.out.write_raw(f"{self.out.comment} Do not edit!\n")
250243

251-
def assign_opcode_ids(self):
244+
def assign_opcode_ids(self) -> None:
252245
"""Assign IDs to opcodes"""
253246

254-
ops: list[(bool, str)] = [] # (has_arg, name) for each opcode
247+
ops: list[tuple[bool, str]] = [] # (has_arg, name) for each opcode
255248
instrumented_ops: list[str] = []
256249

257250
for instr in itertools.chain(
258251
[instr for instr in self.instrs.values() if instr.kind != "op"],
259252
self.macro_instrs.values()):
260-
253+
assert isinstance(instr, (Instruction, MacroInstruction, PseudoInstruction))
261254
name = instr.name
262255
if name.startswith('INSTRUMENTED_'):
263256
instrumented_ops.append(name)
@@ -274,11 +267,11 @@ def assign_opcode_ids(self):
274267
assert len(set(ops)) == len(ops)
275268
assert len(set(instrumented_ops)) == len(instrumented_ops)
276269

277-
opname: list[str or None] = [None] * 512
278-
opmap: dict = {}
279-
markers: dict = {}
270+
opname: list[str|None] = [None] * 512
271+
opmap: dict[str, int] = {}
272+
markers: dict[str, int] = {}
280273

281-
def map_op(op, name):
274+
def map_op(op: int, name: str) -> None:
282275
assert op < len(opname)
283276
assert opname[op] is None
284277
assert name not in opmap
@@ -320,11 +313,11 @@ def map_op(op, name):
320313
for i, op in enumerate(sorted(self.pseudos)):
321314
map_op(256 + i, op)
322315

323-
assert 255 not in opmap # 255 is reserved
316+
assert 255 not in opmap.values() # 255 is reserved
324317
self.opmap = opmap
325318
self.markers = markers
326319

327-
def write_opcode_ids(self, opcode_ids_h_filename, opcode_targets_filename):
320+
def write_opcode_ids(self, opcode_ids_h_filename: str, opcode_targets_filename: str) -> None:
328321
"""Write header file that defined the opcode IDs"""
329322

330323
with open(opcode_ids_h_filename, "w") as f:
@@ -342,10 +335,10 @@ def write_opcode_ids(self, opcode_ids_h_filename, opcode_targets_filename):
342335
self.out.emit("")
343336
self.out.emit("/* Instruction opcodes for compiled code */")
344337

345-
def define(name, opcode):
338+
def define(name: str, opcode: int) -> None:
346339
self.out.emit(f"#define {name:<38} {opcode:>3}")
347340

348-
all_pairs = []
341+
all_pairs: list[tuple[int, int, str]] = []
349342
# the second item in the tuple sorts the markers before the ops
350343
all_pairs.extend((i, 1, name) for (name, i) in self.markers.items())
351344
all_pairs.extend((i, 2, name) for (name, i) in self.opmap.items())
@@ -392,11 +385,7 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
392385
assert target_instr
393386
if format is None:
394387
format = target_instr.instr_fmt
395-
else:
396-
assert format == target_instr.instr_fmt
397388
assert format is not None
398-
case _:
399-
typing.assert_never(thing)
400389
all_formats.add(format)
401390

402391
# Turn it into a sorted list of enum values.
@@ -483,8 +472,6 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
483472
self.write_metadata_for_macro(self.macro_instrs[thing.name])
484473
case parsing.Pseudo():
485474
self.write_metadata_for_pseudo(self.pseudo_instrs[thing.name])
486-
case _:
487-
typing.assert_never(thing)
488475

489476
with self.metadata_item(
490477
"const struct opcode_macro_expansion "
@@ -520,8 +507,6 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No
520507
)
521508
case parsing.Pseudo():
522509
pass
523-
case _:
524-
typing.assert_never(thing)
525510

526511
with self.metadata_item(
527512
"const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]", "=", ";"
@@ -770,8 +755,6 @@ def write_instructions(
770755
# self.write_macro(self.macro_instrs[thing.name])
771756
case parsing.Pseudo():
772757
pass
773-
case _:
774-
typing.assert_never(thing)
775758

776759
print(
777760
f"Wrote {n_instrs} instructions and {n_macros} macros "
@@ -814,8 +797,6 @@ def write_executor_instructions(
814797
pass
815798
case parsing.Pseudo():
816799
pass
817-
case _:
818-
typing.assert_never(thing)
819800
print(
820801
f"Wrote {n_instrs} instructions and {n_uops} ops to {executor_filename}",
821802
file=sys.stderr,
@@ -843,8 +824,6 @@ def write_abstract_interpreter_instructions(
843824
pass
844825
case parsing.Pseudo():
845826
pass
846-
case _:
847-
typing.assert_never(thing)
848827
print(
849828
f"Wrote some stuff to {abstract_interpreter_filename}",
850829
file=sys.stderr,
@@ -878,7 +857,7 @@ def write_instr(self, instr: Instruction) -> None:
878857
self.out.emit(f"DISPATCH();")
879858

880859

881-
def main():
860+
def main() -> None:
882861
"""Parse command line, parse input, analyze, write output."""
883862
args = arg_parser.parse_args() # Prints message and sys.exit(2) on error
884863
if len(args.input) == 0:

Tools/cases_generator/lexer.py

+18-10
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
import re
66
from dataclasses import dataclass
7+
from collections.abc import Iterator
78

8-
def choice(*opts):
9+
10+
def choice(*opts: str) -> str:
911
return "|".join("(%s)" % opt for opt in opts)
1012

1113
# Regexes
@@ -123,13 +125,19 @@ def choice(*opts):
123125
'SWITCH', 'TYPEDEF', 'UNION', 'UNSIGNED', 'VOID',
124126
'VOLATILE', 'WHILE'
125127
)
128+
129+
# For mypy
130+
REGISTER = 'REGISTER'
131+
OVERRIDE = 'OVERRIDE'
132+
IF = 'IF'
133+
126134
for name in kwds:
127135
globals()[name] = name
128136
keywords = { name.lower() : name for name in kwds }
129137

130138

131139
def make_syntax_error(
132-
message: str, filename: str, line: int, column: int, line_text: str,
140+
message: str, filename: str | None, line: int, column: int, line_text: str,
133141
) -> SyntaxError:
134142
return SyntaxError(message, (filename, line, column, line_text))
135143

@@ -142,30 +150,30 @@ class Token:
142150
end: tuple[int, int]
143151

144152
@property
145-
def line(self):
153+
def line(self) -> int:
146154
return self.begin[0]
147155

148156
@property
149-
def column(self):
157+
def column(self) -> int:
150158
return self.begin[1]
151159

152160
@property
153-
def end_line(self):
161+
def end_line(self) -> int:
154162
return self.end[0]
155163

156164
@property
157-
def end_column(self):
165+
def end_column(self) -> int:
158166
return self.end[1]
159167

160168
@property
161-
def width(self):
169+
def width(self) -> int:
162170
return self.end[1] - self.begin[1]
163171

164-
def replaceText(self, txt):
172+
def replaceText(self, txt: str) -> 'Token':
165173
assert isinstance(txt, str)
166174
return Token(self.kind, txt, self.begin, self.end)
167175

168-
def __repr__(self):
176+
def __repr__(self) -> str:
169177
b0, b1 = self.begin
170178
e0, e1 = self.end
171179
if b0 == e0:
@@ -174,7 +182,7 @@ def __repr__(self):
174182
return f"{self.kind}({self.text!r}, {b0}:{b1}, {e0}:{e1})"
175183

176184

177-
def tokenize(src, line=1, filename=None):
185+
def tokenize(src: str, line: int = 1, filename: str | None = None) -> Iterator[Token]:
178186
linestart = -1
179187
for m in matcher.finditer(src):
180188
start, end = m.span()

Tools/cases_generator/parsing.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Context(NamedTuple):
3232
end: int
3333
owner: PLexer
3434

35-
def __repr__(self):
35+
def __repr__(self) -> str:
3636
return f"<{self.owner.filename}: {self.begin}-{self.end}>"
3737

3838

@@ -75,7 +75,7 @@ class StackEffect(Node):
7575
size: str = "" # Optional `[size]`
7676
# Note: size cannot be combined with type or cond
7777

78-
def __repr__(self):
78+
def __repr__(self) -> str:
7979
items = [self.name, self.type, self.cond, self.size]
8080
while items and items[-1] == "":
8181
del items[-1]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Requirements file for external linters and checks we run on Tools/clinic/ in CI
2+
mypy==1.4.1

0 commit comments

Comments
 (0)