PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/rpython/flowspace/operation.py

https://bitbucket.org/pypy/pypy/
Python | 715 lines | 645 code | 51 blank | 19 comment | 53 complexity | 65c836ad43776dfde4004f9d91fe4399 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """
  2. This module defines all the SpaceOperations used in rpython.flowspace.
  3. """
  4. import __builtin__
  5. import __future__
  6. import operator
  7. import sys
  8. import types
  9. from rpython.tool.pairtype import pair, DoubleDispatchRegistry
  10. from rpython.rlib.unroll import unrolling_iterable, _unroller
  11. from rpython.tool.sourcetools import compile2
  12. from rpython.flowspace.model import (Constant, WrapException, const, Variable,
  13. SpaceOperation)
  14. from rpython.flowspace.specialcase import register_flow_sc
  15. from rpython.annotator.model import (
  16. SomeTuple, AnnotatorError, read_can_only_throw)
  17. from rpython.annotator.argument import ArgumentsForTranslation
  18. from rpython.flowspace.specialcase import SPECIAL_CASES
  19. NOT_REALLY_CONST = {
  20. Constant(sys): {
  21. Constant('maxint'): True,
  22. Constant('maxunicode'): True,
  23. Constant('api_version'): True,
  24. Constant('exit'): True,
  25. Constant('exc_info'): True,
  26. Constant('getrefcount'): True,
  27. Constant('getdefaultencoding'): True,
  28. # this is an incomplete list of true constants.
  29. # if we add much more, a dedicated class
  30. # might be considered for special objects.
  31. }
  32. }
  33. # built-ins that can always raise exceptions
  34. builtins_exceptions = {
  35. int: [ValueError],
  36. float: [ValueError],
  37. chr: [ValueError],
  38. unichr: [ValueError],
  39. unicode: [UnicodeDecodeError],
  40. }
  41. class _OpHolder(object):
  42. pass
  43. op = _OpHolder()
  44. func2op = {}
  45. class HLOperationMeta(type):
  46. def __init__(cls, name, bases, attrdict):
  47. type.__init__(cls, name, bases, attrdict)
  48. if hasattr(cls, 'opname'):
  49. setattr(op, cls.opname, cls)
  50. if cls.dispatch == 1:
  51. cls._registry = {}
  52. cls._transform = {}
  53. elif cls.dispatch == 2:
  54. cls._registry = DoubleDispatchRegistry()
  55. cls._transform = DoubleDispatchRegistry()
  56. class HLOperation(SpaceOperation):
  57. __metaclass__ = HLOperationMeta
  58. pure = False
  59. can_overflow = False
  60. dispatch = None # number of arguments to dispatch on
  61. # (None means special handling)
  62. def __init__(self, *args):
  63. self.args = list(args)
  64. self.result = Variable()
  65. self.offset = -1
  66. def replace(self, mapping):
  67. newargs = [arg.replace(mapping) for arg in self.args]
  68. newresult = self.result.replace(mapping)
  69. newop = type(self)(*newargs)
  70. newop.result = newresult
  71. newop.offset = self.offset
  72. return newop
  73. @classmethod
  74. def make_sc(cls):
  75. def sc_operator(ctx, *args_w):
  76. return cls(*args_w).eval(ctx)
  77. return sc_operator
  78. def eval(self, ctx):
  79. result = self.constfold()
  80. if result is not None:
  81. return result
  82. return ctx.do_op(self)
  83. def constfold(self):
  84. return None
  85. def consider(self, annotator):
  86. args_s = [annotator.annotation(arg) for arg in self.args]
  87. spec = type(self).get_specialization(*args_s)
  88. return spec(annotator, *self.args)
  89. def get_can_only_throw(self, annotator):
  90. return None
  91. def get_transformer(self, *args_s):
  92. return lambda *args: None
  93. def transform(self, annotator):
  94. args_s = [annotator.annotation(arg) for arg in self.args]
  95. transformer = self.get_transformer(*args_s)
  96. return transformer(annotator, *self.args)
  97. class PureOperation(HLOperation):
  98. pure = True
  99. def constfold(self):
  100. args = []
  101. if all(w_arg.foldable() for w_arg in self.args):
  102. args = [w_arg.value for w_arg in self.args]
  103. # All arguments are constants: call the operator now
  104. try:
  105. result = self.pyfunc(*args)
  106. except Exception as e:
  107. from rpython.flowspace.flowcontext import FlowingError
  108. msg = "%s%r always raises %s: %s" % (
  109. self.opname, tuple(args), type(e), e)
  110. raise FlowingError(msg)
  111. else:
  112. # don't try to constant-fold operations giving a 'long'
  113. # result. The result is probably meant to be sent to
  114. # an intmask(), but the 'long' constant confuses the
  115. # annotator a lot.
  116. if self.can_overflow and type(result) is long:
  117. pass
  118. # don't constant-fold getslice on lists, either
  119. elif self.opname == 'getslice' and type(result) is list:
  120. pass
  121. # otherwise, fine
  122. else:
  123. try:
  124. return const(result)
  125. except WrapException:
  126. # type cannot sanely appear in flow graph,
  127. # store operation with variable result instead
  128. pass
  129. class OverflowingOperation(PureOperation):
  130. can_overflow = True
  131. def ovfchecked(self):
  132. ovf = self.ovf_variant(*self.args)
  133. ovf.offset = self.offset
  134. return ovf
  135. class SingleDispatchMixin(object):
  136. dispatch = 1
  137. @classmethod
  138. def register(cls, Some_cls):
  139. def decorator(func):
  140. cls._registry[Some_cls] = func
  141. return func
  142. return decorator
  143. @classmethod
  144. def _dispatch(cls, Some_cls):
  145. for c in Some_cls.__mro__:
  146. try:
  147. return cls._registry[c]
  148. except KeyError:
  149. pass
  150. raise AnnotatorError("Unknown operation")
  151. def get_can_only_throw(self, annotator):
  152. args_s = [annotator.annotation(v) for v in self.args]
  153. spec = type(self).get_specialization(*args_s)
  154. return read_can_only_throw(spec, args_s[0])
  155. @classmethod
  156. def get_specialization(cls, s_arg, *_ignored):
  157. try:
  158. impl = getattr(s_arg, cls.opname)
  159. def specialized(annotator, arg, *other_args):
  160. return impl(*[annotator.annotation(x) for x in other_args])
  161. try:
  162. specialized.can_only_throw = impl.can_only_throw
  163. except AttributeError:
  164. pass
  165. return specialized
  166. except AttributeError:
  167. return cls._dispatch(type(s_arg))
  168. @classmethod
  169. def register_transform(cls, Some_cls):
  170. def decorator(func):
  171. cls._transform[Some_cls] = func
  172. return func
  173. return decorator
  174. @classmethod
  175. def get_transformer(cls, s_arg, *_ignored):
  176. for c in type(s_arg).__mro__:
  177. try:
  178. return cls._transform[c]
  179. except KeyError:
  180. pass
  181. return lambda *args: None
  182. class DoubleDispatchMixin(object):
  183. dispatch = 2
  184. @classmethod
  185. def register(cls, Some1, Some2):
  186. def decorator(func):
  187. cls._registry[Some1, Some2] = func
  188. return func
  189. return decorator
  190. @classmethod
  191. def get_specialization(cls, s_arg1, s_arg2, *_ignored):
  192. try:
  193. impl = getattr(pair(s_arg1, s_arg2), cls.opname)
  194. def specialized(annotator, arg1, arg2, *other_args):
  195. return impl(*[annotator.annotation(x) for x in other_args])
  196. try:
  197. specialized.can_only_throw = impl.can_only_throw
  198. except AttributeError:
  199. pass
  200. return specialized
  201. except AttributeError:
  202. return cls._registry[type(s_arg1), type(s_arg2)]
  203. def get_can_only_throw(self, annotator):
  204. args_s = [annotator.annotation(v) for v in self.args]
  205. spec = type(self).get_specialization(*args_s)
  206. return read_can_only_throw(spec, args_s[0], args_s[1])
  207. @classmethod
  208. def register_transform(cls, Some1, Some2):
  209. def decorator(func):
  210. cls._transform[Some1, Some2] = func
  211. return func
  212. return decorator
  213. @classmethod
  214. def get_transformer(cls, s_arg1, s_arg2, *_ignored):
  215. try:
  216. return cls._transform[type(s_arg1), type(s_arg2)]
  217. except KeyError:
  218. return lambda *args: None
  219. def add_operator(name, arity, dispatch=None, pyfunc=None, pure=False, ovf=False):
  220. operator_func = getattr(operator, name, None)
  221. if dispatch == 1:
  222. bases = [SingleDispatchMixin]
  223. elif dispatch == 2:
  224. bases = [DoubleDispatchMixin]
  225. else:
  226. bases = []
  227. if ovf:
  228. assert pure
  229. base_cls = OverflowingOperation
  230. elif pure:
  231. base_cls = PureOperation
  232. else:
  233. base_cls = HLOperation
  234. bases.append(base_cls)
  235. cls = HLOperationMeta(name, tuple(bases), {'opname': name, 'arity': arity,
  236. 'canraise': [],
  237. 'dispatch': dispatch})
  238. if pyfunc is not None:
  239. func2op[pyfunc] = cls
  240. if operator_func:
  241. func2op[operator_func] = cls
  242. if pyfunc is not None:
  243. cls.pyfunc = staticmethod(pyfunc)
  244. elif operator_func is not None:
  245. cls.pyfunc = staticmethod(operator_func)
  246. if ovf:
  247. from rpython.rlib.rarithmetic import ovfcheck
  248. ovf_func = lambda *args: ovfcheck(cls.pyfunc(*args))
  249. add_operator(name + '_ovf', arity, dispatch, pyfunc=ovf_func)
  250. cls.ovf_variant = getattr(op, name + '_ovf')
  251. # ____________________________________________________________
  252. def new_style_type(x):
  253. """Simulate a situation where every class is new-style"""
  254. return getattr(x, '__class__', type(x))
  255. def do_int(x):
  256. return x.__int__()
  257. def do_index(x):
  258. return x.__index__()
  259. def do_float(x):
  260. return x.__float__()
  261. def do_long(x):
  262. return x.__long__()
  263. def inplace_add(x, y):
  264. x += y
  265. return x
  266. def inplace_sub(x, y):
  267. x -= y
  268. return x
  269. def inplace_mul(x, y):
  270. x *= y
  271. return x
  272. exec compile2("""
  273. def inplace_truediv(x, y):
  274. x /= y
  275. return x
  276. """, flags=__future__.CO_FUTURE_DIVISION, dont_inherit=1)
  277. # makes an INPLACE_TRUE_DIVIDE
  278. def inplace_floordiv(x, y):
  279. x //= y
  280. return x
  281. exec compile2("""
  282. def inplace_div(x, y):
  283. x /= y
  284. return x
  285. """, flags=0, dont_inherit=1) # makes an INPLACE_DIVIDE
  286. def inplace_mod(x, y):
  287. x %= y
  288. return x
  289. def inplace_pow(x, y):
  290. x **= y
  291. return x
  292. def inplace_lshift(x, y):
  293. x <<= y
  294. return x
  295. def inplace_rshift(x, y):
  296. x >>= y
  297. return x
  298. def inplace_and(x, y):
  299. x &= y
  300. return x
  301. def inplace_or(x, y):
  302. x |= y
  303. return x
  304. def inplace_xor(x, y):
  305. x ^= y
  306. return x
  307. def next(x):
  308. return x.next()
  309. def get(x, y, z=None):
  310. return x.__get__(y, z)
  311. def set(x, y, z):
  312. x.__set__(y, z)
  313. def delete(x, y):
  314. x.__delete__(y)
  315. def userdel(x):
  316. x.__del__()
  317. # slicing: operator.{get,set,del}slice() don't support b=None or c=None
  318. def do_getslice(a, b, c):
  319. return a[b:c]
  320. def do_setslice(a, b, c, d):
  321. a[b:c] = d
  322. def do_delslice(a, b, c):
  323. del a[b:c]
  324. def unsupported(*args):
  325. raise ValueError("this is not supported")
  326. add_operator('is_', 2, dispatch=2, pure=True)
  327. add_operator('id', 1, dispatch=1, pyfunc=id)
  328. add_operator('type', 1, dispatch=1, pyfunc=new_style_type, pure=True)
  329. add_operator('issubtype', 2, dispatch=1, pyfunc=issubclass, pure=True) # not for old-style classes
  330. add_operator('isinstance', 2, dispatch=1, pyfunc=isinstance, pure=True)
  331. add_operator('repr', 1, dispatch=1, pyfunc=repr, pure=True)
  332. add_operator('str', 1, dispatch=1, pyfunc=str, pure=True)
  333. add_operator('format', 2, pyfunc=unsupported)
  334. add_operator('len', 1, dispatch=1, pyfunc=len, pure=True)
  335. add_operator('hash', 1, dispatch=1, pyfunc=hash)
  336. add_operator('setattr', 3, dispatch=1, pyfunc=setattr)
  337. add_operator('delattr', 2, dispatch=1, pyfunc=delattr)
  338. add_operator('getitem', 2, dispatch=2, pure=True)
  339. add_operator('getitem_idx', 2, dispatch=2, pure=True)
  340. add_operator('setitem', 3, dispatch=2)
  341. add_operator('delitem', 2, dispatch=2)
  342. add_operator('getslice', 3, dispatch=1, pyfunc=do_getslice, pure=True)
  343. add_operator('setslice', 4, dispatch=1, pyfunc=do_setslice)
  344. add_operator('delslice', 3, dispatch=1, pyfunc=do_delslice)
  345. add_operator('trunc', 1, pyfunc=unsupported)
  346. add_operator('pos', 1, dispatch=1, pure=True)
  347. add_operator('neg', 1, dispatch=1, pure=True, ovf=True)
  348. add_operator('bool', 1, dispatch=1, pyfunc=bool, pure=True)
  349. op.is_true = op.nonzero = op.bool # for llinterp
  350. add_operator('abs', 1, dispatch=1, pyfunc=abs, pure=True, ovf=True)
  351. add_operator('hex', 1, dispatch=1, pyfunc=hex, pure=True)
  352. add_operator('oct', 1, dispatch=1, pyfunc=oct, pure=True)
  353. add_operator('ord', 1, dispatch=1, pyfunc=ord, pure=True)
  354. add_operator('invert', 1, dispatch=1, pure=True)
  355. add_operator('add', 2, dispatch=2, pure=True, ovf=True)
  356. add_operator('sub', 2, dispatch=2, pure=True, ovf=True)
  357. add_operator('mul', 2, dispatch=2, pure=True, ovf=True)
  358. add_operator('truediv', 2, dispatch=2, pure=True)
  359. add_operator('floordiv', 2, dispatch=2, pure=True, ovf=True)
  360. add_operator('div', 2, dispatch=2, pure=True, ovf=True)
  361. add_operator('mod', 2, dispatch=2, pure=True, ovf=True)
  362. add_operator('divmod', 2, pyfunc=divmod, pure=True)
  363. add_operator('lshift', 2, dispatch=2, pure=True, ovf=True)
  364. add_operator('rshift', 2, dispatch=2, pure=True)
  365. add_operator('and_', 2, dispatch=2, pure=True)
  366. add_operator('or_', 2, dispatch=2, pure=True)
  367. add_operator('xor', 2, dispatch=2, pure=True)
  368. add_operator('int', 1, dispatch=1, pyfunc=do_int, pure=True)
  369. add_operator('index', 1, pyfunc=do_index, pure=True)
  370. add_operator('float', 1, dispatch=1, pyfunc=do_float, pure=True)
  371. add_operator('long', 1, dispatch=1, pyfunc=do_long, pure=True)
  372. add_operator('inplace_add', 2, dispatch=2, pyfunc=inplace_add)
  373. add_operator('inplace_sub', 2, dispatch=2, pyfunc=inplace_sub)
  374. add_operator('inplace_mul', 2, dispatch=2, pyfunc=inplace_mul)
  375. add_operator('inplace_truediv', 2, dispatch=2, pyfunc=inplace_truediv)
  376. add_operator('inplace_floordiv', 2, dispatch=2, pyfunc=inplace_floordiv)
  377. add_operator('inplace_div', 2, dispatch=2, pyfunc=inplace_div)
  378. add_operator('inplace_mod', 2, dispatch=2, pyfunc=inplace_mod)
  379. add_operator('inplace_pow', 2, pyfunc=inplace_pow)
  380. add_operator('inplace_lshift', 2, dispatch=2, pyfunc=inplace_lshift)
  381. add_operator('inplace_rshift', 2, dispatch=2, pyfunc=inplace_rshift)
  382. add_operator('inplace_and', 2, dispatch=2, pyfunc=inplace_and)
  383. add_operator('inplace_or', 2, dispatch=2, pyfunc=inplace_or)
  384. add_operator('inplace_xor', 2, dispatch=2, pyfunc=inplace_xor)
  385. add_operator('lt', 2, dispatch=2, pure=True)
  386. add_operator('le', 2, dispatch=2, pure=True)
  387. add_operator('eq', 2, dispatch=2, pure=True)
  388. add_operator('ne', 2, dispatch=2, pure=True)
  389. add_operator('gt', 2, dispatch=2, pure=True)
  390. add_operator('ge', 2, dispatch=2, pure=True)
  391. add_operator('cmp', 2, dispatch=2, pyfunc=cmp, pure=True) # rich cmps preferred
  392. add_operator('coerce', 2, dispatch=2, pyfunc=coerce, pure=True)
  393. add_operator('contains', 2, pure=True)
  394. add_operator('get', 3, pyfunc=get, pure=True)
  395. add_operator('set', 3, pyfunc=set)
  396. add_operator('delete', 2, pyfunc=delete)
  397. add_operator('userdel', 1, pyfunc=userdel)
  398. add_operator('buffer', 1, pyfunc=buffer, pure=True) # see buffer.py
  399. add_operator('yield_', 1)
  400. add_operator('newslice', 3)
  401. add_operator('hint', None, dispatch=1)
  402. class Contains(SingleDispatchMixin, PureOperation):
  403. opname = 'contains'
  404. arity = 2
  405. pyfunc = staticmethod(operator.contains)
  406. # XXX "contains" clashes with SomeObject method
  407. @classmethod
  408. def get_specialization(cls, s_seq, s_elem):
  409. return cls._dispatch(type(s_seq))
  410. class NewDict(HLOperation):
  411. opname = 'newdict'
  412. canraise = []
  413. def consider(self, annotator):
  414. return annotator.bookkeeper.newdict()
  415. class NewTuple(PureOperation):
  416. opname = 'newtuple'
  417. pyfunc = staticmethod(lambda *args: args)
  418. canraise = []
  419. def consider(self, annotator):
  420. return SomeTuple(items=[annotator.annotation(arg) for arg in self.args])
  421. class NewList(HLOperation):
  422. opname = 'newlist'
  423. canraise = []
  424. def consider(self, annotator):
  425. return annotator.bookkeeper.newlist(
  426. *[annotator.annotation(arg) for arg in self.args])
  427. class NewSlice(HLOperation):
  428. opname = 'newslice'
  429. canraise = []
  430. def consider(self, annotator):
  431. raise AnnotatorError("Cannot use extended slicing in rpython")
  432. class Pow(PureOperation):
  433. opname = 'pow'
  434. arity = 3
  435. can_overflow = False
  436. canraise = []
  437. pyfunc = pow
  438. def __init__(self, w_base, w_exponent, w_mod=const(None)):
  439. self.args = [w_base, w_exponent, w_mod]
  440. self.result = Variable()
  441. self.offset = -1
  442. class Iter(SingleDispatchMixin, HLOperation):
  443. opname = 'iter'
  444. arity = 1
  445. can_overflow = False
  446. canraise = []
  447. pyfunc = staticmethod(iter)
  448. def constfold(self):
  449. w_iterable, = self.args
  450. if isinstance(w_iterable, Constant):
  451. iterable = w_iterable.value
  452. if isinstance(iterable, unrolling_iterable):
  453. return const(iterable.get_unroller())
  454. class Next(SingleDispatchMixin, HLOperation):
  455. opname = 'next'
  456. arity = 1
  457. can_overflow = False
  458. canraise = [StopIteration, RuntimeError]
  459. pyfunc = staticmethod(next)
  460. def eval(self, ctx):
  461. w_iter, = self.args
  462. if isinstance(w_iter, Constant):
  463. it = w_iter.value
  464. if isinstance(it, _unroller):
  465. try:
  466. v, next_unroller = it.step()
  467. except IndexError:
  468. from rpython.flowspace.flowcontext import Raise
  469. raise Raise(const(StopIteration()))
  470. else:
  471. ctx.replace_in_stack(it, next_unroller)
  472. return const(v)
  473. return HLOperation.eval(self, ctx)
  474. class GetAttr(SingleDispatchMixin, HLOperation):
  475. opname = 'getattr'
  476. arity = 2
  477. can_overflow = False
  478. canraise = []
  479. pyfunc = staticmethod(getattr)
  480. def constfold(self):
  481. from rpython.flowspace.flowcontext import FlowingError
  482. if len(self.args) == 3:
  483. raise FlowingError(
  484. "getattr() with three arguments not supported: %s" % (self,))
  485. w_obj, w_name = self.args
  486. # handling special things like sys
  487. if (w_obj in NOT_REALLY_CONST and
  488. w_name not in NOT_REALLY_CONST[w_obj]):
  489. return
  490. if w_obj.foldable() and w_name.foldable():
  491. obj, name = w_obj.value, w_name.value
  492. try:
  493. result = getattr(obj, name)
  494. except Exception as e:
  495. etype = e.__class__
  496. msg = "getattr(%s, %s) always raises %s: %s" % (
  497. obj, name, etype, e)
  498. raise FlowingError(msg)
  499. try:
  500. return const(result)
  501. except WrapException:
  502. pass
  503. class CallOp(HLOperation):
  504. @property
  505. def canraise(self):
  506. w_callable = self.args[0]
  507. if isinstance(w_callable, Constant):
  508. c = w_callable.value
  509. if (isinstance(c, (types.BuiltinFunctionType,
  510. types.BuiltinMethodType,
  511. types.ClassType,
  512. types.TypeType)) and
  513. c.__module__ in ['__builtin__', 'exceptions']):
  514. return builtins_exceptions.get(c, [])
  515. # *any* exception for non-builtins
  516. return [Exception]
  517. class SimpleCall(SingleDispatchMixin, CallOp):
  518. opname = 'simple_call'
  519. def eval(self, ctx):
  520. w_callable, args_w = self.args[0], self.args[1:]
  521. if isinstance(w_callable, Constant):
  522. fn = w_callable.value
  523. try:
  524. sc = SPECIAL_CASES[fn] # TypeError if 'fn' not hashable
  525. except (KeyError, TypeError):
  526. pass
  527. else:
  528. return sc(ctx, *args_w)
  529. return ctx.do_op(self)
  530. def build_args(self, args_s):
  531. return ArgumentsForTranslation(list(args_s))
  532. class CallArgs(SingleDispatchMixin, CallOp):
  533. opname = 'call_args'
  534. def eval(self, ctx):
  535. w_callable = self.args[0]
  536. if isinstance(w_callable, Constant):
  537. fn = w_callable.value
  538. try:
  539. sc = SPECIAL_CASES[fn] # TypeError if 'fn' not hashable
  540. except (KeyError, TypeError):
  541. pass
  542. else:
  543. from rpython.flowspace.flowcontext import FlowingError
  544. raise FlowingError(
  545. "should not call %r with keyword arguments" % (fn,))
  546. return ctx.do_op(self)
  547. def build_args(self, args_s):
  548. return ArgumentsForTranslation.fromshape(args_s[0].const,
  549. list(args_s[1:]))
  550. # Other functions that get directly translated to SpaceOperators
  551. func2op[type] = op.type
  552. func2op[operator.truth] = op.bool
  553. func2op[pow] = op.pow
  554. func2op[operator.pow] = op.pow
  555. func2op[__builtin__.iter] = op.iter
  556. func2op[getattr] = op.getattr
  557. func2op[__builtin__.next] = op.next
  558. for fn, oper in func2op.items():
  559. register_flow_sc(fn)(oper.make_sc())
  560. op_appendices = {
  561. OverflowError: 'ovf',
  562. IndexError: 'idx',
  563. KeyError: 'key',
  564. ZeroDivisionError: 'zer',
  565. ValueError: 'val',
  566. }
  567. # specifying IndexError, and KeyError beyond Exception,
  568. # allows the annotator to be more precise, see test_reraiseAnything/KeyError in
  569. # the annotator tests
  570. op.getitem.canraise = [IndexError, KeyError, Exception]
  571. op.getitem_idx.canraise = [IndexError, KeyError, Exception]
  572. op.setitem.canraise = [IndexError, KeyError, Exception]
  573. op.delitem.canraise = [IndexError, KeyError, Exception]
  574. op.contains.canraise = [Exception] # from an r_dict
  575. def _add_exceptions(names, exc):
  576. for name in names.split():
  577. oper = getattr(op, name)
  578. lis = oper.canraise
  579. if exc in lis:
  580. raise ValueError("your list is causing duplication!")
  581. lis.append(exc)
  582. assert exc in op_appendices
  583. def _add_except_ovf(names):
  584. # duplicate exceptions and add OverflowError
  585. for name in names.split():
  586. oper = getattr(op, name)
  587. oper_ovf = getattr(op, name + '_ovf')
  588. oper_ovf.canraise = list(oper.canraise)
  589. oper_ovf.canraise.append(OverflowError)
  590. _add_exceptions("""div mod divmod truediv floordiv pow
  591. inplace_div inplace_mod inplace_truediv
  592. inplace_floordiv inplace_pow""", ZeroDivisionError)
  593. _add_exceptions("""pow inplace_pow lshift inplace_lshift rshift
  594. inplace_rshift""", ValueError)
  595. _add_exceptions("""truediv divmod
  596. inplace_add inplace_sub inplace_mul inplace_truediv
  597. inplace_floordiv inplace_div inplace_mod inplace_pow
  598. inplace_lshift""", OverflowError) # without a _ovf version
  599. _add_except_ovf("""neg abs add sub mul
  600. floordiv div mod lshift""") # with a _ovf version
  601. _add_exceptions("""pow""",
  602. OverflowError) # for the float case
  603. del _add_exceptions, _add_except_ovf