Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pyflakes/checker.py: 88%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1209 statements  

1""" 

2Main module. 

3 

4Implement the central Checker class. 

5Also, it models the Bindings and Scopes. 

6""" 

7import __future__ 

8import builtins 

9import ast 

10import collections 

11import contextlib 

12import functools 

13import os 

14import re 

15import string 

16import sys 

17from collections.abc import Iterable 

18 

19from pyflakes import messages 

20 

21PYPY = hasattr(sys, 'pypy_version_info') 

22 

23builtin_vars = frozenset(dir(builtins)) | { 

24 # Globally defined names which are not attributes of the builtins module, or 

25 # are only present on some platforms. 

26 '__file__', '__builtins__', '__annotations__', 'WindowsError' 

27} 

28 

29 

30@functools.cache 

31def _custom_builtins() -> frozenset[str]: 

32 var = os.environ.get('PYFLAKES_BUILTINS') 

33 if var is not None: 

34 return frozenset(var.split(',')) 

35 else: 

36 return frozenset() 

37 

38 

39parse_format_string = string.Formatter().parse 

40 

41 

42@functools.cache 

43def _doctest_parser(): 

44 import doctest 

45 return doctest.DocTestParser().get_examples 

46 

47 

48def getAlternatives(n): 

49 if isinstance(n, ast.If): 

50 return [n.body] 

51 elif isinstance(n, ast.Try): 

52 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers] 

53 elif isinstance(n, ast.Match): 

54 return [mc.body for mc in n.cases] 

55 

56 

57FOR_TYPES = (ast.For, ast.AsyncFor) 

58 

59 

60def _is_singleton(node): # type: (ast.AST) -> bool 

61 return ( 

62 isinstance(node, ast.Constant) and 

63 isinstance(node.value, (bool, type(Ellipsis), type(None))) 

64 ) 

65 

66 

67def _is_tuple_constant(node): # type: (ast.AST) -> bool 

68 return ( 

69 isinstance(node, ast.Tuple) and 

70 all(_is_constant(elt) for elt in node.elts) 

71 ) 

72 

73 

74def _is_constant(node): 

75 return isinstance(node, ast.Constant) or _is_tuple_constant(node) 

76 

77 

78def _is_const_non_singleton(node): # type: (ast.AST) -> bool 

79 return _is_constant(node) and not _is_singleton(node) 

80 

81 

82def _is_name_or_attr(node, name): # type: (ast.AST, str) -> bool 

83 return ( 

84 (isinstance(node, ast.Name) and node.id == name) or 

85 (isinstance(node, ast.Attribute) and node.attr == name) 

86 ) 

87 

88 

89MAPPING_KEY_RE = re.compile(r'\(([^()]*)\)') 

90CONVERSION_FLAG_RE = re.compile('[#0+ -]*') 

91WIDTH_RE = re.compile(r'(?:\*|\d*)') 

92PRECISION_RE = re.compile(r'(?:\.(?:\*|\d*))?') 

93LENGTH_RE = re.compile('[hlL]?') 

94# https://docs.python.org/3/library/stdtypes.html#old-string-formatting 

95VALID_CONVERSIONS = frozenset('diouxXeEfFgGcrsa%') 

96 

97 

98def _must_match(regex, string, pos): 

99 match = regex.match(string, pos) 

100 assert match is not None 

101 return match 

102 

103 

104def parse_percent_format(s): 

105 """Parses the string component of a `'...' % ...` format call 

106 

107 Copied from https://github.com/asottile/pyupgrade at v1.20.1 

108 """ 

109 

110 def _parse_inner(): 

111 string_start = 0 

112 string_end = 0 

113 in_fmt = False 

114 

115 i = 0 

116 while i < len(s): 

117 if not in_fmt: 

118 try: 

119 i = s.index('%', i) 

120 except ValueError: # no more % fields! 

121 yield s[string_start:], None 

122 return 

123 else: 

124 string_end = i 

125 i += 1 

126 in_fmt = True 

127 else: 

128 key_match = MAPPING_KEY_RE.match(s, i) 

129 if key_match: 

130 key = key_match.group(1) 

131 i = key_match.end() 

132 else: 

133 key = None 

134 

135 conversion_flag_match = _must_match(CONVERSION_FLAG_RE, s, i) 

136 conversion_flag = conversion_flag_match.group() or None 

137 i = conversion_flag_match.end() 

138 

139 width_match = _must_match(WIDTH_RE, s, i) 

140 width = width_match.group() or None 

141 i = width_match.end() 

142 

143 precision_match = _must_match(PRECISION_RE, s, i) 

144 precision = precision_match.group() or None 

145 i = precision_match.end() 

146 

147 # length modifier is ignored 

148 i = _must_match(LENGTH_RE, s, i).end() 

149 

150 try: 

151 conversion = s[i] 

152 except IndexError: 

153 raise ValueError('end-of-string while parsing format') 

154 i += 1 

155 

156 fmt = (key, conversion_flag, width, precision, conversion) 

157 yield s[string_start:string_end], fmt 

158 

159 in_fmt = False 

160 string_start = i 

161 

162 if in_fmt: 

163 raise ValueError('end-of-string while parsing format') 

164 

165 return tuple(_parse_inner()) 

166 

167 

168def iter_child_nodes(node, omit=None): 

169 """ 

170 Yield all direct child nodes of *node*, that is, all fields that 

171 are nodes and all items of fields that are lists of nodes. 

172 

173 :param node: AST node to be iterated upon 

174 :param omit: String or tuple of strings denoting the 

175 attributes of the node to be omitted from 

176 further parsing 

177 :param _fields_order: Order of AST node fields 

178 """ 

179 for name in node.__class__._fields: 

180 if omit and name in omit: 

181 continue 

182 field = getattr(node, name, None) 

183 if isinstance(field, ast.AST): 

184 yield field 

185 elif isinstance(field, list): 

186 for item in field: 

187 if isinstance(item, ast.AST): 

188 yield item 

189 

190 

191def iter_dict_children(node: ast.Dict) -> Iterable[tuple[ast.AST, ast.AST]]: 

192 return zip(node.keys, node.values) 

193 

194 

195def convert_to_value(item): 

196 if isinstance(item, ast.Constant): 

197 return item.value 

198 elif isinstance(item, ast.Tuple): 

199 return tuple(convert_to_value(i) for i in item.elts) 

200 elif isinstance(item, ast.Name): 

201 return VariableKey(item=item) 

202 else: 

203 return UnhandledKeyType() 

204 

205 

206def is_notimplemented_name_node(node): 

207 return isinstance(node, ast.Name) and getNodeName(node) == 'NotImplemented' 

208 

209 

210class Binding: 

211 """ 

212 Represents the binding of a value to a name. 

213 

214 The checker uses this to keep track of which names have been bound and 

215 which names have not. See L{Assignment} for a special type of binding that 

216 is checked with stricter rules. 

217 

218 @ivar used: pair of (L{Scope}, node) indicating the scope and 

219 the node that this binding was last used. 

220 """ 

221 

222 def __init__(self, name, source): 

223 self.name = name 

224 self.source = source 

225 self.used = False 

226 

227 def __repr__(self): # pragma: no cover 

228 return '<{} object {!r} from line {!r} at 0x{:x}>'.format( 

229 self.__class__.__name__, 

230 self.name, 

231 self.source.lineno, 

232 id(self), 

233 ) 

234 

235 def redefines(self, other): 

236 return isinstance(other, Definition) and self.name == other.name 

237 

238 

239class Definition(Binding): 

240 """ 

241 A binding that defines a function or a class. 

242 """ 

243 def redefines(self, other): 

244 return ( 

245 super().redefines(other) or 

246 (isinstance(other, Assignment) and self.name == other.name) 

247 ) 

248 

249 

250class Builtin(Definition): 

251 """A definition created for all Python builtins.""" 

252 

253 def __init__(self, name): 

254 super().__init__(name, None) 

255 

256 def __repr__(self): # pragma: no cover 

257 return '<{} object {!r} at 0x{:x}>'.format( 

258 self.__class__.__name__, 

259 self.name, 

260 id(self) 

261 ) 

262 

263 

264class UnhandledKeyType: 

265 """ 

266 A dictionary key of a type that we cannot or do not check for duplicates. 

267 """ 

268 

269 

270class VariableKey: 

271 """ 

272 A dictionary key which is a variable. 

273 

274 @ivar item: The variable AST object. 

275 """ 

276 def __init__(self, item): 

277 self.name = item.id 

278 

279 def __eq__(self, compare): 

280 return ( 

281 compare.__class__ == self.__class__ and 

282 compare.name == self.name 

283 ) 

284 

285 def __hash__(self): 

286 return hash(self.name) 

287 

288 

289class Importation(Definition): 

290 """ 

291 A binding created by an import statement. 

292 

293 @ivar fullName: The complete name given to the import statement, 

294 possibly including multiple dotted components. 

295 @type fullName: C{str} 

296 """ 

297 

298 def __init__(self, name, source, full_name=None, *, is_lazy: int): 

299 self.fullName = full_name or name 

300 self.redefined = [] 

301 self.is_lazy = is_lazy 

302 super().__init__(name, source) 

303 

304 def redefines(self, other): 

305 if isinstance(other, SubmoduleImportation): 

306 # See note in SubmoduleImportation about RedefinedWhileUnused 

307 return self.fullName == other.fullName 

308 return isinstance(other, Definition) and self.name == other.name 

309 

310 def _has_alias(self): 

311 """Return whether importation needs an as clause.""" 

312 return not self.fullName.split('.')[-1] == self.name 

313 

314 @property 

315 def _lazy_s(self) -> str: 

316 return 'lazy ' if self.is_lazy else '' 

317 

318 @property 

319 def _alias_s(self) -> str: 

320 return f' as {self.name}' if self._has_alias() else '' 

321 

322 @property 

323 def source_statement(self): 

324 """Generate a source statement equivalent to the import.""" 

325 return f'{self._lazy_s}import {self.fullName}{self._alias_s}' 

326 

327 @property 

328 def imported_name(self): 

329 """Return import full name with alias.""" 

330 return f'{self.fullName}{self._alias_s}' 

331 

332 

333class SubmoduleImportation(Importation): 

