def visit_TryExcept(self, node): existing_node = self.generic_visit(node) for handler in existing_node.handlers: handler_name = getattr(handler.name, 'id', handler.name) if handler_name is not None: handler.body.insert(0, self._create_context_call( 'assign', [Str(s=handler_name), Name(id=handler_name, ctx=Load()), Num(n=handler.lineno)])) return existing_node
def construct_assign_dict(target, dict_name): # construct_assign_dict('a','d') # -> a = d['a'] from ast import Assign, Name, Store, Subscript, Load, Index, Str a = target d = dict_name expr = Assign(targets=[Name(id=a, ctx=Store())], value=Subscript(value=Name(id=d, ctx=Load()), slice=Index(value=Str(s=a)), ctx=Load())) return expr
def visit_Assign(self, node): existing_node = self.generic_visit(node) new_nodes = [existing_node] existing_node.value = self._create_bare_context_call( 'assign', [ Str(s=self._get_assignment_targets(existing_node.targets)), existing_node.value, Num(n=existing_node.lineno) ]) return new_nodes
def test_get_value(self) -> None: """Tests get_value succeeds""" val = "foo" self.assertEqual(get_value(Str(s=val, constant_value=None, string=None)), val) self.assertEqual( get_value(Constant(value=val, constant_value=None, string=None)), val ) self.assertIsInstance(get_value(Tuple(expr=None)), Tuple) self.assertIsInstance(get_value(Tuple(expr=None)), Tuple) self.assertIsNone(get_value(Name(None, None))) self.assertEqual(get_value(get_value(ast.parse("-5").body[0])), -5)
def visit_Name(self, node: Name) -> Union[Name, Call]: if not isinstance(node.ctx, Load): return node delegate = Call(func=Name(id='__autoimport__', ctx=Load()), args=[Str(s=node.id)], keywords=[]) copy_location(delegate, node) fix_missing_locations(delegate) return delegate
def visit_constant(self, constant: Expr): """Proceeds by converting constant value to a numpy array and converting it to the appropriate value in the generated code (whether it be a Python scalar or a Numpy array)""" value = constant.data.asnumpy() const_expr = ast.Call( ast.Attribute(Name("numpy", Load()), "array", Load()), [self.parse_numpy_array(value)], [ast.keyword("dtype", Str(constant.checked_type.dtype))], ) return (self.create_call("nd.array", [const_expr]), [])
def document(tree, **kw): # Simplify it just to show the problem isn't related to the content of the macro return tree """ This macro takes literal strings and converts them into: _help_ID = type_hint+STRING where: ID is the first target of the last assignment. type_hint is the assigned type and default value (only works for a few types) STRING is the literal string """ for n in range(len(tree)): s = tree[n] if not n: prev = s continue # The whole sentence is a string? if (isinstance(s, Expr) and isinstance(s.value, Str) and # and the previous is an assign isinstance(prev, Assign)): # noqa: E128 # Apply it to the first target target = prev.targets[0] value = prev.value # Extract its name # variables and attributes are supported if isinstance(target, Name): name = target.id is_attr = False elif isinstance(target, Attribute): name = target.attr is_attr = True else: continue # Remove starting underscore if name[0] == '_': name = name[1:] # Create a _help_ID doc_id = '_help_'+name # Create the type hint for numbers, strings and booleans type_hint = '' if isinstance(value, Num): type_hint = '[number={}]'.format(value.n) elif isinstance(value, Str): type_hint = "[string='{}']".format(value.s) elif isinstance(value, NameConstant) and isinstance(value.value, bool): type_hint = '[boolean={}]'.format(str(value.value).lower()) # Transform the string into an assign for _help_ID if is_attr: target = Attribute(value=Name(id='self', ctx=Load()), attr=doc_id, ctx=Store()) else: target = Name(id=doc_id, ctx=Store()) tree[n] = Assign(targets=[target], value=Str(s=type_hint+s.value.s)) prev = s # Return the modified AST return tree
def program_src(type_defs: TypesDict, project: CProject, scene: CScene, add_logic: bool = True) -> str: tree = empty_script_tree(project.id, add_main_loop=add_logic) # get object instances from resources object main = find_function("main", tree) last_assign = find_last_assign(main) for obj in scene.objects: add_import(tree, "object_types." + humps.depascalize(obj.type), obj.type, try_to_import=False) last_assign += 1 main.body.insert(last_assign, object_instance_from_res(obj.name, obj.id, obj.type)) # TODO temporary solution - should be (probably) handled by plugin(s) from arcor2 import json # TODO should we put there even unused parameters? for param in project.parameters: val = json.loads(param.value) aval: Optional[expr] = None if isinstance(val, bool): # subclass of int aval = NameConstant(value=val, kind=None) elif isinstance(val, (int, float)): aval = Num(n=val, kind=None) elif isinstance(val, str): aval = Str(s=val, kind="") if not aval: raise Arcor2Exception( f"Unsupported project parameter type ({param.type}) or value ({val})." ) last_assign += 1 main.body.insert( last_assign, Assign( # TODO use rather AnnAssign? targets=[Name(id=param.name, ctx=Store())], value=aval, type_comment=None), ) if add_logic: add_logic_to_loop(type_defs, tree, scene, project) return SCRIPT_HEADER + tree_to_str(tree)
def visit_Name(self, node): if node.id in self.local_dict: return node elif node.id in self.global_dict: name_obj = self.global_dict[node.id] if isinstance(name_obj, (Basic, type)) or callable(name_obj): return node elif node.id in ['True', 'False']: return node return fix_missing_locations( Call(Name('Symbol', Load()), [Str(node.id)], [], None, None))
def _getblockattr(name, lineno, col): """calls getattr(name, '__xonsh_block__', False).""" return xonsh_call( "getattr", args=[ Name(id=name, ctx=Load(), lineno=lineno, col_offset=col), Str(s="__xonsh_block__", lineno=lineno, col_offset=col), NameConstant(value=False, lineno=lineno, col_offset=col), ], lineno=lineno, col=col, )
def visit_Name(self, node): if node.id in self.local_dict: return node elif node.id in self.global_dict: name_obj = self.global_dict[node.id] if isinstance(name_obj, (Basic, type)) or callable(name_obj): return node elif node.id in ["True", "False"]: return node return fix_missing_locations( Call(func=Name("Symbol", Load()), args=[Str(node.id)], keywords=[]) )
def _trace_assignment(self, target, default_lineno=None): lineno = getattr(target, 'lineno', default_lineno) # name, value, line number if isinstance(target, Name): arg_name = target.id elif arg and isinstance(target, arg): arg_name = target.arg else: assert_message = 'Target type was {}.'.format(type(target)) assert isinstance(target, str), assert_message arg_name = target args = [Str(s=arg_name), Name(id=arg_name, ctx=Load()), Num(n=lineno)] return self._create_context_call('assign', args)
def visit_Expr(self, node): '''Rewrite foo.append(...) as foo = invoke(foo, 'append', ...). This depends on the `invoke` method simply knowing which method invocations ought to be saved, thus this is tightly coupled to the pyrsistent API. ''' match = match_ast(self._method_pattern, self.visit(node.value)) if match is None: return cl(Expr(value=self.visit(node.value)), node) subject = match['subject'] args = [subject, Str(s=match['method'])] + match['arguments'] assign = Assign(targets=[Context.set(Store, subject)], value=self.names.call_global(globals.invoke, args, match['keywords'])) return self.visit_Assign(cl(assign, node))
def _do_wrap_class_register(tree, mod, base_class): if isinstance(tree, ClassDef): # Create the register call name = tree.name reg_name = name.lower() # BaseOutput.register member: attr = Attribute(value=Name(id=base_class, ctx=Load()), attr='register', ctx=Load()) # Function call to it passing reg_name and name do_register = Expr(value=Call(func=attr, args=[Str(s=reg_name), Name(id=name, ctx=Load())], keywords=[])) # Create the import do_import = ImportFrom(module=mod, names=[alias(name=base_class, asname=None)], level=1) return [do_import, tree, do_register] # Just in case somebody applies it to anything other than a class return tree # pragma: no cover
def log(expr, **kw): ''' Print the passed value, labeling the output with the expression. Example: d = { 'a': 1 } log[d['a']] # prints # d['a']: 1 ''' label = unparse(expr) + ': ' return Call(func=Name(id='print', ctx=Load()), args=[Str(s=label), expr], keywords=[])
def init(vars): node = Name(id=Log.log_dict, ctx=Store()) var_strs = [Str(s=var.name) for var in vars] void = Call(func=Name(id='Void', ctx=Load())) return [ Assign(targets=[node], value=DictComp(key=Name(id='__key', ctx=Load()), value=Log.__fromkeys(var_strs, void), generators=[ comprehension(target=Name(id='__key', ctx=Store()), iter=Log.__fromkeys( Log.sections)) ])) ]
def wrapper(self, node): # pylint: disable=C0111 if hasattr(node, '_already_process'): self.generic_visit(node) return node call_node = deepcopy(visit_func(self, node).body) node._already_process = True call_node.args[0] = node if not isinstance(node, Subscript)\ else node.value if hasattr(node, 'production_name'): call_node.args[1] = node.production_name self._hint_name = str(node.production_name.s) self._counter = 0 elif not isinstance(node, (Str, Name)): call_node.args[1] = Str(s=self._generate_name()) else: call_node.args[1] = Str(s=self._last_generate_name()) call_node.args[1]._already_process = True call_node = copy_location(call_node, node) self.generic_visit(call_node) return call_node
def _trace_print_function(self, existing_node): values = list(existing_node.args) formats = ['%r'] * len(values) if existing_node.starargs is not None: values.append(existing_node.starargs) formats.append('*%r') for keyword in existing_node.keywords: values.append(keyword.value) formats.append('{}=%r'.format(keyword.arg)) message_format = 'print(' + ', '.join(formats) + ') ' return self._create_bare_context_call('add_message', [BinOp(left=Str(message_format), op=Mod(), right=Tuple(elts=values, ctx=Load())), Num(existing_node.lineno)])
def _generate_assignment((arg_name, arg_resource_handle)): # type: (Tuple[basestring, int]) -> If """ We have a function that looks like: def do_something(param, model_=INJECTED): <...> We insert into its beginning a statement like ___INJECT_CONTEXT_INTERNAL_RESOURCES = ___INJECT_CONTEXT_INTERNAL.resources if model_ is INJECTED: model_ = ___INJECT_CONTEXT_INTERNAL_RESOURCES[3] if model is ___INJECT_CONTEXT_INTERNAL: # means that no resource is available ___INJECT_CONTEXT_INTERNAL_RESOURCES.flag_missing('model_') Code outside of this function sets a global variable _INJECTED__model to point at the right thing. """ target_attribute = Subscript( value=Name(id=INTERNAL_RESOURCES_NAME, ctx=Load()), slice=Index(value=Num(n=arg_resource_handle)), ctx=Load()) consequence = [ Assign(targets=[Name(id=arg_name, ctx=Store())], value=target_attribute), If(test=Compare( left=Name(id=arg_name, ctx=Load()), ops=[Is()], comparators=[Name(id=INTERNAL_CONTEXT_NAME, ctx=Load())]), body=[ Expr(value=Call(func=Attribute(value=Name( id=INTERNAL_CONTEXT_NAME, ctx=Load()), attr='flag_missing', ctx=Load()), keywords=[], starargs=None, kwargs=None, args=[Str(s=arg_name)])) ], orelse=[]) ] # type: List[Union[Assign, If] return If(test=Compare( left=Name(id=arg_name, ctx=Load()), ops=[Is()], comparators=[default_nodes_mapping[arg_name]]), body=consequence, orelse=[])
def visit_Delete(self, node): existing_node = self.generic_visit(node) for target in existing_node.targets: attribute_names = self._get_attribute_names(target) if attribute_names: target_name = '.'.join(attribute_names[:-1]) else: target_value = getattr(target, 'value', None) attribute_names = self._get_attribute_names(target_value) if attribute_names: target_name = '.'.join(attribute_names) else: target_name = getattr(target_value, 'id', None) if target_name is not None: args = [Str(s=target_name), target.value, Num(n=target.lineno)] target.value = self._create_bare_context_call( 'record_delete', args) return existing_node
def compile_importnode(self, srcnode, parent): assign = Assign(targets=[Name(id=str(srcnode.alias), ctx=Store())], value=Call(func=Attribute(value=Name(id='__piglet_rt', ctx=Load()), attr='load', ctx=Load()), args=[Name(id='__piglet_template', ctx=Load()), Str(s=srcnode.href)], starargs=None, kwargs=None, keywords=[])) assign = self.annotate_runtime_errors(assign, srcnode) container = self.get_func(parent) if container.name == '__piglet_root__': self.module.body.insert(self.module.body.index(container), assign) else: container.body.append(assign)
def visit_Call(self, node): existing_node = self.generic_visit(node) func_node = existing_node.func if self._is_untraceable_attribute(func_node): return existing_node if isinstance(func_node, Name) and func_node.id == 'print': return self._trace_print_function(existing_node) comparisons = [] # [(name, node)] names = self._get_attribute_names(func_node) if names is not None: comparisons.append( ('.'.join(names[:-1]), existing_node.func.value)) for arg_node in existing_node.args: if isinstance(arg_node, Name): comparisons.append((arg_node.id, arg_node)) if not comparisons: return existing_node args = [ List(elts=[], ctx=Load()), List(elts=[], ctx=Load()), existing_node, List(elts=[], ctx=Load()), Num(n=existing_node.lineno) ] for name, node in comparisons: args[0].elts.append(Str(s=name)) # name args[1].elts.append( # repr() before Call(func=Name(id='repr', ctx=Load()), args=[node], keywords=[], starargs=None, kwargs=None)) args[3].elts.append( # repr() after Call(func=Name(id='repr', ctx=Load()), args=[node], keywords=[], starargs=None, kwargs=None)) new_node = self._create_bare_context_call('record_call', args) return new_node
def compile_filternode(self, srcnode, parent): func = parse_and_strip(srcnode.function)[0].value with self.collect_output(parent) as ACC: for node in srcnode.children: self._compile(node, parent) joined = Call(func=Attribute(value=Str(s=''), attr='join', content=Load()), args=[LoadName(ACC)], starargs=None, kwargs=None, keywords=[]) parent.body.append(Expr(value=Yield( Call(func=func, args=[joined], starargs=None, kwargs=None, keywords=[]) )))
def visit_Assign(self, node): existing_node = self.generic_visit(node) try: targets = existing_node.targets except AttributeError: targets = [existing_node.target] if any(map(self._is_untraceable_attribute, targets)): return existing_node line_numbers = set() find_line_numbers(existing_node, line_numbers) first_line_number = min(line_numbers) last_line_number = max(line_numbers) new_nodes = [] format_string = self._wrap_assignment_targets( targets) if (len(targets) == 1 and isinstance(targets[0], Tuple)): existing_node.value = Call(func=Name(id='tuple', ctx=Load()), args=[existing_node.value], keywords=[], starargs=None, kwargs=None) existing_node.value = self._create_bare_context_call( 'set_assignment_value', [existing_node.value]) new_nodes.append(self._create_context_call('start_assignment')) try_body = [existing_node] if format_string is not None: try_body.append(self._create_context_call( 'report_assignment', [Str(s=format_string), Num(n=existing_node.lineno)])) end_assignment = self._create_context_call('end_assignment') finally_body = [end_assignment] new_nodes.append(TryFinally(body=try_body, finalbody=finally_body, handlers=[], orelse=[], lineno=first_line_number)) self._set_statement_line_numbers(try_body, first_line_number) self._set_statement_line_numbers(finally_body, last_line_number) return new_nodes
def visit_Assign(self, node): '''Interprets an assignament as a definition of a new nonterminal symbol. Only can be assigned rules, optionals, choices, nonterminals, terminals and repeated expressions. Valid: A = B, C meaning A := B follow by C A = [B, C] meaning A := B follow by C or the empty string A = {B | C} meaning A := B or C A = B meaning A := B (other nonterminal symbol) A = c meaning A := c (a terminal symbol)a A = B[...] meaning A := B one or more times It is not allowed multiples assignaments like A, B = C and in all the cases the name of the symbol (A in the case A=...) must be a valid name. ''' if len(node.targets) != 1 or not isinstance(node.targets[0], Name): raise NotationASTTransformer.ParserASTError( node, "Only one assign 'A = ...' is allowed and 'A' must be a " "variable with a valid name.") # We allow 'Dict' to handle better error messages. if not isinstance(node.value, (Tuple, List, Set, Name, Str, Subscript, Dict)): raise NotationASTTransformer.ParserASTError( node, "The value to assign is invalid. The 'rule', 'optional', " "'choices', 'repeated', a variable name and a literal string " "are allowes.") if isinstance(node.value, (Name, Str)): new_node = deepcopy(NotationASTTransformer.__parsed_tuple.body) new_node.elts[0] = node.value node.value = new_node node.value.production_name = Str(node.targets[0].id) node.value.production_name._already_process = True node.targets[0]._already_process = True self.generic_visit(node) return node
def _fix_module_ds(self, module): """ Starting in python 3.7 the AST for mule have changed, and if the first expressions encountered is a string it is attached to the `docstring` attribute of the `Module` ast node. This breaks IPython, as if this string is the only expression, IPython will not return it as the result of the current cell. """ from ast import Str, Expr, Module, fix_missing_locations docstring = getattr(module, 'docstring', None) if not docstring: return module new_body = [ Expr(Str(docstring, lineno=1, col_offset=0), lineno=1, col_offset=0) ] new_body.extend(module.body) return fix_missing_locations(Module(new_body))
def visit_AugAssign(self, node): read_target = deepcopy(node.target) existing_node = self.generic_visit(node) line_numbers = set() self._find_line_numbers(existing_node, line_numbers) first_line_number = min(line_numbers) last_line_number = max(line_numbers) new_nodes = [] try_body = [existing_node] new_nodes.append(self._create_context_call('start_assignment')) format_string = self._wrap_assignment_target(existing_node.target) if format_string is not None: if ':' in format_string: existing_node.value = self._create_bare_context_call( 'set_assignment_value', [existing_node.value]) operator_char = OPERATOR_CHARS.get(type(existing_node.op), '?') format_string += ' {}= {{}} '.format(operator_char) else: self._wrap_assignment_target(read_target, index_to_get=-1) read_target.ctx = Load() set_assignment_value = self._create_context_call( 'set_assignment_value', [read_target]) try_body.append(set_assignment_value) format_string += ' = {}' try_body.append( self._create_context_call( 'report_assignment', [Str(s=format_string), Num(n=existing_node.lineno)])) end_assignment = self._create_context_call('end_assignment') finally_body = [end_assignment] new_nodes.append( TryFinally(body=try_body, finalbody=finally_body, handlers=[], orelse=[], lineno=first_line_number)) self._set_statement_line_numbers(try_body, first_line_number) self._set_statement_line_numbers(finally_body, last_line_number) return new_nodes
def object_instance_from_res(object_name: str, object_id: str, cls_name: str) -> AnnAssign: try: is_valid_identifier(object_name) except Arcor2Exception as e: raise Arcor2Exception(f"Object name {object_name} invalid. {str(e)}") try: is_valid_type(cls_name) except Arcor2Exception as e: raise Arcor2Exception(f"Class name {cls_name} invalid. {str(e)}") return AnnAssign( target=Name(id=object_name, ctx=Store()), annotation=Name(id=cls_name, ctx=Load()), value=Subscript(value=get_name_attr("res", "objects"), slice=Index(value=Str(s=object_id, kind="")), ctx=Load()), simple=1, )
def handle_value(self, value): if isinstance(value.value, Enum): return Attribute( value=Name(id=value.value.__class__.__name__, **self.file), attr=value.value.name, **self.file, ) if isinstance(value.value, str): return Str(s=value.value, **self.file) if value.value is None: return Constant(value=None, **self.file) if isinstance(value.value, int): return Num(n=value.value, **self.file) if isinstance(value.value, bool): return Name(id=str(value.value), **self.file) raise ValueError("Unhandled Value")
def _do_wrap_class_register(tree, mod, base_class): if isinstance(tree, ClassDef): # Create the register call name = tree.name l_start = tree.lineno # Python 3.8: # l_end = tree.end_lineno # Python 3.7, this is good enough for our needs: l_end = l_start + 1 reg_name = name.lower() # BaseOutput.register member: attr = Attribute(value=Name(id=base_class, ctx=Load()), attr='register', ctx=Load()) # Function call to it passing reg_name and name # Put it in the last line. do_register = Expr(value=Call( func=attr, args=[Str(s=reg_name), Name(id=name, ctx=Load())], keywords=[]), lineno=l_end, col_offset=0, end_lineno=l_end, end_col_offset=50) # Create the import # Put it in the decorator line. do_import = ImportFrom(module=mod, names=[alias(name=base_class, asname=None)], level=1, lineno=l_start - 1, col_offset=0, end_lineno=l_start - 1, end_col_offset=50) return [do_import, tree, do_register] # Just in case somebody applies it to anything other than a class return tree # pragma: no cover