diff options
author | Marion <marion.zepf@gmail.com> | 2013-08-28 08:41:07 (GMT) |
---|---|---|
committer | Marion <marion.zepf@gmail.com> | 2013-08-28 08:41:07 (GMT) |
commit | 676ce91131ca56de318a6459d2ec697e9d6b1f74 (patch) | |
tree | c2fb835748221b83f687ea7ce6568a37239874f6 | |
parent | 875d5c047747c2122865bbb60bc5b2edc0278feb (diff) |
better handling for TATypeErrors coming from the type system
-rw-r--r-- | TurtleArt/talogo.py | 7 | ||||
-rw-r--r-- | TurtleArt/taprimitive.py | 31 | ||||
-rw-r--r-- | TurtleArt/tatype.py | 43 |
3 files changed, 54 insertions, 27 deletions
diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py index 3553a93..1c95c3b 100644 --- a/TurtleArt/talogo.py +++ b/TurtleArt/talogo.py @@ -38,6 +38,7 @@ import traceback from tablock import (Block, media_blocks_dictionary) from taconstants import (TAB_LAYER, DEFAULT_SCALE) from tapalette import (block_names, value_blocks) +from tatype import TATypeError from tautils import (get_pixbuf_from_journal, data_from_file, text_media_type, round_int, debug_output, find_group, get_stack_name) @@ -535,6 +536,12 @@ class LogoCode: self.tw.showlabel('status', 'ValueError: ' + str(ve)) return False + except TATypeError as tte: + if not self.tw.running_turtleart: + traceback.print_exc() + raise logoerror("%s %s %s %s" % (self.cfun.name, + _("doesn't like"), str(tte.bad_value), + _("as input"))) else: return False except StopIteration: diff --git a/TurtleArt/taprimitive.py b/TurtleArt/taprimitive.py index 912a9ef..301e849 100644 --- a/TurtleArt/taprimitive.py +++ b/TurtleArt/taprimitive.py @@ -276,15 +276,17 @@ class Primitive(object): # arguments error = None + list_failed = False + filler = None for slot_list in slot_list_alternatives: list_failed = False new_slot_list = [] - fillers = list(arguments[:]) + filler_list = list(arguments[:]) for slot in slot_list: if isinstance(slot, ArgSlot): - f = fillers.pop(0) + filler = filler_list.pop(0) try: - value = slot.fill(f) + value = slot.fill(filler) except TATypeError as error: list_failed = True break @@ -956,10 +958,11 @@ class PrimitiveDisjunction(Primitive,Disjunction): if runtime_args and isinstance(runtime_args[0], LogoCode): runtime_args = runtime_args[1:] + error = None for prim in self: try: new_prim = prim.fill_slots(*runtime_args, **runtime_kwargs) - except TATypeError: + except TATypeError as error: # on failure, try the next one continue else: @@ -967,7 +970,8 @@ class PrimitiveDisjunction(Primitive,Disjunction): return new_prim() # if we get here, all disjuncts failed - raise TATypeError("all Primitives failed") # TODO better error message + if error is not None: + raise error class ArgListDisjunction(Disjunction): @@ -1003,18 +1007,21 @@ class ArgSlot(object): return (self, ) def fill(self, argument, convert_to_ast=False): - """ Fill this argument slot with the given argument """ + """ Try to fill this argument slot with the given argument. If there + is a type problem, raise a TATypeError. """ if isinstance(argument, ast.AST): convert_to_ast = True elif convert_to_ast: argument = value_to_ast(argument) + error = None for slot in self.get_alternatives(): # check if the argument can fill this slot (type-wise) if slot.wrapper is not None: arg_type = get_type(slot.wrapper)[0] else: + # TODO take call_arg into account? arg_type = get_type(argument)[0] converter = get_converter(arg_type, slot.type) if converter is None: @@ -1069,7 +1076,7 @@ class ArgSlot(object): try: converted_argument = convert(wrapped_argument, slot.type, converter=converter) - except TATypeError as ce: + except TATypeError as error: # on failure, try the next slot continue else: @@ -1077,11 +1084,11 @@ class ArgSlot(object): return converted_argument # if we haven't returned anything yet, then all alternatives failed - traceback.print_exc() - # TODO find appropriate logoerror message depending on type combination - raise TATypeError("type mismatch while filling arg slot") - - return argument + if error is not None: + raise error + else: + raise TATypeError(bad_value=argument, bad_type=arg_type, + req_type=self.type) class ArgSlotDisjunction(ArgSlot,Disjunction): diff --git a/TurtleArt/tatype.py b/TurtleArt/tatype.py index d4fec2b..6b0acd6 100644 --- a/TurtleArt/tatype.py +++ b/TurtleArt/tatype.py @@ -195,22 +195,34 @@ def get_call_ast(func_name, args=None, keywords=None): class TATypeError(BaseException): """ TypeError with the types from the hierarchy, not with Python types """ - def __init__(self, message, type1=None, type2=None): - """ message -- the error message (type1 and type2 are inserted - automatically iff message contains '%s' for them) """ + def __init__(self, bad_value, bad_type=None, req_type=None, message=''): + """ bad_value -- the mis-typed value that caused the error + bad_type -- the type of the bad_value + req_type -- the type that the value was expected to have + message -- short statement about the cause of the error. It is + not shown to the user, but may appear in debugging output. """ + self.bad_value = bad_value + self.bad_type = bad_type + self.req_type = req_type self.message = message - self.type1 = type1 - self.type2 = type2 def __str__(self): - num = self.message.count('%s') - if num == 2: - msg = self.message % (self.type1, self.type2) - elif num == 1: - msg = self.message % (self.type1) - else: - msg = self.message - return "TA TypeError: " + msg + msg = [] + if self.message: + msg.append(self.message) + msg.append(" (") + msg.append("bad value: ") + msg.append(repr(self.bad_value)) + if self.bad_type is not None: + msg.append(", bad type: ") + msg.append(repr(self.bad_type)) + if self.req_type is not None: + msg.append(", req type: ") + msg.append(repr(self.req_type)) + if self.message: + msg.append(")") + return "".join(msg) + __repr__ = __str__ def get_converter(old_type, new_type): @@ -285,8 +297,9 @@ def convert(x, new_type, old_type=None, converter=None): converter = get_converter(old_type, new_type) if converter is None: # no converter available - raise TATypeError("type %s cannot be converted to type %s" - % (repr(old_type), repr(new_type))) + raise TATypeError(bad_value=x, bad_type=old_type, + req_type=new_type, message=("found no converter" + " for this type combination")) def _apply_converter(converter, y): if is_an_ast: |