PageRenderTime 56ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/interpreter/error.py

https://bitbucket.org/dac_io/pypy
Python | 469 lines | 440 code | 13 blank | 16 comment | 17 complexity | dda8ed2747874a74076a2a4767ece226 MD5 | raw file
  1. import os, sys
  2. from pypy.rlib import jit
  3. from pypy.rlib.objectmodel import we_are_translated
  4. from errno import EINTR
  5. AUTO_DEBUG = os.getenv('PYPY_DEBUG')
  6. RECORD_INTERPLEVEL_TRACEBACK = True
  7. class OperationError(Exception):
  8. """Interpreter-level exception that signals an exception that should be
  9. sent to the application level.
  10. OperationError instances have three attributes (and no .args),
  11. w_type, _w_value and _application_traceback, which contain the wrapped
  12. type and value describing the exception, and a chained list of
  13. PyTraceback objects making the application-level traceback.
  14. """
  15. _w_value = None
  16. _application_traceback = None
  17. def __init__(self, w_type, w_value, tb=None):
  18. if not we_are_translated() and w_type is None:
  19. from pypy.tool.error import FlowingError
  20. raise FlowingError(w_value)
  21. self.setup(w_type)
  22. self._w_value = w_value
  23. self._application_traceback = tb
  24. def setup(self, w_type):
  25. self.w_type = w_type
  26. if not we_are_translated():
  27. self.debug_excs = []
  28. def clear(self, space):
  29. # for sys.exc_clear()
  30. self.w_type = space.w_None
  31. self._w_value = space.w_None
  32. self._application_traceback = None
  33. if not we_are_translated():
  34. del self.debug_excs[:]
  35. def match(self, space, w_check_class):
  36. "Check if this application-level exception matches 'w_check_class'."
  37. return space.exception_match(self.w_type, w_check_class)
  38. def async(self, space):
  39. "Check if this is an exception that should better not be caught."
  40. if not space.full_exceptions:
  41. # flow objspace does not support such exceptions and more
  42. # importantly, raises KeyboardInterrupt if you try to access
  43. # space.w_KeyboardInterrupt
  44. return False
  45. return (self.match(space, space.w_SystemExit) or
  46. self.match(space, space.w_KeyboardInterrupt))
  47. def __str__(self):
  48. "NOT_RPYTHON: Convenience for tracebacks."
  49. s = self._w_value
  50. if self.__class__ is not OperationError and s is None:
  51. s = self._compute_value()
  52. return '[%s: %s]' % (self.w_type, s)
  53. def errorstr(self, space, use_repr=False):
  54. "The exception class and value, as a string."
  55. w_value = self.get_w_value(space)
  56. if space is None:
  57. # this part NOT_RPYTHON
  58. exc_typename = str(self.w_type)
  59. exc_value = str(w_value)
  60. else:
  61. w = space.wrap
  62. if space.is_w(space.type(self.w_type), space.w_str):
  63. exc_typename = space.str_w(self.w_type)
  64. else:
  65. exc_typename = space.str_w(
  66. space.getattr(self.w_type, w('__name__')))
  67. if space.is_w(w_value, space.w_None):
  68. exc_value = ""
  69. else:
  70. try:
  71. if use_repr:
  72. exc_value = space.str_w(space.repr(w_value))
  73. else:
  74. exc_value = space.str_w(space.str(w_value))
  75. except OperationError:
  76. # oups, cannot __str__ the exception object
  77. exc_value = "<oups, exception object itself cannot be str'd>"
  78. if not exc_value:
  79. return exc_typename
  80. else:
  81. return '%s: %s' % (exc_typename, exc_value)
  82. def record_interpreter_traceback(self):
  83. """Records the current traceback inside the interpreter.
  84. This traceback is only useful to debug the interpreter, not the
  85. application."""
  86. if not we_are_translated():
  87. if RECORD_INTERPLEVEL_TRACEBACK:
  88. self.debug_excs.append(sys.exc_info())
  89. def print_application_traceback(self, space, file=None):
  90. "NOT_RPYTHON: Dump a standard application-level traceback."
  91. if file is None: file = sys.stderr
  92. self.print_app_tb_only(file)
  93. print >> file, self.errorstr(space)
  94. def print_app_tb_only(self, file):
  95. "NOT_RPYTHON"
  96. tb = self._application_traceback
  97. if tb:
  98. import linecache
  99. print >> file, "Traceback (application-level):"
  100. while tb is not None:
  101. co = tb.frame.pycode
  102. lineno = tb.get_lineno()
  103. fname = co.co_filename
  104. if fname.startswith('<inline>\n'):
  105. lines = fname.split('\n')
  106. fname = lines[0].strip()
  107. try:
  108. l = lines[lineno]
  109. except IndexError:
  110. l = ''
  111. else:
  112. l = linecache.getline(fname, lineno)
  113. print >> file, " File \"%s\"," % fname,
  114. print >> file, "line", lineno, "in", co.co_name
  115. if l:
  116. if l.endswith('\n'):
  117. l = l[:-1]
  118. l = " " + l.lstrip()
  119. print >> file, l
  120. tb = tb.next
  121. def print_detailed_traceback(self, space=None, file=None):
  122. """NOT_RPYTHON: Dump a nice detailed interpreter- and
  123. application-level traceback, useful to debug the interpreter."""
  124. import traceback, cStringIO
  125. if file is None: file = sys.stderr
  126. f = cStringIO.StringIO()
  127. for i in range(len(self.debug_excs)-1, -1, -1):
  128. print >> f, "Traceback (interpreter-level):"
  129. traceback.print_tb(self.debug_excs[i][2], file=f)
  130. f.seek(0)
  131. debug_print(''.join(['|| ' + line for line in f.readlines()]), file)
  132. if self.debug_excs:
  133. from pypy.tool import tb_server
  134. tb_server.publish_exc(self.debug_excs[-1])
  135. self.print_app_tb_only(file)
  136. print >> file, '(application-level)', self.errorstr(space)
  137. if AUTO_DEBUG:
  138. import debug
  139. debug.fire(self)
  140. @jit.unroll_safe
  141. def normalize_exception(self, space):
  142. """Normalize the OperationError. In other words, fix w_type and/or
  143. w_value to make sure that the __class__ of w_value is exactly w_type.
  144. """
  145. #
  146. # This method covers all ways in which the Python statement
  147. # "raise X, Y" can produce a valid exception type and instance.
  148. #
  149. # In the following table, 'Class' means a subclass of BaseException
  150. # and 'inst' is an instance of either 'Class' or a subclass of it.
  151. # Or 'Class' can also be an old-style class and 'inst' an old-style
  152. # instance of it.
  153. #
  154. # Note that 'space.full_exceptions' is set to False by the flow
  155. # object space; in this case we must assume that we are in a
  156. # non-advanced case, and ignore the advanced cases. Old-style
  157. # classes and instances *are* advanced.
  158. #
  159. # input (w_type, w_value)... becomes... advanced case?
  160. # ---------------------------------------------------------------------
  161. # (tuple, w_value) (tuple[0], w_value) yes
  162. # (Class, None) (Class, Class()) no
  163. # (Class, inst) (inst.__class__, inst) no
  164. # (Class, tuple) (Class, Class(*tuple)) yes
  165. # (Class, x) (Class, Class(x)) no
  166. # ("string", ...) ("string", ...) deprecated
  167. # (inst, None) (inst.__class__, inst) no
  168. #
  169. w_type = self.w_type
  170. w_value = self.get_w_value(space)
  171. if space.full_exceptions:
  172. while space.is_true(space.isinstance(w_type, space.w_tuple)):
  173. w_type = space.getitem(w_type, space.wrap(0))
  174. if space.exception_is_valid_obj_as_class_w(w_type):
  175. # this is for all cases of the form (Class, something)
  176. if space.is_w(w_value, space.w_None):
  177. # raise Type: we assume we have to instantiate Type
  178. w_value = space.call_function(w_type)
  179. w_type = self._exception_getclass(space, w_value)
  180. else:
  181. w_valuetype = space.exception_getclass(w_value)
  182. if space.exception_issubclass_w(w_valuetype, w_type):
  183. # raise Type, Instance: let etype be the exact type of value
  184. w_type = w_valuetype
  185. else:
  186. if space.full_exceptions and space.is_true(
  187. space.isinstance(w_value, space.w_tuple)):
  188. # raise Type, tuple: assume the tuple contains the
  189. # constructor args
  190. w_value = space.call(w_type, w_value)
  191. else:
  192. # raise Type, X: assume X is the constructor argument
  193. w_value = space.call_function(w_type, w_value)
  194. w_type = self._exception_getclass(space, w_value)
  195. else:
  196. # the only case left here is (inst, None), from a 'raise inst'.
  197. w_inst = w_type
  198. w_instclass = self._exception_getclass(space, w_inst)
  199. if not space.is_w(w_value, space.w_None):
  200. raise OperationError(space.w_TypeError,
  201. space.wrap("instance exception may not "
  202. "have a separate value"))
  203. w_value = w_inst
  204. w_type = w_instclass
  205. self.w_type = w_type
  206. self._w_value = w_value
  207. def _exception_getclass(self, space, w_inst):
  208. w_type = space.exception_getclass(w_inst)
  209. if not space.exception_is_valid_class_w(w_type):
  210. typename = w_type.getname(space)
  211. msg = ("exceptions must be old-style classes or derived "
  212. "from BaseException, not %s")
  213. raise operationerrfmt(space.w_TypeError, msg, typename)
  214. return w_type
  215. def write_unraisable(self, space, where, w_object=None):
  216. if w_object is None:
  217. objrepr = ''
  218. else:
  219. try:
  220. objrepr = space.str_w(space.repr(w_object))
  221. except OperationError:
  222. objrepr = '?'
  223. msg = 'Exception %s in %s%s ignored\n' % (
  224. self.errorstr(space, use_repr=True), where, objrepr)
  225. try:
  226. space.call_method(space.sys.get('stderr'), 'write', space.wrap(msg))
  227. except OperationError:
  228. pass # ignored
  229. def get_w_value(self, space):
  230. w_value = self._w_value
  231. if w_value is None:
  232. value = self._compute_value()
  233. self._w_value = w_value = space.wrap(value)
  234. return w_value
  235. def _compute_value(self):
  236. raise NotImplementedError
  237. def get_traceback(self):
  238. """Calling this marks the PyTraceback as escaped, i.e. it becomes
  239. accessible and inspectable by app-level Python code. For the JIT.
  240. Note that this has no effect if there are already several traceback
  241. frames recorded, because in this case they are already marked as
  242. escaping by executioncontext.leave() being called with
  243. got_exception=True.
  244. """
  245. from pypy.interpreter.pytraceback import PyTraceback
  246. tb = self._application_traceback
  247. if tb is not None and isinstance(tb, PyTraceback):
  248. tb.frame.mark_as_escaped()
  249. return tb
  250. def set_traceback(self, traceback):
  251. """Set the current traceback. It should either be a traceback
  252. pointing to some already-escaped frame, or a traceback for the
  253. current frame. To support the latter case we do not mark the
  254. frame as escaped. The idea is that it will be marked as escaping
  255. only if the exception really propagates out of this frame, by
  256. executioncontext.leave() being called with got_exception=True.
  257. """
  258. self._application_traceback = traceback
  259. # ____________________________________________________________
  260. # optimization only: avoid the slowest operation -- the string
  261. # formatting with '%' -- in the common case were we don't
  262. # actually need the message. Only supports %s and %d.
  263. _fmtcache = {}
  264. _fmtcache2 = {}
  265. def decompose_valuefmt(valuefmt):
  266. """Returns a tuple of string parts extracted from valuefmt,
  267. and a tuple of format characters."""
  268. formats = []
  269. parts = valuefmt.split('%')
  270. i = 1
  271. while i < len(parts):
  272. if parts[i].startswith('s') or parts[i].startswith('d'):
  273. formats.append(parts[i][0])
  274. parts[i] = parts[i][1:]
  275. i += 1
  276. elif parts[i] == '': # support for '%%'
  277. parts[i-1] += '%' + parts[i+1]
  278. del parts[i:i+2]
  279. else:
  280. raise ValueError("invalid format string (only %s or %d supported)")
  281. assert len(formats) > 0, "unsupported: no % command found"
  282. return tuple(parts), tuple(formats)
  283. def get_operrcls2(valuefmt):
  284. strings, formats = decompose_valuefmt(valuefmt)
  285. assert len(strings) == len(formats) + 1
  286. try:
  287. OpErrFmt = _fmtcache2[formats]
  288. except KeyError:
  289. from pypy.rlib.unroll import unrolling_iterable
  290. attrs = ['x%d' % i for i in range(len(formats))]
  291. entries = unrolling_iterable(enumerate(attrs))
  292. #
  293. class OpErrFmt(OperationError):
  294. def __init__(self, w_type, strings, *args):
  295. self.setup(w_type)
  296. assert len(args) == len(strings) - 1
  297. self.xstrings = strings
  298. for i, attr in entries:
  299. setattr(self, attr, args[i])
  300. if not we_are_translated() and w_type is None:
  301. from pypy.tool.error import FlowingError
  302. raise FlowingError(self._compute_value())
  303. def _compute_value(self):
  304. lst = [None] * (len(formats) + len(formats) + 1)
  305. for i, attr in entries:
  306. string = self.xstrings[i]
  307. value = getattr(self, attr)
  308. lst[i+i] = string
  309. lst[i+i+1] = str(value)
  310. lst[-1] = self.xstrings[-1]
  311. return ''.join(lst)
  312. #
  313. _fmtcache2[formats] = OpErrFmt
  314. return OpErrFmt, strings
  315. def get_operationerr_class(valuefmt):
  316. try:
  317. result = _fmtcache[valuefmt]
  318. except KeyError:
  319. result = _fmtcache[valuefmt] = get_operrcls2(valuefmt)
  320. return result
  321. get_operationerr_class._annspecialcase_ = 'specialize:memo'
  322. def operationerrfmt(w_type, valuefmt, *args):
  323. """Equivalent to OperationError(w_type, space.wrap(valuefmt % args)).
  324. More efficient in the (common) case where the value is not actually
  325. needed."""
  326. OpErrFmt, strings = get_operationerr_class(valuefmt)
  327. return OpErrFmt(w_type, strings, *args)
  328. operationerrfmt._annspecialcase_ = 'specialize:arg(1)'
  329. # ____________________________________________________________
  330. # Utilities
  331. from pypy.tool.ansi_print import ansi_print
  332. def debug_print(text, file=None, newline=True):
  333. # 31: ANSI color code "red"
  334. ansi_print(text, esc="31", file=file, newline=newline)
  335. try:
  336. WindowsError
  337. except NameError:
  338. _WINDOWS = False
  339. else:
  340. _WINDOWS = True
  341. def wrap_windowserror(space, e, w_filename=None):
  342. from pypy.rlib import rwin32
  343. winerror = e.winerror
  344. try:
  345. msg = rwin32.FormatError(winerror)
  346. except ValueError:
  347. msg = 'Windows Error %d' % winerror
  348. exc = space.w_WindowsError
  349. if w_filename is not None:
  350. w_error = space.call_function(exc, space.wrap(winerror),
  351. space.wrap(msg), w_filename)
  352. else:
  353. w_error = space.call_function(exc, space.wrap(winerror),
  354. space.wrap(msg))
  355. return OperationError(exc, w_error)
  356. def wrap_oserror2(space, e, w_filename=None, exception_name='w_OSError',
  357. w_exception_class=None):
  358. assert isinstance(e, OSError)
  359. if _WINDOWS and isinstance(e, WindowsError):
  360. return wrap_windowserror(space, e, w_filename)
  361. errno = e.errno
  362. if errno == EINTR:
  363. space.getexecutioncontext().checksignals()
  364. try:
  365. msg = os.strerror(errno)
  366. except ValueError:
  367. msg = 'error %d' % errno
  368. if w_exception_class is None:
  369. exc = getattr(space, exception_name)
  370. else:
  371. exc = w_exception_class
  372. if w_filename is not None:
  373. w_error = space.call_function(exc, space.wrap(errno),
  374. space.wrap(msg), w_filename)
  375. else:
  376. w_error = space.call_function(exc, space.wrap(errno),
  377. space.wrap(msg))
  378. return OperationError(exc, w_error)
  379. wrap_oserror2._annspecialcase_ = 'specialize:arg(3)'
  380. def wrap_oserror(space, e, filename=None, exception_name='w_OSError',
  381. w_exception_class=None):
  382. if filename is not None:
  383. return wrap_oserror2(space, e, space.wrap(filename),
  384. exception_name=exception_name,
  385. w_exception_class=w_exception_class)
  386. else:
  387. return wrap_oserror2(space, e, None,
  388. exception_name=exception_name,
  389. w_exception_class=w_exception_class)
  390. wrap_oserror._annspecialcase_ = 'specialize:arg(3)'
  391. def exception_from_errno(space, w_type):
  392. from pypy.rlib.rposix import get_errno
  393. errno = get_errno()
  394. msg = os.strerror(errno)
  395. w_error = space.call_function(w_type, space.wrap(errno), space.wrap(msg))
  396. return OperationError(w_type, w_error)
  397. def new_exception_class(space, name, w_bases=None, w_dict=None):
  398. """Create a new exception type.
  399. @param name: the name of the type.
  400. @param w_bases: Either an exception type, or a wrapped tuple of
  401. exception types. default is space.w_Exception.
  402. @param w_dict: an optional dictionary to populate the class __dict__.
  403. """
  404. if '.' in name:
  405. module, name = name.rsplit('.', 1)
  406. else:
  407. module = None
  408. if w_bases is None:
  409. w_bases = space.newtuple([space.w_Exception])
  410. elif not space.isinstance_w(w_bases, space.w_tuple):
  411. w_bases = space.newtuple([w_bases])
  412. if w_dict is None:
  413. w_dict = space.newdict()
  414. w_exc = space.call_function(
  415. space.w_type, space.wrap(name), w_bases, w_dict)
  416. if module:
  417. space.setattr(w_exc, space.wrap("__module__"), space.wrap(module))
  418. return w_exc
  419. def typed_unwrap_error_msg(space, expected, w_obj):
  420. type_name = space.type(w_obj).getname(space)
  421. return space.wrap("expected %s, got %s object" % (expected, type_name))