eric6/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py

changeset 7064
1010f737def2
parent 7060
d04e8965af91
child 7360
9190402e4505
equal deleted inserted replaced
7063:2bea77c643a0 7064:1010f737def2
512 512
513 class DoctestScope(ModuleScope): 513 class DoctestScope(ModuleScope):
514 """Scope for a doctest.""" 514 """Scope for a doctest."""
515 515
516 516
517 class DummyNode(object):
518 """Used in place of an `ast.AST` to set error message positions"""
519 def __init__(self, lineno, col_offset):
520 self.lineno = lineno
521 self.col_offset = col_offset
522
523
517 # Globally defined names which are not attributes of the builtins module, or 524 # Globally defined names which are not attributes of the builtins module, or
518 # are only present on some platforms. 525 # are only present on some platforms.
519 _MAGIC_GLOBALS = ['__file__', '__builtins__', 'WindowsError'] 526 _MAGIC_GLOBALS = ['__file__', '__builtins__', 'WindowsError']
520 # module scope annotation will store in `__annotations__`, see also PEP 526. 527 # module scope annotation will store in `__annotations__`, see also PEP 526.
521 if PY36_PLUS: 528 if PY36_PLUS:
528 return node.id 535 return node.id
529 if hasattr(node, 'name'): # an ExceptHandler node 536 if hasattr(node, 'name'): # an ExceptHandler node
530 return node.name 537 return node.name
531 538
532 539
533 def is_typing_overload(value, scope): 540 def is_typing_overload(value, scope_stack):
541 def name_is_typing_overload(name): # type: (str) -> bool
542 for scope in reversed(scope_stack):
543 if name in scope:
544 return (
545 isinstance(scope[name], ImportationFrom) and
546 scope[name].fullName == 'typing.overload'
547 )
548 else:
549 return False
550
534 def is_typing_overload_decorator(node): 551 def is_typing_overload_decorator(node):
535 return ( 552 return (
536 ( 553 (
537 isinstance(node, ast.Name) and 554 isinstance(node, ast.Name) and name_is_typing_overload(node.id)
538 node.id in scope and
539 scope[node.id].fullName == 'typing.overload'
540 ) or ( 555 ) or (
541 isinstance(node, ast.Attribute) and 556 isinstance(node, ast.Attribute) and
542 isinstance(node.value, ast.Name) and 557 isinstance(node.value, ast.Name) and
543 node.value.id == 'typing' and 558 node.value.id == 'typing' and
544 node.attr == 'overload' 559 node.attr == 'overload'
545 ) 560 )
546 ) 561 )
547 562
548 return ( 563 return (
549 isinstance(value.source, ast.FunctionDef) and 564 isinstance(value.source, ast.FunctionDef) and
550 len(value.source.decorator_list) == 1 and 565 any(
551 is_typing_overload_decorator(value.source.decorator_list[0]) 566 is_typing_overload_decorator(dec)
567 for dec in value.source.decorator_list
568 )
552 ) 569 )
553 570
554 571
555 def make_tokens(code): 572 def make_tokens(code):
556 # PY3: tokenize.tokenize requires readline of bytes 573 # PY3: tokenize.tokenize requires readline of bytes
885 (FOR_TYPES, ast.comprehension))): 902 (FOR_TYPES, ast.comprehension))):
886 self.report(messages.RedefinedInListComp, 903 self.report(messages.RedefinedInListComp,
887 node, value.name, existing.source) 904 node, value.name, existing.source)
888 elif not existing.used and value.redefines(existing): 905 elif not existing.used and value.redefines(existing):
889 if value.name != '_' or isinstance(existing, Importation): 906 if value.name != '_' or isinstance(existing, Importation):
890 if not is_typing_overload(existing, self.scope): 907 if not is_typing_overload(existing, self.scopeStack):
891 self.report(messages.RedefinedWhileUnused, 908 self.report(messages.RedefinedWhileUnused,
892 node, value.name, existing.source) 909 node, value.name, existing.source)
893 910
894 elif isinstance(existing, Importation) and value.redefines(existing): 911 elif isinstance(existing, Importation) and value.redefines(existing):
895 existing.redefined.append(node) 912 existing.redefined.append(node)
1060 for part in parts: 1077 for part in parts:
1061 if PY2: 1078 if PY2:
1062 part = part.replace('...', 'Ellipsis') 1079 part = part.replace('...', 'Ellipsis')
1063 self.deferFunction(functools.partial( 1080 self.deferFunction(functools.partial(
1064 self.handleStringAnnotation, 1081 self.handleStringAnnotation,
1065 part, node, lineno, col_offset, 1082 part, DummyNode(lineno, col_offset), lineno, col_offset,
1066 messages.CommentAnnotationSyntaxError, 1083 messages.CommentAnnotationSyntaxError,
1067 )) 1084 ))
1068 1085
1069 def handleChildren(self, tree, omit=None): 1086 def handleChildren(self, tree, omit=None):
1070 self._handle_type_comments(tree) 1087 self._handle_type_comments(tree)
1310 # One 'global' statement can bind multiple (comma-delimited) names. 1327 # One 'global' statement can bind multiple (comma-delimited) names.
1311 for node_name in node.names: 1328 for node_name in node.names:
1312 node_value = Assignment(node_name, node) 1329 node_value = Assignment(node_name, node)
1313 1330
1314 # Remove UndefinedName messages already reported for this name. 1331 # Remove UndefinedName messages already reported for this name.
1315 # TO DO: if the global is not used in this scope, it does not 1332 # TODO: if the global is not used in this scope, it does not
1316 # become a globally defined name. See test_unused_global. 1333 # become a globally defined name. See test_unused_global.
1317 self.messages = [ 1334 self.messages = [
1318 m for m in self.messages if not 1335 m for m in self.messages if not
1319 isinstance(m, messages.UndefinedName) or 1336 isinstance(m, messages.UndefinedName) or
1320 m.message_args[0] != node_name] 1337 m.message_args[0] != node_name]
1469 1486
1470 def runFunction(): 1487 def runFunction():
1471 1488
1472 self.pushScope() 1489 self.pushScope()
1473 1490
1474 self.handleChildren(node, omit='decorator_list') 1491 self.handleChildren(node, omit=['decorator_list', 'returns'])
1475 1492
1476 def checkUnusedAssignments(): 1493 def checkUnusedAssignments():
1477 """ 1494 """
1478 Check to see if any assignments have not been used. 1495 Check to see if any assignments have not been used.
1479 """ 1496 """

eric ide

mercurial