334 """ 

335 A binding created by a submodule import statement. 

336 

337 A submodule import is a special case where the root module is implicitly 

338 imported, without an 'as' clause, and the submodule is also imported. 

339 Python does not restrict which attributes of the root module may be used. 

340 

341 This class is only used when the submodule import is without an 'as' clause. 

342 

343 pyflakes handles this case by registering the root module name in the scope, 

344 allowing any attribute of the root module to be accessed. 

345 

346 RedefinedWhileUnused is suppressed in `redefines` unless the submodule 

347 name is also the same, to avoid false positives. 

348 """ 

349 

350 def __init__(self, name, source, *, is_lazy: int): 

351 # A dot should only appear in the name when it is a submodule import 

352 assert '.' in name and (not source or isinstance(source, ast.Import)) 

353 package_name = name.split('.')[0] 

354 super().__init__(package_name, source, is_lazy=is_lazy) 

355 self.fullName = name 

356 

357 def redefines(self, other): 

358 if isinstance(other, Importation): 

359 return self.fullName == other.fullName 

360 return super().redefines(other) 

361 

362 @property 

363 def source_statement(self): 

364 return f'{self._lazy_s}import {self.fullName}' 

365 

366 @property 

367 def imported_name(self): 

368 return self.fullName 

369 

370 

371class ImportationFrom(Importation): 

372 

373 def __init__(self, name, source, module, real_name=None, *, is_lazy: int): 

374 self.module = module 

375 self.real_name = real_name or name 

376 

377 if module.endswith('.'): 

378 full_name = module + self.real_name 

379 else: 

380 full_name = module + '.' + self.real_name 

381 

382 super().__init__(name, source, full_name, is_lazy=is_lazy) 

383 

384 @property 

385 def source_statement(self): 

386 return f'{self._lazy_s}from {self.module} import {self.real_name}{self._alias_s}' 

387 

388 @property 

389 def imported_name(self): 

390 """Return import full name with alias.""" 

391 return f'{self.fullName}{self._alias_s}' 

392 

393 

394class StarImportation(Importation): 

395 """A binding created by a 'from x import *' statement.""" 

396 

397 def __init__(self, name, source): 

398 super().__init__('*', source, is_lazy=False) 

399 # Each star importation needs a unique name, and 

400 # may not be the module name otherwise it will be deemed imported 

401 self.name = name + '.*' 

402 self.fullName = name 

403 

404 @property 

405 def source_statement(self): 

406 return f'from {self.fullName} import *' 

407 

408 @property 

409 def imported_name(self): 

410 # When the module ends with a ., avoid the ambiguous '..*' 

411 if self.fullName.endswith('.'): 

412 return self.source_statement 

413 else: 

414 return self.name 

415 

416 

417class FutureImportation(ImportationFrom): 

418 """ 

419 A binding created by a from `__future__` import statement. 

420 

421 `__future__` imports are implicitly used. 

422 """ 

423 

424 def __init__(self, name, source, scope): 

425 super().__init__(name, source, '__future__', is_lazy=False) 

426 self.used = (scope, source) 

427 

428 

429class Argument(Binding): 

430 """ 

431 Represents binding a name as an argument. 

432 """ 

433 

434 

435class Assignment(Binding): 

436 """ 

437 Represents binding a name with an explicit assignment. 

438 

439 The checker will raise warnings for any Assignment that isn't used. Also, 

440 the checker does not consider assignments in tuple/list unpacking to be 

441 Assignments, rather it treats them as simple Bindings. 

442 """ 

443 

444 

445class NamedExprAssignment(Assignment): 

446 """ 

447 Represents binding a name with an assignment expression. 

448 """ 

449 

450 

451class Annotation(Binding): 

452 """ 

453 Represents binding a name to a type without an associated value. 

454 

455 As long as this name is not assigned a value in another binding, it is considered 

456 undefined for most purposes. One notable exception is using the name as a type 

457 annotation. 

458 """ 

459 

460 def redefines(self, other): 

461 """An Annotation doesn't define any name, so it cannot redefine one.""" 

462 return False 

463 

464 

465class FunctionDefinition(Definition): 

466 pass 

467 

468 

469class ClassDefinition(Definition): 

470 pass 

471 

472 

473class ExportBinding(Binding): 

474 """ 

475 A binding created by an C{__all__} assignment. If the names in the list 

476 can be determined statically, they will be treated as names for export and 

477 additional checking applied to them. 

478 

479 The only recognized C{__all__} assignment via list/tuple concatenation is in the 

480 following format: 

481 

482 __all__ = ['a'] + ['b'] + ['c'] 

483 

484 Names which are imported and not otherwise used but appear in the value of 

485 C{__all__} will not have an unused import warning reported for them. 

486 """ 

487 

488 def __init__(self, name, source, scope): 

489 if '__all__' in scope and isinstance(source, ast.AugAssign): 

490 self.names = list(scope['__all__'].names) 

491 else: 

492 self.names = [] 

493 

494 def _add_to_names(container): 

495 for node in container.elts: 

496 if isinstance(node, ast.Constant) and isinstance(node.value, str): 

497 self.names.append(node.value) 

498 

499 if isinstance(source.value, (ast.List, ast.Tuple)): 

500 _add_to_names(source.value) 

501 # If concatenating lists or tuples 

502 elif isinstance(source.value, ast.BinOp): 

503 currentValue = source.value 

504 while isinstance(currentValue.right, (ast.List, ast.Tuple)): 

505 left = currentValue.left 

506 right = currentValue.right 

507 _add_to_names(right) 

508 # If more lists are being added 

509 if isinstance(left, ast.BinOp): 

510 currentValue = left 

511 # If just two lists are being added 

512 elif isinstance(left, (ast.List, ast.Tuple)): 

513 _add_to_names(left) 

514 # All lists accounted for - done 

515 break 

516 # If not list concatenation 

517 else: 

518 break 

519 super().__init__(name, source) 

520 

521 

522class Scope(dict): 

523 importStarred = False # set to True when import * is found 

524 

525 def __repr__(self): # pragma: no cover 

526 scope_cls = self.__class__.__name__ 

527 return f'<{scope_cls} at 0x{id(self):x} {dict.__repr__(self)}>' 

528 

529 

530class ClassScope(Scope): 

531 def __init__(self): 

532 super().__init__() 

533 # {name: node} 

534 self.indirect_assignments = {} 

535 

536 

537class FunctionScope(Scope): 

538 """ 

539 I represent a name scope for a function. 

540 

541 @ivar globals: Names declared 'global' in this function. 

542 """ 

543 usesLocals = False 

544 always_used = frozenset(( 

545 '__tracebackhide__', '__traceback_info__', 

546 '__traceback_supplement__', '__debuggerskip__', 

547 )) 

548 

549 def __init__(self): 

550 super().__init__() 

551 # {name: node} 

552 self.indirect_assignments = {} 

553 

554 def unused_assignments(self): 

555 """ 

556 Return a generator for the assignments which have not been used. 

557 """ 

558 for name, binding in self.items(): 

559 if (not binding.used and 

560 name != '_' and # see issue #202 

561 name not in self.always_used and 

562 not self.usesLocals and 

563 isinstance(binding, Assignment)): 

564 yield name, binding 

565 

566 def unused_annotations(self): 

567 """ 

568 Return a generator for the annotations which have not been used. 

569 """ 

570 for name, binding in self.items(): 

571 if not binding.used and isinstance(binding, Annotation): 

572 yield name, binding 

573 

574 

575class TypeScope(Scope): 

576 pass 

577 

578 

579class ComprehensionScope(Scope): 

580 pass 

581 

582 

583class GeneratorScope(ComprehensionScope): 

584 pass 

585 

586 

587class ModuleScope(Scope): 

588 """Scope for a module.""" 

589 _futures_allowed = True 

590 _annotations_future_enabled = False 

591 

592 

593class DoctestScope(ModuleScope): 

594 """Scope for a doctest.""" 

595 

596 

597class DetectClassScopedMagic: 

598 names = dir() 

599 

600 

601def getNodeName(node): 

602 # Returns node.id, or node.name, or None 

603 if hasattr(node, 'id'): # One of the many nodes with an id 

604 return node.id 

605 if hasattr(node, 'name'): # an ExceptHandler node 

606 return node.name 

607 if hasattr(node, 'rest'): # a MatchMapping node 

608 return node.rest 

609 

610 

611TYPING_MODULES = frozenset(('typing', 'typing_extensions')) 

612 

613 

614def _is_typing_helper(node, is_name_match_fn, scope_stack): 

615 """ 

616 Internal helper to determine whether or not something is a member of a 

617 typing module. This is used as part of working out whether we are within a 

618 type annotation context. 

619 

620 Note: you probably don't want to use this function directly. Instead see the 

621 utils below which wrap it (`_is_typing` and `_is_any_typing_member`). 

622 """ 

623 

624 def _bare_name_is_attr(name): 

625 for scope in reversed(scope_stack): 

626 if name in scope: 

627 return ( 

628 isinstance(scope[name], ImportationFrom) and 

629 scope[name].module in TYPING_MODULES and 

630 is_name_match_fn(scope[name].real_name) 

631 ) 

632 

633 return False 

634 

635 def _module_scope_is_typing(name): 

636 for scope in reversed(scope_stack): 

637 if name in scope: 

638 return ( 

639 isinstance(scope[name], Importation) and 

640 scope[name].fullName in TYPING_MODULES 

641 ) 

642 

643 return False 

644 

645 return ( 

646 ( 

647 isinstance(node, ast.Name) and 

648 _bare_name_is_attr(node.id) 

649 ) or ( 

650 isinstance(node, ast.Attribute) and 

651 isinstance(node.value, ast.Name) and 

652 _module_scope_is_typing(node.value.id) and 

653 is_name_match_fn(node.attr) 

654 ) 

655 ) 

656 

657 

658def _is_typing(node, typing_attr, scope_stack): 

659 """ 

660 Determine whether `node` represents the member of a typing module specified 

661 by `typing_attr`. 

662 

663 This is used as part of working out whether we are within a type annotation 

664 context. 

665 """ 

666 return _is_typing_helper(node, lambda x: x == typing_attr, scope_stack) 

667 

