def fill(self, argument, convert_to_ast=False, call_my_args=True): """ Try to fill this argument slot with the given argument. Return a ConstantArg containing the result. If there is a type problem, raise a TATypeError. """ if isinstance(argument, ast.AST): convert_to_ast = True # 1. can the argument be called? (func_disjunction, args) = (None, []) if (isinstance(argument, tuple) and argument and callable(argument[0])): func_disjunction = argument[0] if len(argument) >= 2 and isinstance(argument[1], LogoCode): args = argument[2:] else: args = argument[1:] elif callable(argument): func_disjunction = argument # make sure we can loop over func_disjunction if not isinstance(func_disjunction, PrimitiveDisjunction): func_disjunction = PrimitiveDisjunction((func_disjunction, )) error = None bad_value = argument # the value that caused the TATypeError for func in func_disjunction: error = None for slot in self.get_alternatives(): if isinstance(slot.wrapper, PrimitiveDisjunction): wrapper_disjunction = slot.wrapper else: wrapper_disjunction = PrimitiveDisjunction((slot.wrapper,)) for wrapper in wrapper_disjunction: # check if the argument can fill this slot (type-wise) # (lambda functions are always accepted) if getattr(func, '__name__', None) == '<lambda>': converter = identity old_type = TYPE_OBJECT new_type = slot.type else: if wrapper is not None: arg_types = get_type(wrapper)[0] bad_value = wrapper elif func is not None: arg_types = get_type(func)[0] bad_value = func else: arg_types = get_type(argument)[0] bad_value = argument converter = None if not isinstance(arg_types, TypeDisjunction): arg_types = TypeDisjunction((arg_types, )) if isinstance(slot.type, TypeDisjunction): slot_types = slot.type else: slot_types = TypeDisjunction((slot.type, )) for old_type in arg_types: for new_type in slot_types: converter = get_converter(old_type, new_type) if converter is not None: break if converter is not None: break # unable to convert, try next wrapper/ slot/ func if converter is None: continue # 1. (cont'd) call the argument or pass it on as a callable called_argument = argument if func is not None: func_prim = func if not isinstance(func_prim, Primitive): func_prim = Primitive( func_prim, [ArgSlot(TYPE_OBJECT)] * len(args)) try: func_prim = func_prim.fill_slots( args, convert_to_ast=convert_to_ast, call_my_args=(slot.call_arg and call_my_args)) except TATypeError as error: if Primitive._DEBUG: traceback.print_exc() # on failure, try next wrapper/ slot/ func bad_value = error.bad_value continue if convert_to_ast: called_argument = func_prim.get_ast() else: if slot.call_arg and call_my_args: # call and pass on the return value called_argument = func_prim() else: # don't call and pass on the callable called_argument = func_prim # 2. apply any wrappers wrapped_argument = called_argument if wrapper is not None: if convert_to_ast: if not hasattr(wrapper, "get_ast"): raise PyExportError( ("cannot convert callable" " %s to an AST") % (repr(wrapper))) wrapped_argument = wrapper.get_ast( called_argument) else: if slot.call_arg and call_my_args: wrapped_argument = wrapper(called_argument) else: wrapped_argument = wrapper.fill_slots( [called_argument], call_my_args=False) # last chance to convert raw values to ASTs # (but not lists of ASTs) if (convert_to_ast and not isinstance(wrapped_argument, ast.AST) and not (isinstance(wrapped_argument, list) and wrapped_argument and isinstance(wrapped_argument[0], ast.AST))): wrapped_argument = value_to_ast(wrapped_argument) # 3. check the type and convert the argument if necessary converted_argument = wrapped_argument if slot.call_arg and call_my_args: try: converted_argument = convert( wrapped_argument, new_type, old_type=old_type, converter=converter) except TATypeError as error: if Primitive._DEBUG: traceback.print_exc() # on failure, try next wrapper/ slot/ func bad_value = wrapped_argument continue elif converter != identity: converted_argument = Primitive( converter, return_type=new_type, arg_descs=[ConstantArg(wrapped_argument, value_type=old_type, call_arg=False)]) # on success, return the result return ConstantArg( converted_argument, value_type=new_type, call_arg=(slot.call_arg and call_my_args)) # if we haven't returned anything yet, then all alternatives failed if error is not None: raise error else: raise TATypeError(bad_value=bad_value, bad_type=old_type, req_type=new_type)
def fill(self, argument, convert_to_ast=False, call_my_args=True): """ Try to fill this argument slot with the given argument. Return a ConstantArg containing the result. If there is a type problem, raise a TATypeError. """ if isinstance(argument, ast.AST): convert_to_ast = True # 1. can the argument be called? (func_disjunction, args) = (None, []) if (isinstance(argument, tuple) and argument and callable(argument[0])): func_disjunction = argument[0] if len(argument) >= 2 and isinstance(argument[1], LogoCode): args = argument[2:] else: args = argument[1:] elif callable(argument): func_disjunction = argument # make sure we can loop over func_disjunction if not isinstance(func_disjunction, PrimitiveDisjunction): func_disjunction = PrimitiveDisjunction((func_disjunction, )) error = None bad_value = argument # the value that caused the TATypeError for func in func_disjunction: error = None for slot in self.get_alternatives(): if isinstance(slot.wrapper, PrimitiveDisjunction): wrapper_disjunction = slot.wrapper else: wrapper_disjunction = PrimitiveDisjunction((slot.wrapper,)) for wrapper in wrapper_disjunction: # check if the argument can fill this slot (type-wise) # (lambda functions are always accepted) if getattr(func, '__name__', None) == '<lambda>': converter = identity old_type = TYPE_OBJECT new_type = slot.type else: if wrapper is not None: arg_types = get_type(wrapper)[0] bad_value = wrapper elif func is not None: arg_types = get_type(func)[0] bad_value = func else: arg_types = get_type(argument)[0] bad_value = argument converter = None if not isinstance(arg_types, TypeDisjunction): arg_types = TypeDisjunction((arg_types, )) if isinstance(slot.type, TypeDisjunction): slot_types = slot.type else: slot_types = TypeDisjunction((slot.type, )) for old_type in arg_types: for new_type in slot_types: converter = get_converter(old_type, new_type) if converter is not None: break if converter is not None: break # unable to convert, try next wrapper/ slot/ func if converter is None: continue # 1. (cont'd) call the argument or pass it on as a callable called_argument = argument if func is not None: func_prim = func if not isinstance(func_prim, Primitive): func_prim = Primitive( func_prim, [ArgSlot(TYPE_OBJECT)] * len(args)) try: func_prim = func_prim.fill_slots( args, convert_to_ast=convert_to_ast, call_my_args=(slot.call_arg and call_my_args)) except TATypeError as error: if Primitive._DEBUG: traceback.print_exc() # on failure, try next wrapper/ slot/ func bad_value = error.bad_value continue if convert_to_ast: called_argument = func_prim.get_ast() else: if slot.call_arg and call_my_args: # call and pass on the return value called_argument = func_prim() else: # don't call and pass on the callable called_argument = func_prim # 2. apply any wrappers wrapped_argument = called_argument if wrapper is not None: if convert_to_ast: if not hasattr(wrapper, "get_ast"): raise PyExportError( ("cannot convert callable" " %s to an AST") % (repr(wrapper))) wrapped_argument = wrapper.get_ast( called_argument) else: if slot.call_arg and call_my_args: wrapped_argument = wrapper(called_argument) else: wrapped_argument = wrapper.fill_slots( [called_argument], call_my_args=False) # last chance to convert raw values to ASTs # (but not lists of ASTs) if (convert_to_ast and not isinstance(wrapped_argument, ast.AST) and not (isinstance(wrapped_argument, list) and wrapped_argument and isinstance(wrapped_argument[0], ast.AST))): wrapped_argument = value_to_ast(wrapped_argument) # 3. check the type and convert the argument if necessary converted_argument = wrapped_argument if slot.call_arg and call_my_args: try: converted_argument = convert( wrapped_argument, new_type, old_type=old_type, converter=converter) except TATypeError as error: if Primitive._DEBUG: traceback.print_exc() # on failure, try next wrapper/ slot/ func bad_value = wrapped_argument continue elif converter != identity: converted_argument = Primitive( converter, return_type=new_type, arg_descs=[ConstantArg(wrapped_argument, value_type=old_type, call_arg=False)]) # on success, return the result return ConstantArg( converted_argument, value_type=new_type, call_arg=(slot.call_arg and call_my_args)) # if we haven't returned anything yet, then all alternatives failed if error is not None: raise error else: raise TATypeError(bad_value=bad_value, bad_type=old_type, req_type=new_type)