diff --git a/pyopencl/__init__.py b/pyopencl/__init__.py index 13efa4ec58b5b1ab65b2749450040bb47b7fa78d..d6bec005fee5376cae92507d651f75351b7bb0b9 100644 --- a/pyopencl/__init__.py +++ b/pyopencl/__init__.py @@ -222,6 +222,11 @@ class Program(object): try: return build_func() except _cl.RuntimeError as e: + from pytools import Record + + class ErrorRecord(Record): + pass + what = e.what if options: what = what + "\n(options: %s)" % " ".join(options) @@ -236,7 +241,14 @@ class Program(object): what = what + "\n(source saved as %s)" % srcfile.name - err = _cl.RuntimeError(msg=what, routine=e.routine, code=e.code) + code = e.code + routine = e.routine + + err = _cl.RuntimeError( + ErrorRecord( + what=lambda: what, + code=lambda: code, + routine=lambda: routine)) # Python 3.2 outputs the whole list of currently active exceptions # This serves to remove one (redundant) level from that nesting. @@ -421,11 +433,22 @@ def _add_functionality(): try: self._build(options=options, devices=devices) except Error as e: + from pytools import Record + + class ErrorRecord(Record): + pass + what = e.what + "\n\n" + (75*"="+"\n").join( "Build on %s:\n\n%s" % (dev, log) for dev, log in self._get_build_logs()) + code = e.code + routine = e.routine - err = _cl.RuntimeError(msg=what, routine=e.routine, code=e.code) + err = _cl.RuntimeError( + ErrorRecord( + what=lambda: what, + code=lambda: code, + routine=lambda: routine)) if err is not None: # Python 3.2 outputs the whole list of currently active exceptions @@ -710,37 +733,37 @@ def _add_functionality(): # }}} - # # {{{ Error - - # def error_str(self): - # val = self.args[0] - # try: - # val.routine - # except AttributeError: - # return str(val) - # else: - # result = "%s failed: %s" % (val.routine(), - # status_code.to_string(val.code(), "<unknown error %d>") - # .lower().replace("_", " ")) - # if val.what(): - # result += " - " + val.what() - # return result - - # def error_code(self): - # return self.args[0].code() - - # def error_routine(self): - # return self.args[0].routine() - - # def error_what(self): - # return self.args[0].what() - - # Error.__str__ = error_str - # Error.code = property(error_code) - # Error.routine = property(error_routine) - # Error.what = property(error_what) - - # # }}} + # {{{ Error + + def error_str(self): + val = self.args[0] + try: + val.routine + except AttributeError: + return str(val) + else: + result = "%s failed: %s" % (val.routine(), + status_code.to_string(val.code(), "<unknown error %d>") + .lower().replace("_", " ")) + if val.what(): + result += " - " + val.what() + return result + + def error_code(self): + return self.args[0].code() + + def error_routine(self): + return self.args[0].routine() + + def error_what(self): + return self.args[0].what() + + Error.__str__ = error_str + Error.code = property(error_code) + Error.routine = property(error_routine) + Error.what = property(error_what) + + # }}} # if _cl.have_gl(): # def gl_object_get_gl_object(self): diff --git a/pyopencl/cffi_cl.py b/pyopencl/cffi_cl.py index 0f5023256fff212b52e50bb7cfd94d669f59c121..9263287aafea301976ae8db0aec00196de9221a0 100644 --- a/pyopencl/cffi_cl.py +++ b/pyopencl/cffi_cl.py @@ -428,12 +428,24 @@ del _constant_callback # {{{ exceptions class Error(Exception): - def __init__(self, msg='', code=0, routine=''): - self.routine = routine - assert isinstance(code, int) - self.code = code - self.what = msg - super(Error, self).__init__(msg) + class __ErrorRecord(object): + __slots__ = ('_routine', '_code', '_what') + def __init__(self, msg='', code=0, routine=''): + self._routine = routine + assert isinstance(code, int) + self._code = code + self._what = msg + def routine(self): + return self._routine + def code(self): + return self._code + def what(self): + return self._what + def __init__(self, *a, **kw): + if len(a) == 1 and not kw and hasattr(a[0], 'what'): + super(Error, self).__init__(a[0]) + else: + super(Error, self).__init__(self.__ErrorRecord(*a, **kw)) class MemoryError(Error):