668 

669def _is_any_typing_member(node, scope_stack): 

670 """ 

671 Determine whether `node` represents any member of a typing module. 

672 

673 This is used as part of working out whether we are within a type annotation 

674 context. 

675 """ 

676 return _is_typing_helper(node, lambda x: True, scope_stack) 

677 

678 

679def is_typing_overload(value, scope_stack): 

680 return ( 

681 isinstance(value.source, (ast.FunctionDef, ast.AsyncFunctionDef)) and 

682 any( 

683 _is_typing(dec, 'overload', scope_stack) 

684 for dec in value.source.decorator_list 

685 ) 

686 ) 

687 

688 

689class AnnotationState: 

690 NONE = 0 

691 STRING = 1 

692 BARE = 2 

693 STR_AS_TYPE = 3 

694 

695 

696def in_annotation(func): 

697 @functools.wraps(func) 

698 def in_annotation_func(self, *args, **kwargs): 

699 with self._enter_annotation(): 

700 return func(self, *args, **kwargs) 

701 return in_annotation_func 

702 

703 

704def in_string_annotation(func): 

705 @functools.wraps(func) 

706 def in_annotation_func(self, *args, **kwargs): 

707 with self._enter_annotation(AnnotationState.STRING): 

708 return func(self, *args, **kwargs) 

709 return in_annotation_func 

710 

711 

712class Checker: 

713 """I check the cleanliness and sanity of Python code.""" 

714 

715 _ast_node_scope = { 

716 ast.Module: ModuleScope, 

717 ast.ClassDef: ClassScope, 

718 ast.FunctionDef: FunctionScope, 

719 ast.AsyncFunctionDef: FunctionScope, 

720 ast.Lambda: FunctionScope, 

721 ast.ListComp: ComprehensionScope, 

722 ast.SetComp: ComprehensionScope, 

723 ast.GeneratorExp: GeneratorScope, 

724 ast.DictComp: ComprehensionScope, 

725 } 

726 

727 nodeDepth = 0 

728 offset = None 

729 _in_annotation = AnnotationState.NONE 

730 

731 def __init__(self, tree, filename='(none)', builtins=None, 

732 withDoctest='PYFLAKES_DOCTEST' in os.environ): 

733 self._nodeHandlers = {} 

734 self._deferred = collections.deque() 

735 self.deadScopes = [] 

736 self.messages = [] 

737 self.filename = filename 

738 self.builtIns = builtin_vars | _custom_builtins() 

739 if builtins: 

740 self.builtIns = self.builtIns.union(builtins) 

741 self.withDoctest = withDoctest 

742 self.exceptHandlers = [()] 

743 self.root = tree 

744 

745 self.scopeStack = [] 

746 scope_tp = Checker._ast_node_scope[type(tree)] 

747 

748 with self.in_scope(scope_tp): 

749 for builtin in self.builtIns: 

750 self.addBinding(None, Builtin(builtin)) 

751 self.handleChildren(tree) 

752 self._run_deferred() 

753 

754 self.checkDeadScopes() 

755 

756 def deferFunction(self, callable): 

757 """ 

758 Schedule a function handler to be called just before completion. 

759 

760 This is used for handling function bodies, which must be deferred 

761 because code later in the file might modify the global scope. When 

762 `callable` is called, the scope at the time this is called will be 

763 restored, however it will contain any new bindings added to it. 

764 """ 

765 self._deferred.append((callable, self.scopeStack[:], self.offset)) 

766 

767 def _run_deferred(self): 

768 orig = (self.scopeStack, self.offset) 

769 

770 while self._deferred: 

771 handler, scope, offset = self._deferred.popleft() 

772 self.scopeStack, self.offset = scope, offset 

773 handler() 

774 

775 self.scopeStack, self.offset = orig 

776 

777 def _in_doctest(self): 

778 return (len(self.scopeStack) >= 2 and 

779 isinstance(self.scopeStack[1], DoctestScope)) 

780 

781 @property 

782 def futuresAllowed(self): 

783 return ( 

784 isinstance(self.scope, ModuleScope) and 

785 self.scope._futures_allowed 

786 ) 

787 

788 @futuresAllowed.setter 

789 def futuresAllowed(self, value): 

790 assert value is False 

791 if isinstance(self.scope, ModuleScope): 

792 self.scope._futures_allowed = False 

793 

794 @property 

795 def annotationsFutureEnabled(self): 

796 scope = self.scopeStack[0] 

797 if not isinstance(scope, ModuleScope): 

798 return False 

799 return scope._annotations_future_enabled 

800 

801 @annotationsFutureEnabled.setter 

802 def annotationsFutureEnabled(self, value): 

803 assert value is True 

804 assert isinstance(self.scope, ModuleScope) 

805 self.scope._annotations_future_enabled = True 

806 

807 @property 

808 def scope(self): 

809 return self.scopeStack[-1] 

810 

811 @contextlib.contextmanager 

812 def in_scope(self, cls): 

813 self.scopeStack.append(cls()) 

814 try: 

815 yield 

816 finally: 

817 self.deadScopes.append(self.scopeStack.pop()) 

818 

819 def checkDeadScopes(self): 

820 """ 

821 Look at scopes which have been fully examined and report names in them 

822 which were imported but unused. 

823 """ 

824 for scope in self.deadScopes: 

825 if isinstance(scope, (ClassScope, FunctionScope)): 

826 for name, node in scope.indirect_assignments.items(): 

827 self.report(messages.UnusedIndirectAssignment, node, name) 

828 

829 # imports in classes are public members 

830 if isinstance(scope, ClassScope): 

831 continue 

832 

833 if isinstance(scope, FunctionScope): 

834 for name, binding in scope.unused_assignments(): 

835 self.report(messages.UnusedVariable, binding.source, name) 

836 for name, binding in scope.unused_annotations(): 

837 self.report(messages.UnusedAnnotation, binding.source, name) 

838 

839 all_binding = scope.get('__all__') 

840 if all_binding and not isinstance(all_binding, ExportBinding): 

841 all_binding = None 

842 

843 if all_binding: 

844 all_names = set(all_binding.names) 

845 undefined = [ 

846 name for name in all_binding.names 

847 if name not in scope 

848 ] 

849 else: 

850 all_names = undefined = [] 

851 

852 if undefined: 

853 if not scope.importStarred and \ 

854 os.path.basename(self.filename) != '__init__.py': 

855 # Look for possible mistakes in the export list 

856 for name in undefined: 

857 self.report(messages.UndefinedExport, 

858 scope['__all__'].source, name) 

859 

860 # mark all import '*' as used by the undefined in __all__ 

861 if scope.importStarred: 

862 from_list = [] 

863 for binding in scope.values(): 

864 if isinstance(binding, StarImportation): 

865 binding.used = all_binding 

866 from_list.append(binding.fullName) 

867 # report * usage, with a list of possible sources 

868 from_list = ', '.join(sorted(from_list)) 

869 for name in undefined: 

870 self.report(messages.ImportStarUsage, 

871 scope['__all__'].source, name, from_list) 

872 

873 # Look for imported names that aren't used. 

874 for value in scope.values(): 

875 if isinstance(value, Importation): 

876 if not value.used and value.name not in all_names: 

877 self.report( 

878 messages.UnusedImport, 

879 value.source, value.imported_name 

880 ) 

881 for node in value.redefined: 

882 self.report( 

883 messages.RedefinedWhileUnused, 

884 node, value.name, value.source, 

885 ) 

886 

887 def report(self, messageClass, *args, **kwargs): 

888 self.messages.append(messageClass(self.filename, *args, **kwargs)) 

889 

890 def getParent(self, node): 

891 # Lookup the first parent which is not Tuple, List or Starred 

892 while True: 

893 node = node._pyflakes_parent 

894 if not hasattr(node, 'elts') and not hasattr(node, 'ctx'): 

895 return node 

896 

897 def getCommonAncestor(self, lnode, rnode, stop): 

898 if ( 

899 stop in (lnode, rnode) or 

900 not ( 

901 hasattr(lnode, '_pyflakes_parent') and 

902 hasattr(rnode, '_pyflakes_parent') 

903 ) 

904 ): 

905 return None 

906 if lnode is rnode: 

907 return lnode 

908 

909 if (lnode._pyflakes_depth > rnode._pyflakes_depth): 

910 return self.getCommonAncestor(lnode._pyflakes_parent, rnode, stop) 

911 if (lnode._pyflakes_depth < rnode._pyflakes_depth): 

912 return self.getCommonAncestor(lnode, rnode._pyflakes_parent, stop) 

913 return self.getCommonAncestor( 

914 lnode._pyflakes_parent, 

915 rnode._pyflakes_parent, 

916 stop, 

917 ) 

918 

919 def descendantOf(self, node, ancestors, stop): 

920 for a in ancestors: 

921 if self.getCommonAncestor(node, a, stop): 

922 return True 

923 return False 

924 

925 def differentForks(self, lnode, rnode): 

926 """True, if lnode and rnode are located on different forks of IF/TRY""" 

927 ancestor = self.getCommonAncestor(lnode, rnode, self.root) 

928 parts = getAlternatives(ancestor) 

929 if parts: 

930 for items in parts: 

931 if self.descendantOf(lnode, items, ancestor) ^ \ 

932 self.descendantOf(rnode, items, ancestor): 

933 return True 

934 return False 

935 

936 def addBinding(self, node, value): 

937 """ 

938 Called when a binding is altered. 

939 

940 - `node` is the statement responsible for the change 

941 - `value` is the new value, a Binding instance 

942 """ 

943 # assert value.source in (node, node._pyflakes_parent): 

944 for scope in reversed(self.scopeStack): 

945 if value.name in scope: 

946 break 

947 existing = scope.get(value.name) 

948 

949 if (existing and not isinstance(existing, Builtin) and 

950 not self.differentForks(node, existing.source)): 

951 

952 parent_stmt = self.getParent(value.source) 

953 if isinstance(existing, Importation) and isinstance(parent_stmt, FOR_TYPES): 

954 self.report(messages.ImportShadowedByLoopVar, 

955 node, value.name, existing.source) 

956 

957 elif scope is self.scope: 

