def updatePyAstVariableUsages(pyAst, variablesInScope, varsToTurnIntoCalls, isClassContext): #in the variables we've been handed, every member access chain 'x.y.z' has been #replaced with an actual variable lookup of the form 'x.y.z'. We need to perform #this same replacement in the actual python source code we're running, since #we may not actually have enough information to recover 'x' replacements = {} for possible_replacement in variablesInScope: if '.' in possible_replacement: replacements[tuple( possible_replacement.split('.'))] = possible_replacement #we need to deepcopy the AST since the collapser modifies the AST, and this is just a #slice of a cached tree. pyAst = ast.fix_missing_locations(copy.deepcopy(pyAst)) if varsToTurnIntoCalls: pyAst = PyAstFreeVariableAnalyses.replaceUsesWithCalls( pyAst, set(varsToTurnIntoCalls), isClassContext) pyAst = PyAstFreeVariableAnalyses.collapseFreeVariableMemberAccessChains( pyAst, replacements, isClassContext=isClassContext) return ast.fix_missing_locations(pyAst)
def test_FreeVariableTransformer_3(self): tree = ast.parse( textwrap.dedent(""" def g(y): return x.y.z.__str__() """)) # deep-copy tree because transformers modify the AST in place # making the test of areAstsIdentical(tree, tree') meaningless tree1 = copy.deepcopy(tree) tree2 = PyAstFreeVariableAnalyses.collapseFreeVariableMemberAccessChains( tree1, {('x', 'y', 'z'): 'x_y_z'}, isClassContext=False) self.assertIsNotNone(tree2) self.assertFalse(PyAstUtil.areAstsIdentical(tree, tree2))