def _attr_lookup(self, attr, value): if "__" not in attr: return Compare( left=Attribute(value=Name(id="self", **self.file), attr=attr, **self.file), ops=[Eq()], comparators=[self.build_expression(value)], **self.file, ) attr, lookup = attr.split("__", 1) if lookup == "isnull": return Compare( left=Attribute(value=Name(id="self", **self.file), attr=attr, **self.file), ops=[Is() if value else IsNot()], comparators=[ Constant(value=None, **self.file) # Name(id="None", **self.file) ], **self.file, ) if lookup == "exact": return self._attr_lookup(attr, value) raise ValueError("Unhandled attr lookup")
def condition(p): left = p[0] right = p[2] if p[1].gettokentype() == 'GRT': return Condition(left, Grt(left, right), right.getstr()) elif p[1].gettokentype() == 'LSS': return Condition(left, Lss(left, right), right.getstr()) elif p[1].gettokentype() == 'EQ': return Condition(left, Eq(left, right), right.getstr()) else: raise ValueError('Oops, isso não é possível.')
def empty_script_tree(project_id: str, add_main_loop: bool = True) -> Module: """Creates barebones of the script (empty 'main' function). Returns ------- """ main_body: List[stmt] = [ Assign( targets=[Name(id="aps", ctx=Store())], value=Call(func=Name(id="ActionPoints", ctx=Load()), args=[Name(id="res", ctx=Load())], keywords=[]), type_comment=None, ) ] if add_main_loop: main_body.append( While(test=NameConstant(value=True, kind=None), body=[Pass()], orelse=[])) else: """put there "pass" in order to make code valid even if there is no other statement (e.g. no object from resources)""" main_body.append(Pass()) # TODO helper function for try ... except tree = Module( body=[ FunctionDef( name="main", args=arguments( args=[ arg(arg="res", annotation=Name(id=RES_CLS, ctx=Load()), type_comment=None) ], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[], ), body=main_body, decorator_list=[], returns=NameConstant(value=None, kind=None), type_comment=None, ), If( test=Compare(left=Name(id="__name__", ctx=Load()), ops=[Eq()], comparators=[Str(s="__main__", kind="")]), body=[ Try( body=[ With( items=[ withitem( context_expr=Call( func=Name(id=RES_CLS, ctx=Load()), args=[Str(s=project_id, kind="")], keywords=[], ), optional_vars=Name(id="res", ctx=Store()), ) ], body=[ Expr(value=Call( func=Name(id="main", ctx=Load()), args=[Name(id="res", ctx=Load())], keywords=[], )) ], type_comment=None, ) ], handlers=[ ExceptHandler( type=Name(id=Exception.__name__, ctx=Load()), name="e", body=[ Expr(value=Call( func=Name(id=arcor2.exceptions.runtime. print_exception.__name__, ctx=Load()), args=[Name(id="e", ctx=Load())], keywords=[], )) ], ) ], orelse=[], finalbody=[], ) ], orelse=[], ), ], type_ignores=[], ) add_import(tree, arcor2.exceptions.runtime.__name__, arcor2.exceptions.runtime.print_exception.__name__) add_import(tree, RES_MODULE, RES_CLS, try_to_import=False) add_import(tree, "action_points", "ActionPoints", try_to_import=False) return tree
def _add_logic(container: Container, current_action: Action, super_container: Optional[Container] = None) -> None: # more paths could lead to the same action, so it might be already added # ...this is easier than searching the tree if current_action.id in added_actions: logger.debug( f"Action {current_action.name} already added, skipping.") return inputs, outputs = project.action_io(current_action.id) logger.debug( f"Adding action {current_action.name}, with {len(inputs)} input(s) and {len(outputs)} output(s)." ) act = current_action.parse_type() ac_obj = scene.object(act.obj_id).name args: List[AST] = [] # TODO make sure that the order of parameters is correct / re-order for param in current_action.parameters: if param.type == ActionParameter.TypeEnum.LINK: parsed_link = param.parse_link() parent_action = project.action(parsed_link.action_id) # TODO add support for tuples assert len(parent_action.flow(FlowTypes.DEFAULT).outputs ) == 1, "Only one result is supported atm." assert parsed_link.output_index == 0 res_name = parent_action.flow(FlowTypes.DEFAULT).outputs[0] # make sure that the result already exists if parent_action.id not in added_actions: raise SourceException( f"Action {current_action.name} attempts to use result {res_name} " f"of subsequent action {parent_action.name}.") args.append(Name(id=res_name, ctx=Load())) elif param.type == ActionParameter.TypeEnum.PROJECT_PARAMETER: args.append( Name(id=project.parameter(param.str_from_value()).name, ctx=Load())) else: plugin = plugin_from_type_name(param.type) args.append( plugin.parameter_ast(type_defs, scene, project, current_action.id, param.name)) list_of_imp_tup = plugin.need_to_be_imported( type_defs, scene, project, current_action.id, param.name) if list_of_imp_tup: # TODO what if there are two same names? for imp_tup in list_of_imp_tup: add_import(tree, imp_tup.module_name, imp_tup.class_name, try_to_import=False) add_method_call( container.body, ac_obj, act.action_type, args, [keyword(arg="an", value=Str(s=current_action.name, kind=""))], current_action.flow(FlowTypes.DEFAULT).outputs, ) added_actions.add(current_action.id) if not outputs: raise SourceException( f"Action {current_action.name} has no outputs.") elif len(outputs) == 1: output = outputs[0] if output.end == output.END: # TODO this is just temporary (while there is while loop), should be rather Return() container.body.append(Continue()) return seq_act = project.action(output.end) seq_act_inputs, _ = project.action_io(seq_act.id) if len(seq_act_inputs ) > 1: # the action belongs to a different block if seq_act.id in added_actions: return logger.debug( f"Action {seq_act.name} going to be added to super_container." ) # test if this is the correct super_container -> count distance (number of blocks) to the START blocks_to_start: Dict[str, int] = {} for inp in seq_act_inputs: parsed_start = inp.parse_start() pact = project.action(parsed_start.start_action_id) blocks_to_start[pact.id] = _blocks_to_start(pact) winner = min(blocks_to_start, key=blocks_to_start.get ) # type: ignore # TODO what is wrong with it? # TODO if blocks_to_start is cached somewhere, the second part of the condition is useless # it might happen that there are two different ways with the same distance if winner == current_action.id or all( value == list(blocks_to_start.values())[0] for value in blocks_to_start.values()): assert super_container is not None _add_logic(super_container, seq_act) return logger.debug(f"Sequential action: {seq_act.name}") _add_logic(container, seq_act, super_container) else: root_if: Optional[If] = None # action has more outputs - each output should have condition for idx, output in enumerate(outputs): if not output.condition: raise SourceException("Missing condition.") # TODO use parameter plugin (action metadata will be needed - to get the return types) # TODO support for other countable types # ...this will only work for booleans from arcor2 import json condition_value = json.loads(output.condition.value) comp = NameConstant(value=condition_value, kind=None) what = output.condition.parse_what() output_name = project.action(what.action_id).flow( what.flow_name).outputs[what.output_index] cond = If( test=Compare(left=Name(id=output_name, ctx=Load()), ops=[Eq()], comparators=[comp]), body=[], orelse=[], ) if idx == 0: root_if = cond container.body.append(root_if) logger.debug(f"Adding branch for: {condition_value}") else: assert isinstance(root_if, If) root_if.orelse.append(cond) if output.end == output.END: cond.body.append( Continue()) # TODO should be rather return continue _add_logic(cond, project.action(output.end), container)
""" if __name__ == "__main__": mod = Module(body=[ FunctionDef(name='F_6', args=arguments(args=[ arg(arg='x', annotation=Name(id='int', ctx=Load())), arg(arg='y', annotation=None) ], vararg=arg(arg='args', annotation=List(elts=[ Name(id='str', ctx=Load()) ], ctx=Load())), kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[ Return(value=Compare(left=Name(id='x', ctx=Load()), ops=[Eq()], comparators=[Num(n=6)])) ], decorator_list=[], returns=Name(id='bool', ctx=Load())) ]) expr_ast = parse(expr) print(expr_ast) print(f"{dump(expr_ast)}\n") print(unparse(mod))