958 if ( 

959 (not existing.used and value.redefines(existing)) and 

960 (value.name != '_' or isinstance(existing, Importation)) and 

961 not is_typing_overload(existing, self.scopeStack) 

962 ): 

963 self.report(messages.RedefinedWhileUnused, 

964 node, value.name, existing.source) 

965 

966 if isinstance(scope, (ClassScope, FunctionScope)): 

967 scope.indirect_assignments.pop(value.name, None) 

968 

969 elif isinstance(existing, Importation) and value.redefines(existing): 

970 existing.redefined.append(node) 

971 

972 if value.name in self.scope: 

973 # then assume the rebound name is used as a global or within a loop 

974 value.used = self.scope[value.name].used 

975 

976 # don't treat annotations as assignments if there is an existing value 

977 # in scope 

978 if value.name not in self.scope or not isinstance(value, Annotation): 

979 if isinstance(value, NamedExprAssignment): 

980 # PEP 572: use scope in which outermost generator is defined 

981 scope = next( 

982 scope 

983 for scope in reversed(self.scopeStack) 

984 if not isinstance(scope, ComprehensionScope) 

985 ) 

986 if value.name in scope and isinstance(scope[value.name], Annotation): 

987 # re-assignment to name that was previously only an annotation 

988 scope[value.name] = value 

989 else: 

990 # it may be a re-assignment to an already existing name 

991 scope.setdefault(value.name, value) 

992 else: 

993 self.scope[value.name] = value 

994 

995 def _unknown_handler(self, node): # pragma: no cover 

996 # this environment variable configures whether to error on unknown 

997 # ast types. 

998 # 

999 # this is silent by default but the error is enabled for the pyflakes 

1000 # testsuite. 

1001 # 

1002 # this allows new syntax to be added to python without *requiring* 

1003 # changes from the pyflakes side. but will still produce an error 

1004 # in the pyflakes testsuite (so more specific handling can be added if 

1005 # needed). 

1006 if os.environ.get('PYFLAKES_ERROR_UNKNOWN'): 

1007 raise NotImplementedError(f'Unexpected type: {type(node)}') 

1008 else: 

1009 self.handleChildren(node) 

1010 

1011 def getNodeHandler(self, node_class): 

1012 try: 

1013 return self._nodeHandlers[node_class] 

1014 except KeyError: 

1015 nodeType = node_class.__name__.upper() 

1016 self._nodeHandlers[node_class] = handler = getattr( 

1017 self, nodeType, self._unknown_handler, 

1018 ) 

1019 return handler 

1020 

1021 def handleNodeLoad(self, node, parent): 

1022 name = getNodeName(node) 

1023 if not name: 

1024 return 

1025 

1026 # only the following can access class scoped variables (since classes 

1027 # aren't really a scope) 

1028 # - direct accesses (not within a nested scope) 

1029 # - generators 

1030 # - type annotations (for generics, etc.) 

1031 can_access_class_vars = None 

1032 importStarred = None 

1033 func_depth = 0 

1034 

1035 # try enclosing function scopes and global scope 

1036 for scope in reversed(self.scopeStack): 

1037 if isinstance(scope, (FunctionScope, GeneratorScope)): 

1038 func_depth += 1 

1039 

1040 if isinstance(scope, ClassScope): 

1041 if name == '__class__': 

1042 return 

1043 elif can_access_class_vars is False: 

1044 # only generators used in a class scope can access the 

1045 # names of the class. this is skipped during the first 

1046 # iteration 

1047 continue 

1048 

1049 binding = scope.get(name, None) 

1050 if isinstance(binding, Annotation) and not self._in_postponed_annotation: 

1051 scope[name].used = (self.scope, node) 

1052 continue 

1053 

1054 elif name == 'print' and isinstance(binding, Builtin): 

1055 if (isinstance(parent, ast.BinOp) and 

1056 isinstance(parent.op, ast.RShift)): 

1057 self.report(messages.InvalidPrintSyntax, node) 

1058 elif ( 

1059 isinstance(binding, Importation) and 

1060 binding.is_lazy and 

1061 func_depth == 0 and ( 

1062 self._in_annotation == AnnotationState.NONE or 

1063 self._in_annotation == AnnotationState.STR_AS_TYPE 

1064 ) 

1065 ): # pragma: >=3.15 cover 

1066 self.report(messages.EagerUseOfLazyImport, node, name, binding.source) 

1067 

1068 try: 

1069 scope[name].used = (self.scope, node) 

1070 

1071 # if the name of SubImportation is same as 

1072 # alias of other Importation and the alias 

1073 # is used, SubImportation also should be marked as used. 

1074 n = scope[name] 

1075 if isinstance(n, Importation) and n._has_alias(): 

1076 try: 

1077 scope[n.fullName].used = (self.scope, node) 

1078 except KeyError: 

1079 pass 

1080 except KeyError: 

1081 pass 

1082 else: 

1083 return 

1084 

1085 importStarred = importStarred or scope.importStarred 

1086 

1087 if can_access_class_vars is not False: 

1088 can_access_class_vars = isinstance( 

1089 scope, (TypeScope, ComprehensionScope), 

1090 ) 

1091 

1092 if importStarred: 

1093 from_list = [] 

1094 

1095 for scope in reversed(self.scopeStack): 

1096 for binding in scope.values(): 

1097 if isinstance(binding, StarImportation): 

1098 # mark '*' imports as used for each scope 

1099 binding.used = (self.scope, node) 

1100 from_list.append(binding.fullName) 

1101 

1102 # report * usage, with a list of possible sources 

1103 from_list = ', '.join(sorted(from_list)) 

1104 self.report(messages.ImportStarUsage, node, name, from_list) 

1105 return 

1106 

1107 if name == '__path__' and os.path.basename(self.filename) == '__init__.py': 

1108 # the special name __path__ is valid only in packages 

1109 return 

1110 

1111 if name in DetectClassScopedMagic.names and isinstance(self.scope, ClassScope): 

1112 return 

1113 

1114 # protected with a NameError handler? 

1115 if 'NameError' not in self.exceptHandlers[-1]: 

1116 self.report(messages.UndefinedName, node, name) 

1117 

1118 def handleNodeStore(self, node): 

1119 name = getNodeName(node) 

1120 if not name: 

1121 return 

1122 # if the name hasn't already been defined in the current scope 

1123 if isinstance(self.scope, FunctionScope) and name not in self.scope: 

1124 # for each function or module scope above us 

1125 for scope in self.scopeStack[:-1]: 

1126 if not isinstance(scope, (FunctionScope, ModuleScope)): 

1127 continue 

1128 # if the name was defined in that scope, and the name has 

1129 # been accessed already in the current scope, and hasn't 

1130 # been declared global 

1131 used = name in scope and scope[name].used 

1132 if used and used[0] is self.scope: 

1133 # then it's probably a mistake 

1134 self.report(messages.UndefinedLocal, 

1135 scope[name].used[1], name, scope[name].source) 

1136 break 

1137 

1138 parent_stmt = self.getParent(node) 

1139 if isinstance(parent_stmt, ast.AnnAssign) and parent_stmt.value is None: 

1140 binding = Annotation(name, node) 

1141 elif isinstance(parent_stmt, (FOR_TYPES, ast.comprehension)) or ( 

1142 parent_stmt != node._pyflakes_parent and 

1143 not self.isLiteralTupleUnpacking(parent_stmt)): 

1144 binding = Binding(name, node) 

1145 elif ( 

1146 name == '__all__' and 

1147 isinstance(self.scope, ModuleScope) and 

1148 isinstance( 

1149 node._pyflakes_parent, 

1150 (ast.Assign, ast.AugAssign, ast.AnnAssign) 

1151 ) 

1152 ): 

1153 binding = ExportBinding(name, node._pyflakes_parent, self.scope) 

1154 elif isinstance(parent_stmt, ast.NamedExpr): 

1155 binding = NamedExprAssignment(name, node) 

1156 else: 

1157 binding = Assignment(name, node) 

1158 self.addBinding(node, binding) 

1159 

1160 def handleNodeDelete(self, node): 

1161 

1162 def on_conditional_branch(): 

1163 """ 

1164 Return `True` if node is part of a conditional body. 

1165 """ 

1166 current = getattr(node, '_pyflakes_parent', None) 

1167 while current: 

1168 if isinstance(current, (ast.If, ast.While, ast.IfExp)): 

1169 return True 

1170 current = getattr(current, '_pyflakes_parent', None) 

1171 return False 

1172 

1173 if on_conditional_branch(): 

1174 # We cannot predict if this conditional branch is going to 

1175 # be executed. 

1176 return 

1177 

1178 if isinstance(self.scope, (ClassScope, FunctionScope)): 

1179 self.scope.indirect_assignments.pop(node.id, None) 

1180 

1181 try: 

1182 del self.scope[node.id] 

1183 except KeyError: 

1184 self.report(messages.UndefinedName, node, node.id) 

1185 

1186 @contextlib.contextmanager 

1187 def _enter_annotation(self, ann_type=AnnotationState.BARE): 

1188 orig, self._in_annotation = self._in_annotation, ann_type 

1189 try: 

1190 yield 

1191 finally: 

1192 self._in_annotation = orig 

1193 

1194 @property 

1195 def _in_postponed_annotation(self): 

1196 return ( 

1197 self._in_annotation == AnnotationState.STRING or 

1198 ( 

1199 self._in_annotation == AnnotationState.BARE and 

1200 (self.annotationsFutureEnabled or sys.version_info >= (3, 14)) 

1201 ) 

1202 ) 

1203 

1204 def handleChildren(self, tree, omit=None): 

1205 for node in iter_child_nodes(tree, omit=omit): 

1206 self.handleNode(node, tree) 

1207 

1208 def isLiteralTupleUnpacking(self, node): 

1209 if isinstance(node, ast.Assign): 

1210 for child in node.targets + [node.value]: 

1211 if not hasattr(child, 'elts'): 

1212 return False 

1213 return True 

1214 

1215 def isDocstring(self, node): 

1216 """ 

1217 Determine if the given node is a docstring, as long as it is at the 

1218 correct place in the node tree. 

1219 """ 

1220 return ( 

1221 isinstance(node, ast.Expr) and 

1222 isinstance(node.value, ast.Constant) and 

1223 isinstance(node.value.value, str) 

1224 ) 

