PKKNvXpytest_raisin/__init__.py"""Plugin enabling the use of exception instances with pytest.raises""" import logging import sys import pytest from pytest_raisin.compat import default_compare __version__ = "0.2" log = logging.getLogger(__name__) original = pytest.raises # Mapping of exception subclasses (keys) to callables (values). exception_comparers = {} def register_exception_compare(exception_class): """Plugin users may register their own errors/callables here by placing pytest-raisin's decorator factory above a function: @pytest.register_exception_compare(MyError) def my_error_compare(exc_actual, exc_expected): ... The arguments exc_actual and exc_expected should be instances of MyError. The function should raise an AssertionError with useful context message should they fail to match. It should return None if the exceptions should be considered equivalent. """ exception_classes = exception_class if not isinstance(exception_class, tuple): exception_classes = (exception_class,) for exception_class in exception_classes: if not isinstance(exception_class, type) or not issubclass(exception_class, BaseException): msg = "Can not register {!r}, it's not an Exception subclass" msg = msg.format(exception_class) raise TypeError(msg) def decorator(func): if not callable(func): raise TypeError('You are decorating a non callable: {!r}'.format(func)) for exception_class in exception_classes: if exception_class in exception_comparers: log.warning("%r was registered multiple times", exception_class) exception_comparers[exception_class] = func log.debug("Registered %r to handle %r comparisons", func, exception_class) return func return decorator def raises(expected_exception, *args, **kwargs): """Monkeypatched in by pytest-raisin plugin""" if isinstance(expected_exception, BaseException) and not args and "message" not in kwargs: message = "DID NOT RAISE {!r}".format(expected_exception) return RaisesContext(expected_exception, message, kwargs.get("match")) # There are some strange non-context usages of raises, e.g. passing a callable along # with args/kwargs or passing a code string to be exec. I don't want to support those # weird use-cases, so just fall-back to original implementation if we received any # positional values i.e. a non-empty *args return original(expected_exception, *args, **kwargs) class RaisesContext(type(pytest.raises(Exception))): def __exit__(self, *tp): __tracebackhide__ = True if tp[0] is None: pytest.fail(self.message) self.excinfo.__init__(tp) # note: subclasses are not allowed here! suppress_exception = self.excinfo.type is type(self.expected_exception) if sys.version_info < (3,) and suppress_exception: sys.exc_clear() if suppress_exception: compare = exception_comparers.get(type(self.expected_exception), default_compare) compare(self.excinfo.value, self.expected_exception) if self.match_expr is not None and suppress_exception: self.excinfo.match(self.match_expr) return suppress_exception def pytest_configure(config): # this is called once after command line args have been parsed pytest.raises = raises pytest.register_exception_compare = register_exception_compare def pytest_unconfigure(config): pytest.raises = original vars(pytest).pop("register_exception_compare", None) pytest.register_exception_compare = register_exception_compare PKGbMtђpytest_raisin/comparison_py2.pydef default_compare(exc_actual, exc_expected): __tracebackhide__ = True actual_args = getattr(exc_actual, "args", None) expected_args = getattr(exc_expected, "args", None) if actual_args == expected_args: return msg = "{} args do not match!\n Actual: {}\n Expected: {}" msg = msg.format(type(exc_expected).__name__, actual_args, expected_args) assert 0, msg PKGbMg uypytest_raisin/comparison_py3.pydef default_compare(exc_actual, exc_expected): __tracebackhide__ = True actual_args = getattr(exc_actual, "args", None) expected_args = getattr(exc_expected, "args", None) if actual_args == expected_args: return msg = "{} args do not match!\n Actual: {}\n Expected: {}" msg = msg.format(type(exc_expected).__name__, actual_args, expected_args) raise AssertionError(msg) from None PKGbM1pytest_raisin/compat.pyimport sys if sys.version_info < (3,): from pytest_raisin.comparison_py2 import default_compare else: from pytest_raisin.comparison_py3 import default_compare PK!H(,pytest_raisin-0.2.dist-info/entry_points.txt.,I-.14傰t33l!x PK!HMuSa!pytest_raisin-0.2.dist-info/WHEEL HM K-*ϳR03rOK-J,/RH,szd&Y)r$[)T&UD"PK!H;*$pytest_raisin-0.2.dist-info/METADATAWQs6~K,iDʲ$՜s靧vnnn$E$dN~߂$&i&bwoop"Ith܊B.j.4BYU{,BfAzJXܐ$VNI>Ʋr8BNS.FWߺa%609WlTb]v,gCgW,-x۟oe,gUп@BeMFyWtt}SAnWVJBsg z{wCWUeV& ;mX蝿`EN4_姳( 6V߫R/ m-9# OAEʐ*8o!͔)=cvn7aɛi!ؽޟ/|SzEk紷bRkz. a4V{栲}c2^ eBh)5={68tvqz3=qΟ\~yx"=zI:rC.AСMor9`˦"4(':Q,6CJW3g&k]P>V {V/W(q$\,dLz晐z=y-TNyBkI^% =QZG:G*fLka!XWXcAF_V+a6v"Q2։ ׹P(ȂyȒT~TnW /?Hb}4R9DA4Oǝ[LRZysP; x$ bQm,C1RQڐDĂ4K^L](ĶhͅFV"Wɖ3Џ%Zp <}"ʕN>)[ @_1jtmYʵ~_Zf/_6D eb4\tID{b*,t:iݴؙ$5v]O?;u_~(^zk7TjGpq<*xO~u6{N}^ kKw]2V}֯o=pusz CQl;M )r 0cP  ]>ȦsV usLEԠ.o"ר0N,xvܺ:MQ{Vb*jB qH/,Sw+U־S4䞲#(D쫊*ڛ<) <ˮE޴pG^hޕ,=.hg? }kPy&\ uԛZ+&ѧKw)(abH=` ; L~Gm=wtÝUv?x{jHj![; 萝b(l9ePqޟ0u-{ȌT$#Ԗ եw  lN&dBWN؏LP%M-Lrȗk?>Ԇۥk=d -6`Gje9mPK!Hj""pytest_raisin-0.2.dist-info/RECORD}n@},%"a2 ׍M7g1 C : U&(X=`^ CHkS&\5I|~ytYIO%cY.i9YleYUqg3H< +)􊕟XbkmAWQzV3Л)#{Kdx p>B`sPKKNvXpytest_raisin/__init__.pyPKGbMtђpytest_raisin/comparison_py2.pyPKGbMg uypytest_raisin/comparison_py3.pyPKGbM1tpytest_raisin/compat.pyPK!H(,Qpytest_raisin-0.2.dist-info/entry_points.txtPK!HMuSa!pytest_raisin-0.2.dist-info/WHEELPK!H;*$Jpytest_raisin-0.2.dist-info/METADATAPK!Hj""upytest_raisin-0.2.dist-info/RECORDPKq?