PageRenderTime 52ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/interpreter/error.py

https://bitbucket.org/pypy/pypy/
Python | 512 lines | 480 code | 16 blank | 16 comment | 14 complexity | efd911ef85ac43af3c57a5cbdb1c1a7d MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import cStringIO
  2. import itertools
  3. import os
  4. import sys
  5. import traceback
  6. from errno import EINTR
  7. from rpython.rlib import jit
  8. from rpython.rlib.objectmodel import we_are_translated, specialize
  9. from pypy.interpreter import debug
  10. AUTO_DEBUG = os.getenv('PYPY_DEBUG')
  11. RECORD_INTERPLEVEL_TRACEBACK = True
  12. class OperationError(Exception):
  13. """Interpreter-level exception that signals an exception that should be
  14. sent to the application level.
  15. OperationError instances have three attributes (and no .args),
  16. w_type, _w_value and _application_traceback, which contain the wrapped
  17. type and value describing the exception, and a chained list of
  18. PyTraceback objects making the application-level traceback.
  19. """
  20. _w_value = None
  21. _application_traceback = None
  22. def __init__(self, w_type, w_value, tb=None):
  23. self.setup(w_type)
  24. self._w_value = w_value
  25. self._application_traceback = tb
  26. def setup(self, w_type):
  27. assert w_type is not None
  28. self.w_type = w_type
  29. if not we_are_translated():
  30. self.debug_excs = []
  31. def clear(self, space):
  32. # XXX remove this method. The point is that we cannot always
  33. # hack at 'self' to clear w_type and _w_value, because in some
  34. # corner cases the OperationError will be used again: see
  35. # test_interpreter.py:test_with_statement_and_sys_clear.
  36. pass
  37. def match(self, space, w_check_class):
  38. "Check if this application-level exception matches 'w_check_class'."
  39. return space.exception_match(self.w_type, w_check_class)
  40. def async(self, space):
  41. "Check if this is an exception that should better not be caught."
  42. return (self.match(space, space.w_SystemExit) or
  43. self.match(space, space.w_KeyboardInterrupt))
  44. def __str__(self):
  45. "NOT_RPYTHON: Convenience for tracebacks."
  46. s = self._w_value
  47. if self.__class__ is not OperationError and s is None:
  48. space = getattr(self.w_type, 'space')
  49. if space is not None:
  50. s = self._compute_value(space)
  51. return '[%s: %s]' % (self.w_type, s)
  52. def errorstr(self, space, use_repr=False):
  53. "The exception class and value, as a string."
  54. w_value = self.get_w_value(space)
  55. if space is None:
  56. # this part NOT_RPYTHON
  57. exc_typename = str(self.w_type)
  58. exc_value = str(w_value)
  59. else:
  60. w = space.wrap
  61. if space.is_w(space.type(self.w_type), space.w_str):
  62. exc_typename = space.str_w(self.w_type)
  63. else:
  64. exc_typename = space.str_w(
  65. space.getattr(self.w_type, w('__name__')))
  66. if space.is_w(w_value, space.w_None):
  67. exc_value = ""
  68. else:
  69. try:
  70. if use_repr:
  71. exc_value = space.str_w(space.repr(w_value))
  72. else:
  73. exc_value = space.str_w(space.str(w_value))
  74. except OperationError:
  75. # oups, cannot __str__ the exception object
  76. exc_value = "<oups, exception object itself cannot be str'd>"
  77. if not exc_value:
  78. return exc_typename
  79. else:
  80. return '%s: %s' % (exc_typename, exc_value)
  81. def record_interpreter_traceback(self):
  82. """Records the current traceback inside the interpreter.
  83. This traceback is only useful to debug the interpreter, not the
  84. application."""
  85. if not we_are_translated():
  86. if RECORD_INTERPLEVEL_TRACEBACK:
  87. self.debug_excs.append(sys.exc_info())
  88. def print_application_traceback(self, space, file=None):
  89. "NOT_RPYTHON: Dump a standard application-level traceback."
  90. if file is None:
  91. 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. if file is None:
  125. 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. debug.fire(self)
  139. @jit.unroll_safe
  140. def normalize_exception(self, space):
  141. """Normalize the OperationError. In other words, fix w_type and/or
  142. w_value to make sure that the __class__ of w_value is exactly w_type.
  143. """
  144. #
  145. # This method covers all ways in which the Python statement
  146. # "raise X, Y" can produce a valid exception type and instance.
  147. #
  148. # In the following table, 'Class' means a subclass of BaseException
  149. # and 'inst' is an instance of either 'Class' or a subclass of it.
  150. # Or 'Class' can also be an old-style class and 'inst' an old-style
  151. # instance of it.
  152. #
  153. # The flow object space only deals with non-advanced case. Old-style
  154. # classes and instances *are* advanced.
  155. #
  156. # input (w_type, w_value)... becomes... advanced case?
  157. # ---------------------------------------------------------------------
  158. # (tuple, w_value) (tuple[0], w_value) yes
  159. # (Class, None) (Class, Class()) no
  160. # (Class, inst) (inst.__class__, inst) no
  161. # (Class, tuple) (Class, Class(*tuple)) yes
  162. # (Class, x) (Class, Class(x)) no
  163. # ("string", ...) ("string", ...) deprecated
  164. # (inst, None) (inst.__class__, inst) no
  165. #
  166. w_type = self.w_type
  167. w_value = self.get_w_value(space)
  168. while space.isinstance_w(w_type, space.w_tuple):
  169. w_type = space.getitem(w_type, space.wrap(0))
  170. if space.exception_is_valid_obj_as_class_w(w_type):
  171. # this is for all cases of the form (Class, something)
  172. if space.is_w(w_value, space.w_None):
  173. # raise Type: we assume we have to instantiate Type
  174. w_value = space.call_function(w_type)
  175. w_type = self._exception_getclass(space, w_value)
  176. else:
  177. w_valuetype = space.exception_getclass(w_value)
  178. if space.exception_issubclass_w(w_valuetype, w_type):
  179. # raise Type, Instance: let etype be the exact type of value
  180. w_type = w_valuetype
  181. else:
  182. if space.isinstance_w(w_value, space.w_tuple):
  183. # raise Type, tuple: assume the tuple contains the
  184. # constructor args
  185. w_value = space.call(w_type, w_value)
  186. else:
  187. # raise Type, X: assume X is the constructor argument
  188. w_value = space.call_function(w_type, w_value)
  189. w_type = self._exception_getclass(space, w_value)
  190. else:
  191. # the only case left here is (inst, None), from a 'raise inst'.
  192. w_inst = w_type
  193. w_instclass = self._exception_getclass(space, w_inst)
  194. if not space.is_w(w_value, space.w_None):
  195. raise oefmt(space.w_TypeError,
  196. "instance exception may not have a separate value")
  197. w_value = w_inst
  198. w_type = w_instclass
  199. self.w_type = w_type
  200. self._w_value = w_value
  201. def _exception_getclass(self, space, w_inst):
  202. w_type = space.exception_getclass(w_inst)
  203. if not space.exception_is_valid_class_w(w_type):
  204. raise oefmt(space.w_TypeError,
  205. "exceptions must be old-style classes or derived from "
  206. "BaseException, not %N", w_type)
  207. return w_type
  208. def write_unraisable(self, space, where, w_object=None,
  209. with_traceback=False, extra_line=''):
  210. if w_object is None:
  211. objrepr = ''
  212. else:
  213. try:
  214. objrepr = space.str_w(space.repr(w_object))
  215. except OperationError:
  216. objrepr = '?'
  217. #
  218. try:
  219. if with_traceback:
  220. w_t = self.w_type
  221. w_v = self.get_w_value(space)
  222. w_tb = space.wrap(self.get_traceback())
  223. space.appexec([space.wrap(where),
  224. space.wrap(objrepr),
  225. space.wrap(extra_line),
  226. w_t, w_v, w_tb],
  227. """(where, objrepr, extra_line, t, v, tb):
  228. import sys, traceback
  229. if where or objrepr:
  230. sys.stderr.write('From %s%s:\\n' % (where, objrepr))
  231. if extra_line:
  232. sys.stderr.write(extra_line)
  233. traceback.print_exception(t, v, tb)
  234. """)
  235. else:
  236. msg = 'Exception %s in %s%s ignored\n' % (
  237. self.errorstr(space, use_repr=True), where, objrepr)
  238. space.call_method(space.sys.get('stderr'), 'write',
  239. space.wrap(msg))
  240. except OperationError:
  241. pass # ignored
  242. def get_w_value(self, space):
  243. w_value = self._w_value
  244. if w_value is None:
  245. value = self._compute_value(space)
  246. self._w_value = w_value = space.wrap(value)
  247. return w_value
  248. def _compute_value(self, space):
  249. raise NotImplementedError
  250. def get_traceback(self):
  251. """Calling this marks the PyTraceback as escaped, i.e. it becomes
  252. accessible and inspectable by app-level Python code. For the JIT.
  253. Note that this has no effect if there are already several traceback
  254. frames recorded, because in this case they are already marked as
  255. escaping by executioncontext.leave() being called with
  256. got_exception=True.
  257. """
  258. from pypy.interpreter.pytraceback import PyTraceback
  259. tb = self._application_traceback
  260. if tb is not None and isinstance(tb, PyTraceback):
  261. tb.frame.mark_as_escaped()
  262. return tb
  263. def set_traceback(self, traceback):
  264. """Set the current traceback."""
  265. self._application_traceback = traceback
  266. class ClearedOpErr:
  267. def __init__(self, space):
  268. self.operr = OperationError(space.w_None, space.w_None)
  269. def get_cleared_operation_error(space):
  270. return space.fromcache(ClearedOpErr).operr
  271. # ____________________________________________________________
  272. # optimization only: avoid the slowest operation -- the string
  273. # formatting with '%' -- in the common case were we don't
  274. # actually need the message. Only supports %s and %d.
  275. _fmtcache = {}
  276. _fmtcache2 = {}
  277. _FMTS = tuple('NRTds')
  278. def decompose_valuefmt(valuefmt):
  279. """Returns a tuple of string parts extracted from valuefmt,
  280. and a tuple of format characters."""
  281. formats = []
  282. parts = valuefmt.split('%')
  283. i = 1
  284. while i < len(parts):
  285. if parts[i].startswith(_FMTS):
  286. formats.append(parts[i][0])
  287. parts[i] = parts[i][1:]
  288. i += 1
  289. elif parts[i] == '': # support for '%%'
  290. parts[i-1] += '%' + parts[i+1]
  291. del parts[i:i+2]
  292. else:
  293. fmts = '%%%s or %%%s' % (', %'.join(_FMTS[:-1]), _FMTS[-1])
  294. raise ValueError("invalid format string (only %s supported)" %
  295. fmts)
  296. assert len(formats) > 0, "unsupported: no % command found"
  297. return tuple(parts), tuple(formats)
  298. def get_operrcls2(valuefmt):
  299. strings, formats = decompose_valuefmt(valuefmt)
  300. assert len(strings) == len(formats) + 1
  301. try:
  302. OpErrFmt = _fmtcache2[formats]
  303. except KeyError:
  304. from rpython.rlib.unroll import unrolling_iterable
  305. attrs = ['x%d' % i for i in range(len(formats))]
  306. entries = unrolling_iterable(zip(itertools.count(), formats, attrs))
  307. class OpErrFmt(OperationError):
  308. def __init__(self, w_type, strings, *args):
  309. self.setup(w_type)
  310. assert len(args) == len(strings) - 1
  311. self.xstrings = strings
  312. for i, _, attr in entries:
  313. setattr(self, attr, args[i])
  314. def _compute_value(self, space):
  315. lst = [None] * (len(formats) + len(formats) + 1)
  316. for i, fmt, attr in entries:
  317. lst[i + i] = self.xstrings[i]
  318. value = getattr(self, attr)
  319. if fmt == 'R':
  320. result = space.str_w(space.repr(value))
  321. elif fmt == 'T':
  322. result = space.type(value).name
  323. elif fmt == 'N':
  324. result = value.getname(space)
  325. else:
  326. result = str(value)
  327. lst[i + i + 1] = result
  328. lst[-1] = self.xstrings[-1]
  329. return ''.join(lst)
  330. #
  331. _fmtcache2[formats] = OpErrFmt
  332. return OpErrFmt, strings
  333. class OpErrFmtNoArgs(OperationError):
  334. def __init__(self, w_type, value):
  335. self._value = value
  336. self.setup(w_type)
  337. def get_w_value(self, space):
  338. w_value = self._w_value
  339. if w_value is None:
  340. self._w_value = w_value = space.wrap(self._value)
  341. return w_value
  342. @specialize.memo()
  343. def get_operr_class(valuefmt):
  344. try:
  345. result = _fmtcache[valuefmt]
  346. except KeyError:
  347. result = _fmtcache[valuefmt] = get_operrcls2(valuefmt)
  348. return result
  349. @specialize.arg(1)
  350. def oefmt(w_type, valuefmt, *args):
  351. """Equivalent to OperationError(w_type, space.wrap(valuefmt % args)).
  352. More efficient in the (common) case where the value is not actually
  353. needed.
  354. Supports the standard %s and %d formats, plus the following:
  355. %N - The result of w_arg.getname(space)
  356. %R - The result of space.str_w(space.repr(w_arg))
  357. %T - The result of space.type(w_arg).name
  358. """
  359. if not len(args):
  360. return OpErrFmtNoArgs(w_type, valuefmt)
  361. OpErrFmt, strings = get_operr_class(valuefmt)
  362. return OpErrFmt(w_type, strings, *args)
  363. # ____________________________________________________________
  364. # Utilities
  365. from rpython.tool.ansi_print import ansi_print
  366. def debug_print(text, file=None, newline=True):
  367. # 31: ANSI color code "red"
  368. ansi_print(text, esc="31", file=file, newline=newline)
  369. try:
  370. WindowsError
  371. except NameError:
  372. _WINDOWS = False
  373. else:
  374. _WINDOWS = True
  375. def wrap_windowserror(space, e, w_filename=None):
  376. from rpython.rlib import rwin32
  377. winerror = e.winerror
  378. try:
  379. msg = rwin32.FormatError(winerror)
  380. except ValueError:
  381. msg = 'Windows Error %d' % winerror
  382. exc = space.w_WindowsError
  383. if w_filename is not None:
  384. w_error = space.call_function(exc, space.wrap(winerror),
  385. space.wrap(msg), w_filename)
  386. else:
  387. w_error = space.call_function(exc, space.wrap(winerror),
  388. space.wrap(msg))
  389. return OperationError(exc, w_error)
  390. def wrap_oserror2(space, e, w_filename=None, exception_name='w_OSError',
  391. w_exception_class=None):
  392. assert isinstance(e, OSError)
  393. if _WINDOWS and isinstance(e, WindowsError):
  394. return wrap_windowserror(space, e, w_filename)
  395. errno = e.errno
  396. if errno == EINTR:
  397. space.getexecutioncontext().checksignals()
  398. try:
  399. msg = os.strerror(errno)
  400. except ValueError:
  401. msg = 'error %d' % errno
  402. if w_exception_class is None:
  403. exc = getattr(space, exception_name)
  404. else:
  405. exc = w_exception_class
  406. if w_filename is not None:
  407. w_error = space.call_function(exc, space.wrap(errno),
  408. space.wrap(msg), w_filename)
  409. else:
  410. w_error = space.call_function(exc, space.wrap(errno),
  411. space.wrap(msg))
  412. return OperationError(exc, w_error)
  413. wrap_oserror2._annspecialcase_ = 'specialize:arg(3)'
  414. def wrap_oserror(space, e, filename=None, exception_name='w_OSError',
  415. w_exception_class=None):
  416. if filename is not None:
  417. return wrap_oserror2(space, e, space.wrap(filename),
  418. exception_name=exception_name,
  419. w_exception_class=w_exception_class)
  420. else:
  421. return wrap_oserror2(space, e, None,
  422. exception_name=exception_name,
  423. w_exception_class=w_exception_class)
  424. wrap_oserror._annspecialcase_ = 'specialize:arg(3)'
  425. def exception_from_saved_errno(space, w_type):
  426. from rpython.rlib.rposix import get_saved_errno
  427. errno = get_saved_errno()
  428. msg = os.strerror(errno)
  429. w_error = space.call_function(w_type, space.wrap(errno), space.wrap(msg))
  430. return OperationError(w_type, w_error)
  431. def new_exception_class(space, name, w_bases=None, w_dict=None):
  432. """Create a new exception type.
  433. @param name: the name of the type.
  434. @param w_bases: Either an exception type, or a wrapped tuple of
  435. exception types. default is space.w_Exception.
  436. @param w_dict: an optional dictionary to populate the class __dict__.
  437. """
  438. if '.' in name:
  439. module, name = name.rsplit('.', 1)
  440. else:
  441. module = None
  442. if w_bases is None:
  443. w_bases = space.newtuple([space.w_Exception])
  444. elif not space.isinstance_w(w_bases, space.w_tuple):
  445. w_bases = space.newtuple([w_bases])
  446. if w_dict is None:
  447. w_dict = space.newdict()
  448. w_exc = space.call_function(
  449. space.w_type, space.wrap(name), w_bases, w_dict)
  450. if module:
  451. space.setattr(w_exc, space.wrap("__module__"), space.wrap(module))
  452. return w_exc