1225 

1226 def getDocstring(self, node): 

1227 if ( 

1228 isinstance(node, ast.Expr) and 

1229 isinstance(node.value, ast.Constant) and 

1230 isinstance(node.value.value, str) 

1231 ): 

1232 return node.value.value, node.lineno - 1 

1233 else: 

1234 return None, None 

1235 

1236 def handleNode(self, node, parent): 

1237 if node is None: 

1238 return 

1239 if self.offset and getattr(node, 'lineno', None) is not None: 

1240 node.lineno += self.offset[0] 

1241 node.col_offset += self.offset[1] 

1242 if ( 

1243 self.futuresAllowed and 

1244 self.nodeDepth == 0 and 

1245 not isinstance(node, ast.ImportFrom) and 

1246 not self.isDocstring(node) 

1247 ): 

1248 self.futuresAllowed = False 

1249 self.nodeDepth += 1 

1250 node._pyflakes_depth = self.nodeDepth 

1251 node._pyflakes_parent = parent 

1252 try: 

1253 handler = self.getNodeHandler(node.__class__) 

1254 handler(node) 

1255 finally: 

1256 self.nodeDepth -= 1 

1257 

1258 def handleDoctests(self, node): 

1259 try: 

1260 (docstring, node_lineno) = self.getDocstring(node.body[0]) 

1261 examples = docstring and _doctest_parser()(docstring) 

1262 except (ValueError, IndexError): 

1263 # e.g. line 6 of the docstring for <string> has inconsistent 

1264 # leading whitespace: ... 

1265 return 

1266 if not examples: 

1267 return 

1268 

1269 # Place doctest in module scope 

1270 saved_stack = self.scopeStack 

1271 self.scopeStack = [self.scopeStack[0]] 

1272 node_offset = self.offset or (0, 0) 

1273 with self.in_scope(DoctestScope): 

1274 if '_' not in self.scopeStack[0]: 

1275 self.addBinding(None, Builtin('_')) 

1276 for example in examples: 

1277 try: 

1278 tree = ast.parse(example.source, "<doctest>") 

1279 except SyntaxError as e: 

1280 position = (node_lineno + example.lineno + e.lineno, 

1281 example.indent + 4 + (e.offset or 0)) 

1282 self.report(messages.DoctestSyntaxError, node, position) 

1283 else: 

1284 self.offset = (node_offset[0] + node_lineno + example.lineno, 

1285 node_offset[1] + example.indent + 4) 

1286 self.handleChildren(tree) 

1287 self.offset = node_offset 

1288 self.scopeStack = saved_stack 

1289 

1290 @in_string_annotation 

1291 def handleStringAnnotation(self, s, node, ref_lineno, ref_col_offset): 

1292 try: 

1293 tree = ast.parse(s) 

1294 except SyntaxError: 

1295 self.report(messages.ForwardAnnotationSyntaxError, node, s) 

1296 return 

1297 

1298 body = tree.body 

1299 if len(body) != 1 or not isinstance(body[0], ast.Expr): 

1300 self.report(messages.ForwardAnnotationSyntaxError, node, s) 

1301 return 

1302 

1303 parsed_annotation = tree.body[0].value 

1304 for descendant in ast.walk(parsed_annotation): 

1305 if ( 

1306 'lineno' in descendant._attributes and 

1307 'col_offset' in descendant._attributes 

1308 ): 

1309 descendant.lineno = ref_lineno 

1310 descendant.col_offset = ref_col_offset 

1311 

1312 self.handleNode(parsed_annotation, node) 

1313 

1314 def handle_annotation_always_deferred(self, annotation, parent): 

1315 fn = in_annotation(Checker.handleNode) 

1316 self.deferFunction(lambda: fn(self, annotation, parent)) 

1317 

1318 @in_annotation 

1319 def handleAnnotation(self, annotation, node): 

1320 if self.annotationsFutureEnabled or sys.version_info >= (3, 14): 

1321 self.handle_annotation_always_deferred(annotation, node) 

1322 else: # pragma: <3.14 cover 

1323 self.handleNode(annotation, node) 

1324 

1325 def ignore(self, node): 

1326 pass 

1327 

1328 # "stmt" type nodes 

1329 DELETE = WHILE = WITH = WITHITEM = ASYNCWITH = EXPR = handleChildren 

1330 

1331 PASS = ignore 

1332 

1333 def FOR(self, node): 

1334 self.handleNode(node.iter, node) 

1335 self.handleChildren(node, omit=('iter',)) 

1336 

1337 ASYNCFOR = COMPREHENSION = FOR 

1338 

1339 # "expr" type nodes 

1340 BOOLOP = UNARYOP = SET = ATTRIBUTE = STARRED = NAMECONSTANT = \ 

1341 handleChildren 

1342 

1343 def SUBSCRIPT(self, node): 

1344 if _is_name_or_attr(node.value, 'Literal'): 

1345 self.handleNode(node.value, node) 

1346 with self._enter_annotation(AnnotationState.NONE): 

1347 self.handleNode(node.slice, node) 

1348 elif _is_name_or_attr(node.value, 'Annotated'): 

1349 self.handleNode(node.value, node) 

1350 

1351 if isinstance(node.slice, ast.Tuple): 

1352 slice_tuple = node.slice 

1353 else: 

1354 slice_tuple = None 

1355 

1356 # not a multi-arg `Annotated` 

1357 if slice_tuple is None or len(slice_tuple.elts) < 2: 

1358 self.handleNode(node.slice, node) 

1359 else: 

1360 # the first argument is the type 

1361 self.handleNode(slice_tuple.elts[0], node) 

1362 # the rest of the arguments are not 

1363 with self._enter_annotation(AnnotationState.NONE): 

1364 for arg in slice_tuple.elts[1:]: 

1365 self.handleNode(arg, node) 

1366 

1367 self.handleNode(node.ctx, node) 

1368 else: 

1369 if _is_any_typing_member(node.value, self.scopeStack): 

1370 with self._enter_annotation(): 

1371 self.handleChildren(node) 

1372 else: 

1373 self.handleChildren(node) 

1374 

1375 def _handle_string_dot_format(self, node): 

1376 try: 

1377 placeholders = tuple(parse_format_string(node.func.value.value)) 

1378 except ValueError as e: 

1379 self.report(messages.StringDotFormatInvalidFormat, node, e) 

1380 return 

1381 

1382 auto = None 

1383 next_auto = 0 

1384 

1385 placeholder_positional = set() 

1386 placeholder_named = set() 

1387 

1388 def _add_key(fmtkey): 

1389 """Returns True if there is an error which should early-exit""" 

1390 nonlocal auto, next_auto 

1391 

1392 if fmtkey is None: # end of string or `{` / `}` escapes 

1393 return False 

1394 

1395 # attributes / indices are allowed in `.format(...)` 

1396 fmtkey, _, _ = fmtkey.partition('.') 

1397 fmtkey, _, _ = fmtkey.partition('[') 

1398 

1399 try: 

1400 fmtkey = int(fmtkey) 

1401 except ValueError: 

1402 pass 

1403 else: # fmtkey was an integer 

1404 if auto is True: 

1405 self.report(messages.StringDotFormatMixingAutomatic, node) 

1406 return True 

1407 else: 

1408 auto = False 

1409 

1410 if fmtkey == '': 

1411 if auto is False: 

1412 self.report(messages.StringDotFormatMixingAutomatic, node) 

1413 return True 

1414 else: 

1415 auto = True 

1416 

1417 fmtkey = next_auto 

1418 next_auto += 1 

1419 

1420 if isinstance(fmtkey, int): 

1421 placeholder_positional.add(fmtkey) 

1422 else: 

1423 placeholder_named.add(fmtkey) 

1424 

1425 return False 

1426 

1427 for _, fmtkey, spec, _ in placeholders: 

1428 if _add_key(fmtkey): 

1429 return 

1430 

1431 # spec can also contain format specifiers 

1432 if spec is not None: 

1433 try: 

1434 spec_placeholders = tuple(parse_format_string(spec)) 

1435 except ValueError as e: 

1436 self.report(messages.StringDotFormatInvalidFormat, node, e) 

1437 return 

1438 

1439 for _, spec_fmtkey, spec_spec, _ in spec_placeholders: 

1440 # can't recurse again 

1441 if spec_spec is not None and '{' in spec_spec: 

1442 self.report( 

1443 messages.StringDotFormatInvalidFormat, 

1444 node, 

1445 'Max string recursion exceeded', 

1446 ) 

1447 return 

1448 if _add_key(spec_fmtkey): 

1449 return 

1450 

1451 # bail early if there is *args or **kwargs 

1452 if ( 

1453 # *args 

1454 any(isinstance(arg, ast.Starred) for arg in node.args) or 

1455 # **kwargs 

1456 any(kwd.arg is None for kwd in node.keywords) 

1457 ): 

1458 return 

1459 

1460 substitution_positional = set(range(len(node.args))) 

1461 substitution_named = {kwd.arg for kwd in node.keywords} 

1462 

1463 extra_positional = substitution_positional - placeholder_positional 

1464 extra_named = substitution_named - placeholder_named 

1465 

1466 missing_arguments = ( 

1467 (placeholder_positional | placeholder_named) - 

1468 (substitution_positional | substitution_named) 

1469 ) 

1470 

1471 if extra_positional: 

1472 self.report( 

1473 messages.StringDotFormatExtraPositionalArguments, 

1474 node, 

1475 ', '.join(sorted(str(x) for x in extra_positional)), 

1476 ) 

1477 if extra_named: 

1478 self.report( 

1479 messages.StringDotFormatExtraNamedArguments, 

1480 node, 

1481 ', '.join(sorted(extra_named)), 

1482 ) 

1483 if missing_arguments: 

1484 self.report( 

1485 messages.StringDotFormatMissingArgument, 

1486 node, 

1487 ', '.join(sorted(str(x) for x in missing_arguments)), 

1488 ) 

1489 

1490 def CALL(self, node): 

1491 if ( 

1492 isinstance(node.func, ast.Attribute) and 

1493 isinstance(node.func.value, ast.Constant) and 

1494 isinstance(node.func.value.value, str) and 

1495 node.func.attr == 'format' 

1496 ): 

