MCPcopy Create free account
hub / github.com/python/mypy / LimitedVariableRenameVisitor

Class LimitedVariableRenameVisitor

mypy/renaming.py:427–576  ·  view source on GitHub ↗

Perform some limited variable renaming in with statements. This allows reusing a variable in multiple with statements with different types. For example, the two instances of 'x' can have incompatible types: with C() as x: f(x) with D() as x: g(x)

Source from the content-addressed store, hash-verified

425
426
427class LimitedVariableRenameVisitor(TraverserVisitor):
428 """Perform some limited variable renaming in with statements.
429
430 This allows reusing a variable in multiple with statements with
431 different types. For example, the two instances of 'x' can have
432 incompatible types:
433
434 with C() as x:
435 f(x)
436 with D() as x:
437 g(x)
438
439 The above code gets renamed conceptually into this (not valid Python!):
440
441 with C() as x':
442 f(x')
443 with D() as x:
444 g(x)
445
446 If there's a reference to a variable defined in 'with' outside the
447 statement, or if there's any trickiness around variable visibility
448 (e.g. function definitions), we give up and won't perform renaming.
449
450 The main use case is to allow binding both readable and writable
451 binary files into the same variable. These have different types:
452
453 with open(fnam, 'rb') as f: ...
454 with open(fnam, 'wb') as f: ...
455 """
456
457 def __init__(self) -> None:
458 # Short names of variables bound in with statements using "as"
459 # in a surrounding scope
460 self.bound_vars: list[str] = []
461 # Stack of names that can't be safely renamed, per scope ('*' means that
462 # no names can be renamed)
463 self.skipped: list[set[str]] = []
464 # References to variables that we may need to rename. Stack of
465 # scopes; each scope is a mapping from name to list of collections
466 # of names that refer to the same logical variable.
467 self.refs: list[dict[str, list[list[NameExpr]]]] = []
468
469 def visit_mypy_file(self, file_node: MypyFile) -> None:
470 """Rename variables within a file.
471
472 This is the main entry point to this class.
473 """
474 with self.enter_scope():
475 for d in file_node.defs:
476 d.accept(self)
477
478 def visit_func_def(self, fdef: FuncDef) -> None:
479 self.reject_redefinition_of_vars_in_scope()
480 with self.enter_scope():
481 for arg in fdef.arguments:
482 self.record_skipped(arg.variable.name)
483 super().visit_func_def(fdef)
484

Callers 1

Calls

no outgoing calls

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…