def collect_gen_expr(statement_info): expressions = [] # Join all of the constant expressions into a single GeneralExpression. constant_names = [] lines = [] for names, node in statement_info.constant_expressions: lines.append(unparse(node)) # Inform the statement of the variables it is writing to. constant_names.extend(names) if lines: ge = GeneralExpression() ge.code = ''.join(lines) expressions.append(ge) for node in statement_info.general_assignments: ge = GeneralExpression() ge.code = unparse(node) # Now check this expression for any inputs that are provided by the # import statements we had. If so, add that import statement to the # object and remove that input. imported_inputs = [] for iv in ge.inputs: node = statement_info.import_statements.get(iv.binding, None) if node is not None: ge.import_statements.append(unparse(node)) imported_inputs.append(iv) for iv in imported_inputs: ge.inputs.remove(iv) expressions.append(ge) return expressions
def test_multi_line_partial_delete_block_update(self): code = "x=1\ny=2+x\nz=3" block = Block(code) code_block = CodeBlock(code=code) new_code="x=1\ny=2" code_block.code = new_code self.assertEqual(len(code_block.block.ast.nodes), 2) self.assertEqual(unparse(code_block.block.ast.nodes[0]).strip(), "x = 1") self.assertEqual(unparse(code_block.block.ast.nodes[1]).strip(), "y = 2")
def test_block_static(self): """ Tests if a block changes if a line does not change """ code = "x=1\ny=2\nz=3" block = Block(code) code_block = CodeBlock(code=code) new_code="x=1\ny=2" old_block = code_block.block.sub_blocks[0] code_block.code = new_code new_block = code_block.block.sub_blocks[0] self.assertEqual(unparse(old_block.ast), unparse(new_block.ast)) self.assertEqual(old_block.uuid, new_block.uuid)
def test_block_static(self): """ Tests if a block changes if a line does not change """ code = "x=1\ny=2\nz=3" block = Block(code) code_block = CodeBlock(code=code) new_code = "x=1\ny=2" old_block = code_block.block.sub_blocks[0] code_block.code = new_code new_block = code_block.block.sub_blocks[0] self.assertEqual(unparse(old_block.ast), unparse(new_block.ast)) self.assertEqual(old_block.uuid, new_block.uuid)
def test_multi_line_partial_delete_block_update(self): code = "x=1\ny=2+x\nz=3" block = Block(code) code_block = CodeBlock(code=code) new_code = "x=1\ny=2" code_block.code = new_code self.assertEqual(len(code_block.block.ast.nodes), 2) self.assertEqual( unparse(code_block.block.ast.nodes[0]).strip(), "x = 1") self.assertEqual( unparse(code_block.block.ast.nodes[1]).strip(), "y = 2")
def _get_keyword_defaults(default_nodes, func_name): """ Translate the default nodes of an ast into default arguments. """ # Unwrap the default values. # fixme: We could stand better warning messages here. defaults = [] for node in default_nodes: # fixme if isinstance(node, compiler.ast.Const): default = str(node.value) elif isinstance(node, compiler.ast.Name): if node.name in ["None", "True", "False"]: default = node.name else: msg = "Got variable name for keyword value in " \ "function: %s. Using its name: %s" % \ (func_name, node.name) warnings.warn(msg) default = node.name else: # Try unparsing and evaluating it. This will work if # the value is something like "-1.0". If we fail for # any reason, issue a warning and use undefined as the # value. try: default = unparse(node) except: msg = "Got '%s' node for keyword value in function." \ " Using None as a stopgap." % node warnings.warn(msg) default = None defaults.append(default) return defaults
def _get_keyword_defaults(default_nodes, func_name): """ Translate the default nodes of an ast into default arguments. """ # Unwrap the default values. # fixme: We could stand better warning messages here. defaults=[] for node in default_nodes: # fixme if isinstance(node, compiler.ast.Const): default = str(node.value) elif isinstance(node, compiler.ast.Name): if node.name in ["None", "True", "False"]: default = node.name else: msg = "Got variable name for keyword value in " \ "function: %s. Using its name: %s" % \ (func_name, node.name) warnings.warn(msg) default = node.name else: # Try unparsing and evaluating it. This will work if # the value is something like "-1.0". If we fail for # any reason, issue a warning and use undefined as the # value. try: default = unparse(node) except: msg = "Got '%s' node for keyword value in function." \ " Using None as a stopgap." % node warnings.warn(msg) default = None defaults.append(default) return defaults
def test_block_static_special_case(self): """ Tests if a block changes if a line does not change when its the only line unchanged """ code = "x=1\ny=2+x\nz=3" block = Block(code) code_block = CodeBlock(code=code) old_ast = code_block.block.ast old_block = code_block.block.sub_blocks[0] new_code = "x=1\ny=2" code_block.code = new_code new_block = code_block.block.sub_blocks[0] self.assertNotEqual(unparse(old_ast), unparse(code_block.block.ast)) self.assertEqual(unparse(old_block.ast), unparse(new_block.ast)) self.assertEqual(old_block.uuid, new_block.uuid)
def test_block_static_special_case(self): """ Tests if a block changes if a line does not change when its the only line unchanged """ code = "x=1\ny=2+x\nz=3" block = Block(code) code_block = CodeBlock(code=code) old_ast = code_block.block.ast old_block = code_block.block.sub_blocks[0] new_code="x=1\ny=2" code_block.code = new_code new_block = code_block.block.sub_blocks[0] self.assertNotEqual(unparse(old_ast), unparse(code_block.block.ast)) self.assertEqual(unparse(old_block.ast), unparse(new_block.ast)) self.assertEqual(old_block.uuid, new_block.uuid)
def test_block_name_replacer(self): """ Does BlockNameReplacer work? """ code = "x = x(x, x)\nx\n" desired = "y = y(y, y)\ny\n" b = Block(code) rename_variable(b.ast, 'x', 'y') self.assertEqual(desired, unparse(b.ast))
def test_block_decomposition(self): """ Tests if a block changes if its the only line left """ code = "x=1\ny=2" block = Block(code) code_block = CodeBlock(code=code) old_ast = code_block.block.ast old_block = code_block.block.sub_blocks[0] new_code = "x=1" code_block.code = new_code new_block = code_block.block.sub_blocks[0] self.assertNotEqual(unparse(old_ast), unparse(code_block.block.ast)) self.assertEqual(unparse(old_block.ast), unparse(new_block.ast)) self.assertEqual(old_block.uuid, new_block.uuid)
def test_block_decomposition(self): """ Tests if a block changes if its the only line left """ code = "x=1\ny=2" block = Block(code) code_block = CodeBlock(code=code) old_ast = code_block.block.ast old_block = code_block.block.sub_blocks[0] new_code="x=1" code_block.code = new_code new_block = code_block.block.sub_blocks[0] self.assertNotEqual(unparse(old_ast), unparse(code_block.block.ast)) self.assertEqual(unparse(old_block.ast), unparse(new_block.ast)) self.assertEqual(old_block.uuid, new_block.uuid)
def _check_round_trip(self, code, desired=None): """ Check the roundtripped code against a desired result. if desired=None (default), then check it against the input code. """ if desired is None: desired = code ast = compiler.parse(code,'exec') actual = unparse(ast) self.assertEqual(desired.strip(), actual.strip())
def _check_round_trip(self, code, desired=None): """ Check the roundtripped code against a desired result. if desired=None (default), then check it against the input code. """ if desired is None: desired = code ast = compiler.parse(code, 'exec') actual = unparse(ast) self.assertEqual(desired.strip(), actual.strip())
def _get_imports_and_locals(self): """ Generate the import statements and local definitions Should we worry about the order of the imports? """ local_funcs = [] imports = {} # function_calls = [statement for statement in self.statements \ # if isinstance(statement, FunctionCall) ] # # # Function calls merged into a group # for stmt in self.statements: # if isinstance(stmt, FunctionCallGroup): # for statement in stmt.group_statements: # function_calls.append(statement) function_calls = explode_model_func_calls(self.statements) info_items = set([(call.label_name, call.function) for call in function_calls]) for name, func in info_items: if isinstance(func, PythonFunctionInfo): # This function is imported # FIXME - Need to be able to handle 'as' names. # If a function has an 'as' name, then it shouldn't be added # to the imports dictionary. module = func.module if imports.has_key(module): imports[module].append(name) else: imports[module] = [name] elif isinstance(func, LocalFunctionInfo): local_funcs.append(func.code + '\n') import_lines = [] for module in imports: names = [] for name in imports[module]: names.append((name, None)) import_lines.append(unparse(From(module, names, 0))) # Get the import statements from GeneralExpressions. for stmt in self.statements: if isinstance(stmt, GeneralExpression): import_lines.extend(stmt.import_statements) # Uniquify the import list while maintaining order. seen = set() unique_lines = [] for line in import_lines: if line not in seen: unique_lines.append(line) seen.add(line) return ''.join(unique_lines) + '\n' + ''.join(local_funcs)
def _check_round_trip_func_no_indent(self, code, desired=None): """ Check the roundtripped code against a desired result. Function definitions will be on a single line. if desired=None (default), then check it against the input code. """ if desired is None: desired = code ast = compiler.parse(code,'exec') actual = unparse(ast, True) self.assertEqual(desired.strip(), actual.strip())
def _check_round_trip_func_no_indent(self, code, desired=None): """ Check the roundtripped code against a desired result. Function definitions will be on a single line. if desired=None (default), then check it against the input code. """ if desired is None: desired = code ast = compiler.parse(code, 'exec') actual = unparse(ast, True) self.assertEqual(desired.strip(), actual.strip())
def save_block_to_file(self, file_path): """ Save the block to a file as python code. """ # We convert the block to code directly instead of using the # code displayed, because the user may have put it in an unparsable # state. # fixme: Is this what we should do? # Should write it out as .py file split_path = os.path.splitext(file_path) if split_path[1] != 'py': new_path = '.'.join((split_path[0], 'py')) else: new_path = file_path # Save the current code to the file. file_obj = open(new_path, 'w') block_code = unparse(self.block_unit.codeblock.block.ast) file_obj.write(block_code) file_obj.close() # And point at the new path name. self.file_path = new_path return
def visitFrom(self, node): if node.names[0][0] == '*': raise ValueError('cannot deal * imports: %s' % unparse(node)) for name, alias in node.names: self.imported_names.append(alias or name)
def from_function_ast(cls, function_ast): code = unparse(function_ast) return cls(code=code)
def visitFrom(self, node): if node.names[0][0] == '*': raise ValueError('cannot deal * imports: %s' % unparse(node)) for name, alias in node.names: self.import_statements[(alias or name)] = node