1497 self._handle_string_dot_format(node) 

1498 

1499 def _annotation(n: ast.AST) -> None: 

1500 with self._enter_annotation(AnnotationState.STR_AS_TYPE): 

1501 self.handleNode(n, node) 

1502 

1503 def _annotations(nodes: list[ast.AST]) -> None: 

1504 for n in nodes: 

1505 _annotation(n) 

1506 

1507 def _non_annotation(n: ast.AST) -> None: 

1508 with self._enter_annotation(AnnotationState.NONE): 

1509 self.handleNode(n, node) 

1510 

1511 def _non_annotations(nodes: list[ast.AST]) -> None: 

1512 for n in nodes: 

1513 _non_annotation(n) 

1514 

1515 if _is_typing(node.func, 'cast', self.scopeStack): 

1516 _non_annotation(node.func) 

1517 

1518 # cast("tp", val) 

1519 _annotations(node.args[:1]) 

1520 _non_annotations(node.args[1:]) 

1521 

1522 # cast(typ="tp", val=val) 

1523 for kwd in node.keywords: 

1524 if kwd.arg == 'typ': 

1525 _annotation(kwd) 

1526 else: 

1527 _non_annotation(kwd) 

1528 

1529 elif _is_typing(node.func, 'assert_type', self.scopeStack): 

1530 _non_annotation(node.func) 

1531 

1532 # assert_type(val, "tp") 

1533 _non_annotations(node.args[:1]) 

1534 _annotations(node.args[1:]) 

1535 _non_annotations(node.keywords) 

1536 

1537 elif _is_typing(node.func, 'TypeVar', self.scopeStack): 

1538 _non_annotation(node.func) 

1539 _non_annotations(node.args[:1]) 

1540 

1541 # TypeVar("T", "int", "str") 

1542 _annotations(node.args[1:]) 

1543 

1544 # TypeVar("T", bound="str") 

1545 for kwd in node.keywords: 

1546 if kwd.arg in ('bound', 'default'): 

1547 _annotation(kwd) 

1548 else: 

1549 _non_annotation(kwd) 

1550 

1551 elif ( 

1552 _is_typing(node.func, 'ParamSpec', self.scopeStack) or 

1553 _is_typing(node.func, 'TypeVarTuple', self.scopeStack) 

1554 ): 

1555 _non_annotation(node.func) 

1556 _non_annotations(node.args) 

1557 

1558 # ParamSpec("P", default=..., bound=...) 

1559 # TypeVarTuple("Ts", default=..., bound=...) 

1560 for kwd in node.keywords: 

1561 if kwd.arg in ('bound', 'default'): 

1562 _annotation(kwd) 

1563 else: 

1564 _non_annotation(kwd) 

1565 

1566 elif _is_typing(node.func, 'NewType', self.scopeStack): 

1567 _non_annotation(node.func) 

1568 _non_annotations(node.args[:1]) 

1569 

1570 # NewType("NT", "C") 

1571 _annotations(node.args[1:]) 

1572 

1573 for kwd in node.keywords: 

1574 if kwd.arg == 'tp': 

1575 _annotation(kwd) 

1576 else: 

1577 _non_annotation(kwd) 

1578 

1579 elif _is_typing(node.func, "TypedDict", self.scopeStack): 

1580 _non_annotation(node.func) 

1581 _non_annotations(node.args[:1]) 

1582 

1583 # TypedDict("a", {"a": int}) 

1584 if len(node.args) > 1 and isinstance(node.args[1], ast.Dict): 

1585 for k, v in iter_dict_children(node.args[1]): 

1586 _non_annotation(k) 

1587 _annotation(v) 

1588 _non_annotations(node.args[2:]) 

1589 else: 

1590 _non_annotations(node.args[1:]) 

1591 

1592 # TypedDict("a", a=int) 

1593 if sys.version_info >= (3, 13): # pragma: >=3.13 cover 

1594 _non_annotations(node.keywords) 

1595 else: # pragma: <3.13 cover 

1596 _annotations(node.keywords) 

1597 

1598 elif _is_typing(node.func, "NamedTuple", self.scopeStack): 

1599 _non_annotation(node.func) 

1600 _non_annotations(node.args[:1]) 

1601 

1602 # NamedTuple("a", [("a", int)]) 

1603 if ( 

1604 len(node.args) > 1 and 

1605 isinstance(node.args[1], (ast.Tuple, ast.List)) 

1606 ): 

1607 for elt in node.args[1].elts: 

1608 if isinstance(elt, (ast.Tuple, ast.List)): 

1609 _non_annotations(elt.elts[:1]) 

1610 _annotations(elt.elts[1:]) 

1611 else: 

1612 _non_annotation(elt) 

1613 _non_annotations(node.args[2:]) 

1614 else: 

1615 _non_annotations(node.args[1:]) 

1616 

1617 # NamedTuple("a", a=int) 

1618 if sys.version_info >= (3, 15): # pragma: >=3.15 cover 

1619 _non_annotations(node.keywords) 

1620 else: # pragma: <3.15 cover 

1621 _annotations(node.keywords) 

1622 else: 

1623 self.handleChildren(node) 

1624 

1625 def _handle_percent_format(self, node): 

1626 try: 

1627 placeholders = parse_percent_format(node.left.value) 

1628 except ValueError: 

1629 self.report( 

1630 messages.PercentFormatInvalidFormat, 

1631 node, 

1632 'incomplete format', 

1633 ) 

1634 return 

1635 

1636 named = set() 

1637 positional_count = 0 

1638 positional = None 

1639 for _, placeholder in placeholders: 

1640 if placeholder is None: 

1641 continue 

1642 name, _, width, precision, conversion = placeholder 

1643 

1644 if conversion == '%': 

1645 continue 

1646 

1647 if conversion not in VALID_CONVERSIONS: 

1648 self.report( 

1649 messages.PercentFormatUnsupportedFormatCharacter, 

1650 node, 

1651 conversion, 

1652 ) 

1653 

1654 if positional is None and conversion: 

1655 positional = name is None 

1656 

1657 for part in (width, precision): 

1658 if part is not None and '*' in part: 

1659 if not positional: 

1660 self.report( 

1661 messages.PercentFormatStarRequiresSequence, 

1662 node, 

1663 ) 

1664 else: 

1665 positional_count += 1 

1666 

1667 if positional and name is not None: 

1668 self.report( 

1669 messages.PercentFormatMixedPositionalAndNamed, 

1670 node, 

1671 ) 

1672 return 

1673 elif not positional and name is None: 

1674 self.report( 

1675 messages.PercentFormatMixedPositionalAndNamed, 

1676 node, 

1677 ) 

1678 return 

1679 

1680 if positional: 

1681 positional_count += 1 

1682 else: 

1683 named.add(name) 

1684 

1685 if ( 

1686 isinstance(node.right, (ast.List, ast.Tuple)) and 

1687 # does not have any *splats (py35+ feature) 

1688 not any( 

1689 isinstance(elt, ast.Starred) 

1690 for elt in node.right.elts 

1691 ) 

1692 ): 

1693 substitution_count = len(node.right.elts) 

1694 if positional and positional_count != substitution_count: 

1695 self.report( 

1696 messages.PercentFormatPositionalCountMismatch, 

1697 node, 

1698 positional_count, 

1699 substitution_count, 

1700 ) 

1701 elif not positional: 

1702 self.report(messages.PercentFormatExpectedMapping, node) 

1703 

1704 if ( 

1705 isinstance(node.right, ast.Dict) and 

1706 all( 

1707 isinstance(k, ast.Constant) and isinstance(k.value, str) 

1708 for k in node.right.keys 

1709 ) 

1710 ): 

1711 if positional and positional_count > 1: 

1712 self.report(messages.PercentFormatExpectedSequence, node) 

1713 return 

1714 

1715 substitution_keys = {k.value for k in node.right.keys} 

1716 extra_keys = substitution_keys - named 

1717 missing_keys = named - substitution_keys 

1718 if not positional and extra_keys: 

1719 self.report( 

1720 messages.PercentFormatExtraNamedArguments, 

1721 node, 

1722 ', '.join(sorted(extra_keys)), 

1723 ) 

1724 if not positional and missing_keys: 

1725 self.report( 

1726 messages.PercentFormatMissingArgument, 

1727 node, 

1728 ', '.join(sorted(missing_keys)), 

1729 ) 

1730 

1731 def BINOP(self, node): 

1732 if ( 

1733 isinstance(node.op, ast.Mod) and 

1734 isinstance(node.left, ast.Constant) and 

1735 isinstance(node.left.value, str) 

1736 ): 

1737 self._handle_percent_format(node) 

1738 self.handleChildren(node) 

1739 

1740 def CONSTANT(self, node): 

1741 if isinstance(node.value, str) and self._in_annotation: 

1742 fn = functools.partial( 

1743 self.handleStringAnnotation, 

1744 node.value, 

1745 node, 

1746 node.lineno, 

1747 node.col_offset, 

1748 ) 

1749 self.deferFunction(fn) 

1750 

1751 # "slice" type nodes 

1752 SLICE = EXTSLICE = INDEX = handleChildren 

1753 

1754 # expression contexts are node instances too, though being constants 

1755 LOAD = STORE = DEL = AUGLOAD = AUGSTORE = PARAM = ignore 

1756 

1757 # same for operators 

1758 AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \ 

1759 BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \ 

1760 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = \ 

1761 MATMULT = ignore 

1762 

1763 def RAISE(self, node): 

1764 self.handleChildren(node) 

1765 

1766 arg = node.exc 

1767 

1768 if isinstance(arg, ast.Call): 

1769 if is_notimplemented_name_node(arg.func): 

1770 # Handle "raise NotImplemented(...)" 

1771 self.report(messages.RaiseNotImplemented, node) 

1772 elif is_notimplemented_name_node(arg): 

1773 # Handle "raise NotImplemented" 

1774 self.report(messages.RaiseNotImplemented, node) 

1775 

1776 # additional node types 

1777 KEYWORD = FORMATTEDVALUE = handleChildren 

1778 

1779 _in_fstring = False 

1780 

1781 def JOINEDSTR(self, node): 

1782 if ( 

1783 # the conversion / etc. flags are parsed as f-strings without 

1784 # placeholders 

1785 not self._in_fstring and 

1786 not any(isinstance(x, ast.FormattedValue) for x in node.values) 

1787 ): 

1788 self.report(messages.FStringMissingPlaceholders, node) 

1789 

1790 self._in_fstring, orig = True, self._in_fstring 

1791 try: 

1792 self.handleChildren(node) 

1793 finally: 

1794 self._in_fstring = orig 

1795 

1796 def TEMPLATESTR(self, node): # pragma: >=3.14 cover 

1797 if not any(isinstance(x, ast.Interpolation) for x in node.values): 

1798 self.report(messages.TStringMissingPlaceholders, node) 

1799 

1800 # similar to f-strings, conversion / etc. flags are parsed as f-strings 

1801 # without placeholders 

1802 self._in_fstring, orig = True, self._in_fstring 

1803 try: 

1804 self.handleChildren(node) 

1805 finally: 

1806 self._in_fstring = orig 

1807 

1808 INTERPOLATION = handleChildren 

1809 

1810 def DICT(self, node): 

1811 # Complain if there are duplicate keys with different values 

1812 # If they have the same value it's not going to cause potentially 

1813 # unexpected behaviour so we'll not complain. 

1814 keys = [ 

1815 convert_to_value(key) for key in node.keys 

1816 ] 

1817 

1818 key_counts = collections.Counter(keys) 

1819 duplicate_keys = [ 

1820 key for key, count in key_counts.items() 

1821 if count > 1 

1822 ] 

1823 

1824 for key in duplicate_keys: 

1825 key_indices = [i for i, i_key in enumerate(keys) if i_key == key] 

1826 

1827 values = collections.Counter( 

1828 convert_to_value(node.values[index]) 

1829 for index in key_indices 

1830 ) 

1831 if any(count == 1 for value, count in values.items()): 

1832 for key_index in key_indices: 

1833 key_node = node.keys[key_index] 

1834 if isinstance(key, VariableKey): 

1835 self.report(messages.MultiValueRepeatedKeyVariable, 

1836 key_node, 

1837 key.name) 

1838 else: 

1839 self.report( 

1840 messages.MultiValueRepeatedKeyLiteral, 

1841 key_node, 

1842 key, 

1843 ) 

1844 

1845 for k, v in iter_dict_children(node): 

1846 self.handleNode(k, node) 

1847 self.handleNode(v, node) 

1848 

1849 def IF(self, node): 

1850 if isinstance(node.test, ast.Tuple) and node.test.elts != []: 

1851 self.report(messages.IfTuple, node) 

1852 self.handleChildren(node) 

1853 

1854 IFEXP = IF 

1855 

1856 def ASSERT(self, node): 

1857 if isinstance(node.test, ast.Tuple) and node.test.elts != []: 

1858 self.report(messages.AssertTuple, node) 

1859 self.handleChildren(node) 

1860 

1861 def GLOBAL(self, node): 

1862 """ 

1863 Keep track of globals declarations. 

1864 """ 

1865 global_scope_index = 1 if self._in_doctest() else 0 

1866 global_scope = self.scopeStack[global_scope_index] 

1867 

1868 # Ignore 'global' statement in global scope. 

1869 if self.scope is not global_scope: 

1870 

1871 # One 'global' statement can bind multiple (comma-delimited) names. 

1872 for node_name in node.names: 

1873 node_value = Assignment(node_name, node) 

1874 

1875 # Remove UndefinedName messages already reported for this name. 

1876 # TODO: if the global is not used in this scope, it does not 

1877 # become a globally defined name. See test_unused_global. 

1878 self.messages = [ 

1879 m for m in self.messages if not 

1880 isinstance(m, messages.UndefinedName) or 

1881 m.message_args[0] != node_name] 

1882 

1883 # Bind name to global scope if it doesn't exist already. 

1884 global_scope.setdefault(node_name, node_value) 

1885 

1886 # Bind name to non-global scopes, but as already "used". 

1887 node_value.used = (global_scope, node) 

1888 for scope in self.scopeStack[global_scope_index + 1:]: 

1889 scope[node_name] = node_value 

1890 

1891 self.scope.indirect_assignments[node_name] = node 

1892 

1893 NONLOCAL = GLOBAL 

1894 

1895 def GENERATOREXP(self, node): 

1896 # the first generator's iterable is eagerly executed in parent scope 

1897 self.handleNode(node.generators[0].iter, node.generators[0]) 

1898 

1899 if isinstance(node, ast.GeneratorExp): 

1900 scope_tp = GeneratorScope 

1901 else: 

1902 scope_tp = ComprehensionScope 

1903 

1904 with self.in_scope(scope_tp): 

1905 self.handleChildren(node.generators[0], omit=('iter',)) 

1906 for gen in node.generators[1:]: 

1907 self.handleNode(gen, node) 

1908 self.handleChildren(node, omit=('generators',)) 

1909 

1910 LISTCOMP = DICTCOMP = SETCOMP = GENERATOREXP 

1911 

1912 def NAME(self, node): 

1913 """ 

1914 Handle occurrence of Name (which can be a load/store/delete access.) 

1915 """ 

1916 # Locate the name in locals / function / globals scopes. 

1917 if isinstance(node.ctx, ast.Load): 

1918 self.handleNodeLoad(node, self.getParent(node)) 

1919 if (node.id == 'locals' and isinstance(self.scope, FunctionScope) and 

1920 isinstance(node._pyflakes_parent, ast.Call)): 

1921 # we are doing locals() call in current scope 

1922 self.scope.usesLocals = True 

1923 elif isinstance(node.ctx, ast.Store): 

1924 self.handleNodeStore(node) 

1925 elif isinstance(node.ctx, ast.Del): 

1926 self.handleNodeDelete(node) 

1927 else: 

1928 # Unknown context 

1929 raise RuntimeError(f"Got impossible expression context: {node.ctx!r}") 

1930 

1931 def CONTINUE(self, node): 

1932 # Walk the tree up until we see a loop (OK), a function or class 

1933 # definition (not OK), for 'continue', a finally block (not OK), or 

1934 # the top module scope (not OK) 

1935 n = node 

1936 while hasattr(n, '_pyflakes_parent'): 

1937 n, n_child = n._pyflakes_parent, n 

1938 if isinstance(n, (ast.While, ast.For, ast.AsyncFor)): 

1939 # Doesn't apply unless it's in the loop itself 

1940 if n_child not in n.orelse: 

1941 return 

1942 if isinstance(n, (ast.FunctionDef, ast.ClassDef)): 

1943 break 

1944 if isinstance(node, ast.Continue): 

1945 self.report(messages.ContinueOutsideLoop, node) 

1946 else: # ast.Break 

1947 self.report(messages.BreakOutsideLoop, node) 

1948 

1949 BREAK = CONTINUE 

1950 

1951 def RETURN(self, node): 

1952 if isinstance(self.scope, (ClassScope, ModuleScope)): 

1953 self.report(messages.ReturnOutsideFunction, node) 

1954 return 

1955 

1956 self.handleNode(node.value, node) 

1957 

1958 def YIELD(self, node): 

1959 if isinstance(self.scope, (ClassScope, ModuleScope)): 

1960 self.report(messages.YieldOutsideFunction, node) 

1961 return 

1962 

1963 self.handleNode(node.value, node) 

1964 

1965 AWAIT = YIELDFROM = YIELD 

1966 

1967 def FUNCTIONDEF(self, node): 

1968 for deco in node.decorator_list: 

1969 self.handleNode(deco, node) 

1970 

1971 with self._type_param_scope(node): 

1972 self.LAMBDA(node) 

1973 

1974 self.addBinding(node, FunctionDefinition(node.name, node)) 

1975 # doctest does not process doctest within a doctest, 

1976 # or in nested functions. 

1977 if (self.withDoctest and 

1978 not self._in_doctest() and 

1979 not isinstance(self.scope, FunctionScope)): 

1980 self.deferFunction(lambda: self.handleDoctests(node)) 

1981 

1982 ASYNCFUNCTIONDEF = FUNCTIONDEF 

1983 

1984 def LAMBDA(self, node): 

1985 args = [] 

1986 annotations = [] 

1987 

1988 for arglist in ( 

1989 node.args.posonlyargs, 

1990 node.args.args, 

1991 node.args.kwonlyargs, 

1992 ): 

1993 for arg in arglist: 

1994 args.append(arg.arg) 

1995 annotations.append(arg.annotation) 

1996 defaults = node.args.defaults + node.args.kw_defaults 

1997 

1998 for wildcard in (node.args.vararg, node.args.kwarg): 

1999 if not wildcard: 

2000 continue 

2001 args.append(wildcard.arg) 

2002 annotations.append(wildcard.annotation) 

2003 

2004 if not isinstance(node, ast.Lambda): 

2005 annotations.append(node.returns) 

2006 

2007 if len(set(args)) < len(args): 

2008 for (idx, arg) in enumerate(args): 

2009 if arg in args[:idx]: 

2010 self.report(messages.DuplicateArgument, node, arg) 

2011 

2012 for annotation in annotations: 

2013 self.handleAnnotation(annotation, node) 

2014 

2015 for default in defaults: 

2016 self.handleNode(default, node) 

2017 

2018 def runFunction(): 

2019 with self.in_scope(FunctionScope): 

2020 self.handleChildren( 

2021 node, 

2022 omit=('decorator_list', 'returns', 'type_params'), 

2023 ) 

2024 

2025 self.deferFunction(runFunction) 

2026 

2027 def ARGUMENTS(self, node): 

2028 self.handleChildren(node, omit=('defaults', 'kw_defaults')) 

2029 

2030 def ARG(self, node): 

2031 self.addBinding(node, Argument(node.arg, node)) 

2032 

2033 def CLASSDEF(self, node): 

2034 """ 

2035 Check names used in a class definition, including its decorators, base 

2036 classes, and the body of its definition. Additionally, add its name to 

2037 the current scope. 

2038 """ 

2039 for deco in node.decorator_list: 

2040 self.handleNode(deco, node) 

2041 

2042 with self._type_param_scope(node): 

2043 for baseNode in node.bases: 

2044 self.handleNode(baseNode, node) 

2045 for keywordNode in node.keywords: 

2046 self.handleNode(keywordNode, node) 

2047 with self.in_scope(ClassScope): 

2048 # doctest does not process doctest within a doctest 

2049 # classes within classes are processed. 

2050 if (self.withDoctest and 

2051 not self._in_doctest() and 

2052 not isinstance(self.scope, FunctionScope)): 

2053 self.deferFunction(lambda: self.handleDoctests(node)) 

2054 for stmt in node.body: 

2055 self.handleNode(stmt, node) 

2056 

2057 self.addBinding(node, ClassDefinition(node.name, node)) 

2058 

2059 def ASSIGN(self, node): 

2060 self.handleNode(node.value, node) 

2061 self.handleChildren(node, omit=('value',)) 

2062 

2063 NAMEDEXPR = ASSIGN 

2064 

2065 def AUGASSIGN(self, node): 

2066 self.handleNodeLoad(node.target, node) 

2067 self.handleNode(node.value, node) 

2068 self.handleNode(node.target, node) 

2069 

2070 def ANNASSIGN(self, node): 

2071 self.handleAnnotation(node.annotation, node) 

2072 # If the assignment has value, handle the *value* now. 

2073 if node.value: 

2074 # If the annotation is `TypeAlias`, handle the *value* as an annotation. 

2075 if _is_typing(node.annotation, 'TypeAlias', self.scopeStack): 

2076 with self._enter_annotation(AnnotationState.STR_AS_TYPE): 

2077 self.handleNode(node.value, node) 

2078 else: 

2079 self.handleNode(node.value, node) 

2080 self.handleNode(node.target, node) 

2081 

2082 def TYPEALIAS(self, node): # pragma: >=3.12 cover 

2083 with self._type_param_scope(node): 

2084 self.handle_annotation_always_deferred(node.value, node) 

2085 self.handleNode(node.name, node) 

2086 

2087 def TUPLE(self, node): 

2088 if isinstance(node.ctx, ast.Store): 

2089 # Python 3 advanced tuple unpacking: a, *b, c = d. 

2090 # Only one starred expression is allowed, and no more than 1<<8 

2091 # assignments are allowed before a stared expression. There is 

2092 # also a limit of 1<<24 expressions after the starred expression, 

2093 # which is impossible to test due to memory restrictions, but we 

2094 # add it here anyway 

2095 has_starred = False 

2096 star_loc = -1 

2097 for i, n in enumerate(node.elts): 

2098 if isinstance(n, ast.Starred): 

2099 if has_starred: 

2100 self.report(messages.TwoStarredExpressions, node) 

2101 # The SyntaxError doesn't distinguish two from more 

2102 # than two. 

2103 break 

2104 has_starred = True 

2105 star_loc = i 

2106 if star_loc >= 1 << 8 or len(node.elts) - star_loc - 1 >= 1 << 24: 

2107 self.report(messages.TooManyExpressionsInStarredAssignment, node) 

2108 self.handleChildren(node) 

2109 

2110 LIST = TUPLE 

2111 

2112 def _in_try(self, node): # pragma: >=3.15 cover 

2113 while True: 

2114 node = self.getParent(node) 

2115 if isinstance(node, (ast.Try, ast.TryStar, ast.ExceptHandler)): 

2116 return True 

2117 elif isinstance(node, ast.Module): 

2118 return False 

2119 

2120 def IMPORT(self, node): 

2121 lazy = sys.version_info >= (3, 15) and node.is_lazy 

2122 if lazy and not isinstance(self.scope, ModuleScope): # pragma: >=3.15 cover 

2123 self.report(messages.LazyImportNotAtModuleScope, node) 

2124 return 

2125 elif lazy and self._in_try(node): # pragma: >=3.15 cover 

2126 self.report(messages.LazyImportNotAtModuleScope, node) 

2127 return 

2128 

2129 for alias in node.names: 

2130 if '.' in alias.name and not alias.asname: 

2131 importation = SubmoduleImportation( 

2132 alias.name, node, 

2133 is_lazy=lazy, 

2134 ) 

2135 else: 

2136 name = alias.asname or alias.name 

2137 importation = Importation(name, node, alias.name, is_lazy=lazy) 

2138 self.addBinding(node, importation) 

2139 

2140 def IMPORTFROM(self, node): 

2141 if node.module == '__future__': 

2142 if not self.futuresAllowed: 

2143 self.report(messages.LateFutureImport, node) 

2144 else: 

2145 self.futuresAllowed = False 

2146 

2147 lazy = sys.version_info >= (3, 15) and node.is_lazy 

2148 if lazy and not isinstance(self.scope, ModuleScope): # pragma: >=3.15 cover 

2149 self.report(messages.LazyImportNotAtModuleScope, node) 

2150 return 

2151 elif lazy and self._in_try(node): # pragma: >=3.15 cover 

2152 self.report(messages.LazyImportNotAtModuleScope, node) 

2153 return 

2154 

2155 module = ('.' * node.level) + (node.module or '') 

2156 

2157 for alias in node.names: 

2158 name = alias.asname or alias.name 

2159 if node.module == '__future__': 

2160 importation = FutureImportation(name, node, self.scope) 

2161 if alias.name not in __future__.all_feature_names: # pragma: <3.14 cover 

2162 self.report(messages.FutureFeatureNotDefined, 

2163 node, alias.name) 

2164 if alias.name == 'annotations': 

2165 self.annotationsFutureEnabled = True 

2166 elif alias.name == '*': 

2167 if not isinstance(self.scope, ModuleScope): 

2168 self.report(messages.ImportStarNotPermitted, node, module) 

2169 continue 

2170 elif lazy: # pragma: >=3.15 cover 

2171 self.report(messages.LazyImportStarNotPermitted, node, module) 

2172 continue 

2173 

2174 self.scope.importStarred = True 

2175 self.report(messages.ImportStarUsed, node, module) 

2176 importation = StarImportation(module, node) 

2177 else: 

2178 importation = ImportationFrom( 

2179 name, node, module, alias.name, 

2180 is_lazy=lazy, 

2181 ) 

2182 self.addBinding(node, importation) 

2183 

2184 def TRY(self, node): 

2185 handler_names = [] 

2186 # List the exception handlers 

2187 for i, handler in enumerate(node.handlers): 

2188 if isinstance(handler.type, ast.Tuple): 

2189 for exc_type in handler.type.elts: 

2190 handler_names.append(getNodeName(exc_type)) 

2191 elif handler.type: 

2192 handler_names.append(getNodeName(handler.type)) 

2193 

2194 if handler.type is None and i < len(node.handlers) - 1: 

2195 self.report(messages.DefaultExceptNotLast, handler) 

2196 # Memorize the except handlers and process the body 

2197 self.exceptHandlers.append(handler_names) 

2198 for child in node.body: 

2199 self.handleNode(child, node) 

2200 self.exceptHandlers.pop() 

2201 # Process the other nodes: "except:", "else:", "finally:" 

2202 self.handleChildren(node, omit='body') 

2203 

2204 TRYSTAR = TRY 

2205 

2206 def EXCEPTHANDLER(self, node): 

2207 if node.name is None: 

2208 self.handleChildren(node) 

2209 return 

2210 

2211 # If the name already exists in the scope, modify state of existing 

2212 # binding. 

2213 if node.name in self.scope: 

2214 self.handleNodeStore(node) 

2215 

2216 # 3.x: the name of the exception, which is not a Name node, but a 

2217 # simple string, creates a local that is only bound within the scope of 

2218 # the except: block. As such, temporarily remove the existing binding 

2219 # to more accurately determine if the name is used in the except: 

2220 # block. 

2221 

2222 try: 

2223 prev_definition = self.scope.pop(node.name) 

2224 except KeyError: 

2225 prev_definition = None 

2226 

2227 self.handleNodeStore(node) 

2228 self.handleChildren(node) 

2229 

2230 # See discussion on https://github.com/PyCQA/pyflakes/pull/59 

2231 

2232 # We're removing the local name since it's being unbound after leaving 

2233 # the except: block and it's always unbound if the except: block is 

2234 # never entered. This will cause an "undefined name" error raised if 

2235 # the checked code tries to use the name afterwards. 

2236 # 

2237 # Unless it's been removed already. Then do nothing. 

2238 

2239 try: 

2240 binding = self.scope.pop(node.name) 

2241 except KeyError: 

2242 pass 

2243 else: 

2244 if not binding.used: 

2245 self.report(messages.UnusedVariable, node, node.name) 

2246 

2247 # Restore. 

2248 if prev_definition: 

2249 self.scope[node.name] = prev_definition 

2250 

2251 def COMPARE(self, node): 

2252 left = node.left 

2253 for op, right in zip(node.ops, node.comparators): 

2254 if ( 

2255 isinstance(op, (ast.Is, ast.IsNot)) and ( 

2256 _is_const_non_singleton(left) or 

2257 _is_const_non_singleton(right) 

2258 ) 

2259 ): 

2260 self.report(messages.IsLiteral, node) 

2261 left = right 

2262 

2263 self.handleChildren(node) 

2264 

2265 MATCH = MATCH_CASE = MATCHCLASS = MATCHOR = MATCHSEQUENCE = handleChildren 

2266 MATCHSINGLETON = MATCHVALUE = handleChildren 

2267 

2268 def _match_target(self, node): 

2269 self.handleNodeStore(node) 

2270 self.handleChildren(node) 

2271 

2272 MATCHAS = MATCHMAPPING = MATCHSTAR = _match_target 

2273 

2274 @contextlib.contextmanager 

2275 def _type_param_scope(self, node): 

2276 with contextlib.ExitStack() as ctx: 

2277 if sys.version_info >= (3, 12): # pragma: >=3.12 cover 

2278 ctx.enter_context(self.in_scope(TypeScope)) 

2279 for param in node.type_params: 

2280 self.handleNode(param, node) 

2281 yield 

2282 

2283 def TYPEVAR(self, node): # pragma: >=3.12 cover 

2284 self.handleNodeStore(node) 

2285 self.handle_annotation_always_deferred(node.bound, node) 

2286 

2287 PARAMSPEC = TYPEVARTUPLE = handleNodeStore