* deprecate py.magic.invoke/revoke in favour of
the new py.code.patch_builtins, py.code.unpatch_builtins * deprecate py.magic.patch/revert * deprecate py.magic.AssertionError in favour of py.code._AssertionError * introduced pytest_assertion plugin. --HG-- branch : trunk
This commit is contained in:
		
							parent
							
								
									e391662cff
								
							
						
					
					
						commit
						13932b7f4b
					
				|  | @ -114,12 +114,12 @@ initpkg(__name__, | ||||||
| 
 | 
 | ||||||
|     # some nice slightly magic APIs |     # some nice slightly magic APIs | ||||||
|     'magic.__doc__'          : ('./magic/__init__.py', '__doc__'), |     'magic.__doc__'          : ('./magic/__init__.py', '__doc__'), | ||||||
|     'magic.invoke'           : ('./magic/invoke.py', 'invoke'), |     'magic.invoke'           : ('./code/oldmagic.py', 'invoke'), | ||||||
|     'magic.revoke'           : ('./magic/invoke.py', 'revoke'), |     'magic.revoke'           : ('./code/oldmagic.py', 'revoke'), | ||||||
|     'magic.patch'            : ('./magic/patch.py', 'patch'), |     'magic.patch'            : ('./code/oldmagic.py', 'patch'), | ||||||
|     'magic.revert'           : ('./magic/patch.py', 'revert'), |     'magic.revert'           : ('./code/oldmagic.py', 'revert'), | ||||||
|     'magic.autopath'         : ('./magic/autopath.py', 'autopath'), |     'magic.autopath'         : ('./magic/autopath.py', 'autopath'), | ||||||
|     'magic.AssertionError'   : ('./magic/assertion.py', 'AssertionError'), |     'magic.AssertionError'   : ('./code/oldmagic2.py', 'AssertionError'), | ||||||
| 
 | 
 | ||||||
|     # python inspection/code-generation API |     # python inspection/code-generation API | ||||||
|     'code.__doc__'           : ('./code/__init__.py', '__doc__'), |     'code.__doc__'           : ('./code/__init__.py', '__doc__'), | ||||||
|  | @ -130,6 +130,9 @@ initpkg(__name__, | ||||||
|     'code.ExceptionInfo'     : ('./code/code.py', 'ExceptionInfo'), |     'code.ExceptionInfo'     : ('./code/code.py', 'ExceptionInfo'), | ||||||
|     'code.Traceback'         : ('./code/code.py', 'Traceback'), |     'code.Traceback'         : ('./code/code.py', 'Traceback'), | ||||||
|     'code.getfslineno'       : ('./code/source.py', 'getfslineno'), |     'code.getfslineno'       : ('./code/source.py', 'getfslineno'), | ||||||
|  |     'code.patch_builtins'    : ('./code/code.py', 'patch_builtins'), | ||||||
|  |     'code.unpatch_builtins'  : ('./code/code.py', 'unpatch_builtins'), | ||||||
|  |     'code._AssertionError'   : ('./code/assertion.py', 'AssertionError'), | ||||||
| 
 | 
 | ||||||
|     # backports and additions of builtins |     # backports and additions of builtins | ||||||
|     'builtin.__doc__'        : ('./builtin/__init__.py', '__doc__'), |     'builtin.__doc__'        : ('./builtin/__init__.py', '__doc__'), | ||||||
|  |  | ||||||
|  | @ -4,52 +4,3 @@ import py | ||||||
| import sys | import sys | ||||||
| import inspect | import inspect | ||||||
| 
 | 
 | ||||||
| def test_all_resolves(): |  | ||||||
|     seen = py.builtin.set([py]) |  | ||||||
|     lastlength = None |  | ||||||
|     while len(seen) != lastlength: |  | ||||||
|         lastlength = len(seen)  |  | ||||||
|         for item in py.builtin.frozenset(seen): |  | ||||||
|             for value in item.__dict__.values(): |  | ||||||
|                 if isinstance(value, type(py.test)): |  | ||||||
|                     seen.add(value) |  | ||||||
|          |  | ||||||
|              |  | ||||||
| class TestAPI_V0_namespace_consistence: |  | ||||||
|     def test_path_entrypoints(self): |  | ||||||
|         assert inspect.ismodule(py.path) |  | ||||||
|         assert_class('py.path', 'local') |  | ||||||
|         assert_class('py.path', 'svnwc') |  | ||||||
|         assert_class('py.path', 'svnurl') |  | ||||||
| 
 |  | ||||||
|     def test_magic_entrypoints(self): |  | ||||||
|         assert_function('py.magic', 'invoke') |  | ||||||
|         assert_function('py.magic', 'revoke') |  | ||||||
|         assert_function('py.magic', 'patch') |  | ||||||
|         assert_function('py.magic', 'revoke') |  | ||||||
| 
 |  | ||||||
|     def test_process_entrypoints(self): |  | ||||||
|         assert_function('py.process', 'cmdexec') |  | ||||||
| 
 |  | ||||||
|     def XXXtest_utest_entrypoints(self): |  | ||||||
|         # XXX TOBECOMPLETED |  | ||||||
|         assert_function('py.test', 'main') |  | ||||||
|         #assert_module('std.utest', 'collect') |  | ||||||
| 
 |  | ||||||
| def assert_class(modpath, name): |  | ||||||
|     mod = __import__(modpath, None, None, [name]) |  | ||||||
|     obj = getattr(mod, name) |  | ||||||
|     assert inspect.isclass(obj) |  | ||||||
| 
 |  | ||||||
|     # we don't test anymore that the exported classes have  |  | ||||||
|     # the exported module path and name on them.  |  | ||||||
|     #fullpath = modpath + '.' + name |  | ||||||
|     #assert obj.__module__ == modpath |  | ||||||
|     #if sys.version_info >= (2,3): |  | ||||||
|     #    assert obj.__name__ == name |  | ||||||
| 
 |  | ||||||
| def assert_function(modpath, name): |  | ||||||
|     mod = __import__(modpath, None, None, [name]) |  | ||||||
|     obj = getattr(mod, name) |  | ||||||
|     assert hasattr(obj, 'func_doc') |  | ||||||
|     #assert obj.func_name == name |  | ||||||
|  |  | ||||||
|  | @ -174,3 +174,14 @@ def test_autoimport(): | ||||||
|     from py.initpkg import autoimport |     from py.initpkg import autoimport | ||||||
|     py.std.os.environ['AUTOTEST_AUTOIMPORT'] = "nonexistmodule" |     py.std.os.environ['AUTOTEST_AUTOIMPORT'] = "nonexistmodule" | ||||||
|     py.test.raises(ImportError, "autoimport('autotest')") |     py.test.raises(ImportError, "autoimport('autotest')") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_all_resolves(): | ||||||
|  |     seen = py.builtin.set([py]) | ||||||
|  |     lastlength = None | ||||||
|  |     while len(seen) != lastlength: | ||||||
|  |         lastlength = len(seen)  | ||||||
|  |         for item in py.builtin.frozenset(seen): | ||||||
|  |             for value in item.__dict__.values(): | ||||||
|  |                 if isinstance(value, type(py.test)): | ||||||
|  |                     seen.add(value) | ||||||
|  |  | ||||||
|  | @ -1,6 +1,8 @@ | ||||||
| from compiler import parse, ast, pycodegen |  | ||||||
| import py | import py | ||||||
| import __builtin__, sys | import sys, inspect | ||||||
|  | from compiler import parse, ast, pycodegen | ||||||
|  | import __builtin__ as cpy_builtin | ||||||
|  | BuiltinAssertionError = cpy_builtin.AssertionError | ||||||
| 
 | 
 | ||||||
| passthroughex = (KeyboardInterrupt, SystemExit, MemoryError) | passthroughex = (KeyboardInterrupt, SystemExit, MemoryError) | ||||||
| 
 | 
 | ||||||
|  | @ -8,10 +10,92 @@ class Failure: | ||||||
|     def __init__(self, node): |     def __init__(self, node): | ||||||
|         self.exc, self.value, self.tb = sys.exc_info() |         self.exc, self.value, self.tb = sys.exc_info() | ||||||
|         self.node = node |         self.node = node | ||||||
|         #import traceback |  | ||||||
|         #traceback.print_exc() |  | ||||||
| 
 | 
 | ||||||
| from py.__.magic.viewtype import View | class View(object): | ||||||
|  |     """View base class. | ||||||
|  | 
 | ||||||
|  |     If C is a subclass of View, then C(x) creates a proxy object around | ||||||
|  |     the object x.  The actual class of the proxy is not C in general, | ||||||
|  |     but a *subclass* of C determined by the rules below.  To avoid confusion | ||||||
|  |     we call view class the class of the proxy (a subclass of C, so of View) | ||||||
|  |     and object class the class of x. | ||||||
|  | 
 | ||||||
|  |     Attributes and methods not found in the proxy are automatically read on x. | ||||||
|  |     Other operations like setting attributes are performed on the proxy, as | ||||||
|  |     determined by its view class.  The object x is available from the proxy | ||||||
|  |     as its __obj__ attribute. | ||||||
|  | 
 | ||||||
|  |     The view class selection is determined by the __view__ tuples and the | ||||||
|  |     optional __viewkey__ method.  By default, the selected view class is the | ||||||
|  |     most specific subclass of C whose __view__ mentions the class of x. | ||||||
|  |     If no such subclass is found, the search proceeds with the parent | ||||||
|  |     object classes.  For example, C(True) will first look for a subclass | ||||||
|  |     of C with __view__ = (..., bool, ...) and only if it doesn't find any | ||||||
|  |     look for one with __view__ = (..., int, ...), and then ..., object,... | ||||||
|  |     If everything fails the class C itself is considered to be the default. | ||||||
|  | 
 | ||||||
|  |     Alternatively, the view class selection can be driven by another aspect | ||||||
|  |     of the object x, instead of the class of x, by overriding __viewkey__. | ||||||
|  |     See last example at the end of this module. | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     _viewcache = {} | ||||||
|  |     __view__ = () | ||||||
|  | 
 | ||||||
|  |     def __new__(rootclass, obj, *args, **kwds): | ||||||
|  |         self = object.__new__(rootclass) | ||||||
|  |         self.__obj__ = obj | ||||||
|  |         self.__rootclass__ = rootclass | ||||||
|  |         key = self.__viewkey__() | ||||||
|  |         try: | ||||||
|  |             self.__class__ = self._viewcache[key] | ||||||
|  |         except KeyError: | ||||||
|  |             self.__class__ = self._selectsubclass(key) | ||||||
|  |         return self | ||||||
|  | 
 | ||||||
|  |     def __getattr__(self, attr): | ||||||
|  |         # attributes not found in the normal hierarchy rooted on View | ||||||
|  |         # are looked up in the object's real class | ||||||
|  |         return getattr(self.__obj__, attr) | ||||||
|  | 
 | ||||||
|  |     def __viewkey__(self): | ||||||
|  |         return self.__obj__.__class__ | ||||||
|  | 
 | ||||||
|  |     def __matchkey__(self, key, subclasses): | ||||||
|  |         if inspect.isclass(key): | ||||||
|  |             keys = inspect.getmro(key) | ||||||
|  |         else: | ||||||
|  |             keys = [key] | ||||||
|  |         for key in keys: | ||||||
|  |             result = [C for C in subclasses if key in C.__view__] | ||||||
|  |             if result: | ||||||
|  |                 return result | ||||||
|  |         return [] | ||||||
|  | 
 | ||||||
|  |     def _selectsubclass(self, key): | ||||||
|  |         subclasses = list(enumsubclasses(self.__rootclass__)) | ||||||
|  |         for C in subclasses: | ||||||
|  |             if not isinstance(C.__view__, tuple): | ||||||
|  |                 C.__view__ = (C.__view__,) | ||||||
|  |         choices = self.__matchkey__(key, subclasses) | ||||||
|  |         if not choices: | ||||||
|  |             return self.__rootclass__ | ||||||
|  |         elif len(choices) == 1: | ||||||
|  |             return choices[0] | ||||||
|  |         else: | ||||||
|  |             # combine the multiple choices | ||||||
|  |             return type('?', tuple(choices), {}) | ||||||
|  | 
 | ||||||
|  |     def __repr__(self): | ||||||
|  |         return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def enumsubclasses(cls): | ||||||
|  |     for subcls in cls.__subclasses__(): | ||||||
|  |         for subsubclass in enumsubclasses(subcls): | ||||||
|  |             yield subsubclass | ||||||
|  |     yield cls | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class Interpretable(View): | class Interpretable(View): | ||||||
|     """A parse tree node with a few extra methods.""" |     """A parse tree node with a few extra methods.""" | ||||||
|  | @ -322,8 +406,6 @@ class Getattr(Interpretable): | ||||||
|             self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) |             self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation) | ||||||
| 
 | 
 | ||||||
| # == Re-interpretation of full statements == | # == Re-interpretation of full statements == | ||||||
| import __builtin__ |  | ||||||
| BuiltinAssertionError = __builtin__.AssertionError |  | ||||||
| 
 | 
 | ||||||
| class Assert(Interpretable): | class Assert(Interpretable): | ||||||
|     __view__ = ast.Assert |     __view__ = ast.Assert | ||||||
|  | @ -390,7 +472,7 @@ def report_failure(e): | ||||||
|         explanation = ", in: " + explanation |         explanation = ", in: " + explanation | ||||||
|     else: |     else: | ||||||
|         explanation = "" |         explanation = "" | ||||||
|     print "%s: %s%s" % (e.exc.__name__, e.value, explanation) |     sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation)) | ||||||
| 
 | 
 | ||||||
| def check(s, frame=None): | def check(s, frame=None): | ||||||
|     if frame is None: |     if frame is None: | ||||||
|  | @ -404,11 +486,12 @@ def check(s, frame=None): | ||||||
|         node.eval(frame) |         node.eval(frame) | ||||||
|     except passthroughex: |     except passthroughex: | ||||||
|         raise |         raise | ||||||
|     except Failure, e: |     except Failure: | ||||||
|  |         e = sys.exc_info()[1] | ||||||
|         report_failure(e) |         report_failure(e) | ||||||
|     else: |     else: | ||||||
|         if not frame.is_true(node.result): |         if not frame.is_true(node.result): | ||||||
|             print "assertion failed:", node.nice_explanation() |             sys.stderr.write("assertion failed: %s\n" % node.nice_explanation()) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ########################################################### | ########################################################### | ||||||
|  | @ -422,7 +505,8 @@ def interpret(source, frame, should_fail=False): | ||||||
|         frame = py.code.Frame(frame) |         frame = py.code.Frame(frame) | ||||||
|     try: |     try: | ||||||
|         module.run(frame) |         module.run(frame) | ||||||
|     except Failure, e: |     except Failure: | ||||||
|  |         e = sys.exc_info()[1] | ||||||
|         return getfailure(e) |         return getfailure(e) | ||||||
|     except passthroughex: |     except passthroughex: | ||||||
|         raise |         raise | ||||||
|  | @ -447,7 +531,7 @@ def getmsg(excinfo): | ||||||
|     source = str(tb.statement).strip() |     source = str(tb.statement).strip() | ||||||
|     x = interpret(source, tb.frame, should_fail=True) |     x = interpret(source, tb.frame, should_fail=True) | ||||||
|     if not isinstance(x, str): |     if not isinstance(x, str): | ||||||
|         raise TypeError, "interpret returned non-string %r" % (x,) |         raise TypeError("interpret returned non-string %r" % (x,)) | ||||||
|     return x |     return x | ||||||
| 
 | 
 | ||||||
| def getfailure(e): | def getfailure(e): | ||||||
|  | @ -469,10 +553,40 @@ def run(s, frame=None): | ||||||
|     module = Interpretable(parse(s, 'exec').node) |     module = Interpretable(parse(s, 'exec').node) | ||||||
|     try: |     try: | ||||||
|         module.run(frame) |         module.run(frame) | ||||||
|     except Failure, e: |     except Failure: | ||||||
|  |         e = sys.exc_info()[1] | ||||||
|         report_failure(e) |         report_failure(e) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class AssertionError(BuiltinAssertionError): | ||||||
|  |     def __init__(self, *args): | ||||||
|  |         BuiltinAssertionError.__init__(self, *args) | ||||||
|  |         if args:  | ||||||
|  |             try: | ||||||
|  |                 self.msg = str(args[0]) | ||||||
|  |             except (KeyboardInterrupt, SystemExit): | ||||||
|  |                 raise | ||||||
|  |             except: | ||||||
|  |                 self.msg = "<[broken __repr__] %s at %0xd>" %( | ||||||
|  |                     args[0].__class__, id(args[0])) | ||||||
|  |              | ||||||
|  |         else:  | ||||||
|  |             f = sys._getframe(1) | ||||||
|  |             try: | ||||||
|  |                 source = py.code.Frame(f).statement | ||||||
|  |                 source = str(source.deindent()).strip() | ||||||
|  |             except py.error.ENOENT: | ||||||
|  |                 source = None | ||||||
|  |                 # this can also occur during reinterpretation, when the | ||||||
|  |                 # co_filename is set to "<run>". | ||||||
|  |             if source: | ||||||
|  |                 self.msg = interpret(source, f, should_fail=True) | ||||||
|  |                 if not self.args: | ||||||
|  |                     self.args = (self.msg,) | ||||||
|  |             else: | ||||||
|  |                 self.msg = None | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     # example: |     # example: | ||||||
|     def f(): |     def f(): | ||||||
|  | @ -5,7 +5,9 @@ try: | ||||||
| except ImportError: | except ImportError: | ||||||
|     import reprlib as repr  |     import reprlib as repr  | ||||||
| 
 | 
 | ||||||
| from __builtin__ import repr as builtin_repr | import __builtin__ as cpy_builtin  | ||||||
|  | 
 | ||||||
|  | builtin_repr = cpy_builtin.repr | ||||||
| 
 | 
 | ||||||
| class Code(object): | class Code(object): | ||||||
|     """ wrapper around Python code objects """ |     """ wrapper around Python code objects """ | ||||||
|  | @ -194,9 +196,9 @@ class TracebackEntry(object): | ||||||
|         """Reinterpret the failing statement and returns a detailed information |         """Reinterpret the failing statement and returns a detailed information | ||||||
|            about what operations are performed.""" |            about what operations are performed.""" | ||||||
|         if self.exprinfo is None: |         if self.exprinfo is None: | ||||||
|             from py.__.magic import exprinfo |             from py.__.code import assertion  | ||||||
|             source = str(self.statement).strip() |             source = str(self.statement).strip() | ||||||
|             x = exprinfo.interpret(source, self.frame, should_fail=True) |             x = assertion.interpret(source, self.frame, should_fail=True) | ||||||
|             if not isinstance(x, str): |             if not isinstance(x, str): | ||||||
|                 raise TypeError, "interpret returned non-string %r" % (x,) |                 raise TypeError, "interpret returned non-string %r" % (x,) | ||||||
|             self.exprinfo = x  |             self.exprinfo = x  | ||||||
|  | @ -355,7 +357,7 @@ class ExceptionInfo(object): | ||||||
|         #     ExceptionInfo-like classes may have different attributes. |         #     ExceptionInfo-like classes may have different attributes. | ||||||
|         if tup is None: |         if tup is None: | ||||||
|             tup = sys.exc_info() |             tup = sys.exc_info() | ||||||
|             if exprinfo is None and isinstance(tup[1], py.magic.AssertionError): |             if exprinfo is None and isinstance(tup[1], py.code._AssertionError): | ||||||
|                 exprinfo = tup[1].msg |                 exprinfo = tup[1].msg | ||||||
|                 if exprinfo and exprinfo.startswith('assert '): |                 if exprinfo and exprinfo.startswith('assert '): | ||||||
|                     self._striptext = 'AssertionError: ' |                     self._striptext = 'AssertionError: ' | ||||||
|  | @ -371,7 +373,7 @@ class ExceptionInfo(object): | ||||||
|         """ return the exception as a string |         """ return the exception as a string | ||||||
|          |          | ||||||
|             when 'tryshort' resolves to True, and the exception is a |             when 'tryshort' resolves to True, and the exception is a | ||||||
|             py.magic.AssertionError, only the actual exception part of |             py.code._AssertionError, only the actual exception part of | ||||||
|             the exception representation is returned (so 'AssertionError: ' is |             the exception representation is returned (so 'AssertionError: ' is | ||||||
|             removed from the beginning) |             removed from the beginning) | ||||||
|         """ |         """ | ||||||
|  | @ -727,3 +729,24 @@ class SafeRepr(repr.Repr): | ||||||
|             return s |             return s | ||||||
| 
 | 
 | ||||||
| safe_repr = SafeRepr().repr | safe_repr = SafeRepr().repr | ||||||
|  | 
 | ||||||
|  | oldbuiltins = {} | ||||||
|  | 
 | ||||||
|  | def patch_builtins(assertion=True, compile=True): | ||||||
|  |     """ put compile and AssertionError builtins to Python's builtins. """ | ||||||
|  |     if assertion: | ||||||
|  |         from py.__.code import assertion | ||||||
|  |         l = oldbuiltins.setdefault('AssertionError', []) | ||||||
|  |         l.append(cpy_builtin.AssertionError) | ||||||
|  |         cpy_builtin.AssertionError = assertion.AssertionError | ||||||
|  |     if compile:  | ||||||
|  |         l = oldbuiltins.setdefault('compile', []) | ||||||
|  |         l.append(cpy_builtin.compile) | ||||||
|  |         cpy_builtin.compile = py.code.compile  | ||||||
|  | 
 | ||||||
|  | def unpatch_builtins(assertion=True, compile=True): | ||||||
|  |     """ remove compile and AssertionError builtins from Python builtins. """ | ||||||
|  |     if assertion: | ||||||
|  |         cpy_builtin.AssertionError = oldbuiltins['AssertionError'].pop() | ||||||
|  |     if compile:  | ||||||
|  |         cpy_builtin.compile = oldbuiltins['compile'].pop() | ||||||
|  |  | ||||||
|  | @ -0,0 +1,61 @@ | ||||||
|  | """ deprecated module for turning on/off some features. """  | ||||||
|  | 
 | ||||||
|  | import py  | ||||||
|  | import __builtin__ as cpy_builtin | ||||||
|  | 
 | ||||||
|  | def invoke(assertion=False, compile=False): | ||||||
|  |     """ (deprecated) invoke magic, currently you can specify: | ||||||
|  | 
 | ||||||
|  |         assertion  patches the builtin AssertionError to try to give | ||||||
|  |                    more meaningful AssertionErrors, which by means | ||||||
|  |                    of deploying a mini-interpreter constructs | ||||||
|  |                    a useful error message. | ||||||
|  |     """ | ||||||
|  |     py.log._apiwarn("1.1",  | ||||||
|  |         "py.magic.invoke() is deprecated, use py.code.patch_builtins()", | ||||||
|  |         stacklevel=2,  | ||||||
|  |     ) | ||||||
|  |     py.code.patch_builtins(assertion=assertion, compile=compile) | ||||||
|  | 
 | ||||||
|  | def revoke(assertion=False, compile=False): | ||||||
|  |     """ (deprecated) revoke previously invoked magic (see invoke()).""" | ||||||
|  |     py.log._apiwarn("1.1",  | ||||||
|  |         "py.magic.revoke() is deprecated, use py.code.unpatch_builtins()", | ||||||
|  |         stacklevel=2,  | ||||||
|  |     ) | ||||||
|  |     py.code.unpatch_builtins(assertion=assertion, compile=compile) | ||||||
|  | 
 | ||||||
|  | patched = {} | ||||||
|  | 
 | ||||||
|  | def patch(namespace, name, value): | ||||||
|  |     """ (deprecated) rebind the 'name' on the 'namespace'  to the 'value', | ||||||
|  |         possibly and remember the original value. Multiple | ||||||
|  |         invocations to the same namespace/name pair will | ||||||
|  |         remember a list of old values. | ||||||
|  |     """ | ||||||
|  |     py.log._apiwarn("1.1",  | ||||||
|  |         "py.magic.patch() is deprecated, in tests use monkeypatch funcarg.",  | ||||||
|  |         stacklevel=2,  | ||||||
|  |     ) | ||||||
|  |     nref = (namespace, name) | ||||||
|  |     orig = getattr(namespace, name) | ||||||
|  |     patched.setdefault(nref, []).append(orig) | ||||||
|  |     setattr(namespace, name, value) | ||||||
|  |     return orig | ||||||
|  | 
 | ||||||
|  | def revert(namespace, name): | ||||||
|  |     """ (deprecated) revert to the orginal value the last patch modified. | ||||||
|  |         Raise ValueError if no such original value exists. | ||||||
|  |     """ | ||||||
|  |     py.log._apiwarn("1.1",  | ||||||
|  |         "py.magic.revert() is deprecated, in tests use monkeypatch funcarg.", | ||||||
|  |         stacklevel=2,  | ||||||
|  |     ) | ||||||
|  |     nref = (namespace, name) | ||||||
|  |     if nref not in patched or not patched[nref]: | ||||||
|  |         raise ValueError, "No original value stored for %s.%s" % nref | ||||||
|  |     current = getattr(namespace, name) | ||||||
|  |     orig = patched[nref].pop() | ||||||
|  |     setattr(namespace, name, orig) | ||||||
|  |     return current | ||||||
|  | 
 | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | 
 | ||||||
|  | import py | ||||||
|  | 
 | ||||||
|  | py.log._apiwarn("1.1", "py.magic.AssertionError is deprecated, use py.code._AssertionError", stacklevel=2) | ||||||
|  | 
 | ||||||
|  | from py.code import _AssertionError as AssertionError | ||||||
|  | @ -0,0 +1,173 @@ | ||||||
|  | import py | ||||||
|  | from py.__.code.assertion import View | ||||||
|  | 
 | ||||||
|  | def setup_module(mod): | ||||||
|  |     py.code.patch_builtins(assertion=True, compile=False) | ||||||
|  | 
 | ||||||
|  | def teardown_module(mod): | ||||||
|  |     py.code.unpatch_builtins(assertion=True, compile=False) | ||||||
|  | 
 | ||||||
|  | def f(): | ||||||
|  |     return 2 | ||||||
|  | 
 | ||||||
|  | def test_assert(): | ||||||
|  |     try: | ||||||
|  |         assert f() == 3 | ||||||
|  |     except AssertionError, e: | ||||||
|  |         s = str(e) | ||||||
|  |         assert s.startswith('assert 2 == 3\n') | ||||||
|  | 
 | ||||||
|  | def test_assert_with_explicit_message(): | ||||||
|  |     try: | ||||||
|  |         assert f() == 3, "hello" | ||||||
|  |     except AssertionError, e: | ||||||
|  |         assert e.msg == 'hello' | ||||||
|  | 
 | ||||||
|  | def test_assert_within_finally(): | ||||||
|  |     class A: | ||||||
|  |         def f(): | ||||||
|  |             pass | ||||||
|  |     excinfo = py.test.raises(TypeError, """ | ||||||
|  |         try: | ||||||
|  |             A().f() | ||||||
|  |         finally: | ||||||
|  |             i = 42 | ||||||
|  |     """) | ||||||
|  |     s = excinfo.exconly()  | ||||||
|  |     assert s.find("takes no argument") != -1 | ||||||
|  | 
 | ||||||
|  |     #def g(): | ||||||
|  |     #    A.f() | ||||||
|  |     #excinfo = getexcinfo(TypeError, g) | ||||||
|  |     #msg = getmsg(excinfo) | ||||||
|  |     #assert msg.find("must be called with A") != -1 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_assert_multiline_1(): | ||||||
|  |     try: | ||||||
|  |         assert (f() == | ||||||
|  |                 3) | ||||||
|  |     except AssertionError, e: | ||||||
|  |         s = str(e) | ||||||
|  |         assert s.startswith('assert 2 == 3\n') | ||||||
|  | 
 | ||||||
|  | def test_assert_multiline_2(): | ||||||
|  |     try: | ||||||
|  |         assert (f() == (4, | ||||||
|  |                    3)[-1]) | ||||||
|  |     except AssertionError, e: | ||||||
|  |         s = str(e) | ||||||
|  |         assert s.startswith('assert 2 ==') | ||||||
|  | 
 | ||||||
|  | def test_assert_non_string_message():  | ||||||
|  |     class A:  | ||||||
|  |         def __str__(self):  | ||||||
|  |             return "hello" | ||||||
|  |     try: | ||||||
|  |         assert 0 == 1, A() | ||||||
|  |     except AssertionError, e:  | ||||||
|  |         assert e.msg == "hello" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # These tests should both fail, but should fail nicely... | ||||||
|  | class WeirdRepr: | ||||||
|  |     def __repr__(self): | ||||||
|  |         return '<WeirdRepr\nsecond line>' | ||||||
|  |              | ||||||
|  | def bug_test_assert_repr(): | ||||||
|  |     v = WeirdRepr() | ||||||
|  |     try:  | ||||||
|  |         assert v == 1 | ||||||
|  |     except AssertionError, e:  | ||||||
|  |         assert e.msg.find('WeirdRepr') != -1 | ||||||
|  |         assert e.msg.find('second line') != -1 | ||||||
|  |         assert 0 | ||||||
|  |          | ||||||
|  | def test_assert_non_string(): | ||||||
|  |     try:  | ||||||
|  |         assert 0, ['list'] | ||||||
|  |     except AssertionError, e:  | ||||||
|  |         assert e.msg.find("list") != -1  | ||||||
|  | 
 | ||||||
|  | def test_assert_implicit_multiline(): | ||||||
|  |     try: | ||||||
|  |         x = [1,2,3] | ||||||
|  |         assert x != [1, | ||||||
|  |            2, 3] | ||||||
|  |     except AssertionError, e: | ||||||
|  |         assert e.msg.find('assert [1, 2, 3] !=') != -1 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_assert_with_brokenrepr_arg(): | ||||||
|  |     class BrokenRepr: | ||||||
|  |         def __repr__(self): 0 / 0 | ||||||
|  |     e = AssertionError(BrokenRepr()) | ||||||
|  |     if e.msg.find("broken __repr__") == -1: | ||||||
|  |         py.test.fail("broken __repr__ not handle correctly") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestView: | ||||||
|  |     def test_class_dispatch(self): | ||||||
|  |         ### Use a custom class hierarchy with existing instances | ||||||
|  | 
 | ||||||
|  |         class Picklable(View): | ||||||
|  |             pass | ||||||
|  | 
 | ||||||
|  |         class Simple(Picklable): | ||||||
|  |             __view__ = object | ||||||
|  |             def pickle(self): | ||||||
|  |                 return repr(self.__obj__) | ||||||
|  | 
 | ||||||
|  |         class Seq(Picklable): | ||||||
|  |             __view__ = list, tuple, dict | ||||||
|  |             def pickle(self): | ||||||
|  |                 return ';'.join( | ||||||
|  |                     [Picklable(item).pickle() for item in self.__obj__]) | ||||||
|  | 
 | ||||||
|  |         class Dict(Seq): | ||||||
|  |             __view__ = dict | ||||||
|  |             def pickle(self): | ||||||
|  |                 return Seq.pickle(self) + '!' + Seq(self.values()).pickle() | ||||||
|  | 
 | ||||||
|  |         assert Picklable(123).pickle() == '123' | ||||||
|  |         assert Picklable([1,[2,3],4]).pickle() == '1;2;3;4' | ||||||
|  |         assert Picklable({1:2}).pickle() == '1!2' | ||||||
|  | 
 | ||||||
|  |     def test_viewtype_class_hierarchy(self): | ||||||
|  |         # Use a custom class hierarchy based on attributes of existing instances | ||||||
|  |         class Operation: | ||||||
|  |             "Existing class that I don't want to change." | ||||||
|  |             def __init__(self, opname, *args): | ||||||
|  |                 self.opname = opname | ||||||
|  |                 self.args = args | ||||||
|  | 
 | ||||||
|  |         existing = [Operation('+', 4, 5), | ||||||
|  |                     Operation('getitem', '', 'join'), | ||||||
|  |                     Operation('setattr', 'x', 'y', 3), | ||||||
|  |                     Operation('-', 12, 1)] | ||||||
|  | 
 | ||||||
|  |         class PyOp(View): | ||||||
|  |             def __viewkey__(self): | ||||||
|  |                 return self.opname | ||||||
|  |             def generate(self): | ||||||
|  |                 return '%s(%s)' % (self.opname, ', '.join(map(repr, self.args))) | ||||||
|  | 
 | ||||||
|  |         class PyBinaryOp(PyOp): | ||||||
|  |             __view__ = ('+', '-', '*', '/') | ||||||
|  |             def generate(self): | ||||||
|  |                 return '%s %s %s' % (self.args[0], self.opname, self.args[1]) | ||||||
|  | 
 | ||||||
|  |         codelines = [PyOp(op).generate() for op in existing] | ||||||
|  |         assert codelines == ["4 + 5", "getitem('', 'join')",  | ||||||
|  |             "setattr('x', 'y', 3)", "12 - 1"] | ||||||
|  | 
 | ||||||
|  | def test_AssertionError(testdir): | ||||||
|  |     testdir.makepyfile(""" | ||||||
|  |         import py | ||||||
|  |         def test_hello(recwarn): | ||||||
|  |             err = py.magic.AssertionError | ||||||
|  |             recwarn.pop(DeprecationWarning) | ||||||
|  |             assert err is py.code._AssertionError | ||||||
|  |     """) | ||||||
|  |     result = testdir.runpytest()  | ||||||
|  |     assert "1 passed" in result.stdout.str() | ||||||
|  | @ -165,4 +165,17 @@ class TestSafeRepr: | ||||||
|         except Exception, e: |         except Exception, e: | ||||||
|             py.test.fail("saferepr failed for newstyle class") |             py.test.fail("saferepr failed for newstyle class") | ||||||
|    |    | ||||||
|  | def test_builtin_patch_unpatch(monkeypatch): | ||||||
|  |     import __builtin__ as cpy_builtin | ||||||
|  |     comp = cpy_builtin.compile  | ||||||
|  |     def mycompile(*args, **kwargs): | ||||||
|  |         return comp(*args, **kwargs) | ||||||
|  |     monkeypatch.setattr(cpy_builtin, 'AssertionError', None) | ||||||
|  |     monkeypatch.setattr(cpy_builtin, 'compile', mycompile) | ||||||
|  |     py.code.patch_builtins() | ||||||
|  |     assert cpy_builtin.AssertionError | ||||||
|  |     assert cpy_builtin.compile != mycompile | ||||||
|  |     py.code.unpatch_builtins() | ||||||
|  |     assert cpy_builtin.AssertionError is None | ||||||
|  |     assert cpy_builtin.compile == mycompile  | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -577,11 +577,11 @@ raise ValueError() | ||||||
|                 x = 1 |                 x = 1 | ||||||
|                 assert x == 2 |                 assert x == 2 | ||||||
|         """) |         """) | ||||||
|         py.magic.invoke(assertion=True) |         py.code.patch_builtins(assertion=True) | ||||||
|         try: |         try: | ||||||
|             excinfo = py.test.raises(AssertionError, mod.somefunc) |             excinfo = py.test.raises(AssertionError, mod.somefunc) | ||||||
|         finally: |         finally: | ||||||
|             py.magic.revoke(assertion=True) |             py.code.unpatch_builtins(assertion=True) | ||||||
|              |              | ||||||
|         p = FormattedExcinfo() |         p = FormattedExcinfo() | ||||||
|         reprentry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) |         reprentry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,64 @@ | ||||||
|  | import py | ||||||
|  | 
 | ||||||
|  | def check_assertion(): | ||||||
|  |     excinfo = py.test.raises(AssertionError, "assert 1 == 2") | ||||||
|  |     s = excinfo.exconly(tryshort=True) | ||||||
|  |     if not s == "assert 1 == 2": | ||||||
|  |         raise ValueError("assertion not enabled: got %s" % s) | ||||||
|  | 
 | ||||||
|  | def test_invoke_assertion(recwarn, monkeypatch): | ||||||
|  |     monkeypatch.setattr(py.std.__builtin__, 'AssertionError', None) | ||||||
|  |     py.magic.invoke(assertion=True) | ||||||
|  |     try: | ||||||
|  |         check_assertion() | ||||||
|  |     finally: | ||||||
|  |         py.magic.revoke(assertion=True) | ||||||
|  |     recwarn.pop(DeprecationWarning) | ||||||
|  | 
 | ||||||
|  | def test_invoke_compile(recwarn, monkeypatch): | ||||||
|  |     monkeypatch.setattr(py.std.__builtin__, 'compile', None) | ||||||
|  |     py.magic.invoke(compile=True) | ||||||
|  |     try: | ||||||
|  |         co = compile("""if 1:  | ||||||
|  |                     def f():  | ||||||
|  |                         return 1 | ||||||
|  |                     \n""", '', 'exec') | ||||||
|  |         d = {} | ||||||
|  |         exec co in d | ||||||
|  |         assert py.code.Source(d['f'])  | ||||||
|  |     finally: | ||||||
|  |         py.magic.revoke(compile=True) | ||||||
|  |     recwarn.pop(DeprecationWarning) | ||||||
|  | 
 | ||||||
|  | def test_patch_revert(recwarn): | ||||||
|  |     class a: | ||||||
|  |         pass | ||||||
|  |     py.test.raises(AttributeError, "py.magic.patch(a, 'i', 42)") | ||||||
|  | 
 | ||||||
|  |     a.i = 42 | ||||||
|  |     py.magic.patch(a, 'i', 23) | ||||||
|  |     assert a.i == 23 | ||||||
|  |     recwarn.pop(DeprecationWarning) | ||||||
|  |     py.magic.revert(a, 'i') | ||||||
|  |     assert a.i == 42 | ||||||
|  |     recwarn.pop(DeprecationWarning) | ||||||
|  | 
 | ||||||
|  | def test_double_patch(recwarn): | ||||||
|  |     class a: | ||||||
|  |         i = 42 | ||||||
|  |     assert py.magic.patch(a, 'i', 2) == 42 | ||||||
|  |     recwarn.pop(DeprecationWarning) | ||||||
|  |     assert py.magic.patch(a, 'i', 3) == 2 | ||||||
|  |     assert a.i == 3 | ||||||
|  |     assert py.magic.revert(a, 'i') == 3 | ||||||
|  |     recwarn.pop(DeprecationWarning) | ||||||
|  |     assert a.i == 2 | ||||||
|  |     assert py.magic.revert(a, 'i') == 2 | ||||||
|  |     assert a.i == 42 | ||||||
|  | 
 | ||||||
|  | def test_valueerror(recwarn): | ||||||
|  |     class a: | ||||||
|  |         i = 2 | ||||||
|  |         pass | ||||||
|  |     py.test.raises(ValueError, "py.magic.revert(a, 'i')") | ||||||
|  |     recwarn.pop(DeprecationWarning) | ||||||
|  | @ -1,38 +0,0 @@ | ||||||
| import __builtin__, sys |  | ||||||
| import py |  | ||||||
| from py.__.magic import exprinfo |  | ||||||
| 
 |  | ||||||
| BuiltinAssertionError = __builtin__.AssertionError |  | ||||||
| 
 |  | ||||||
| class AssertionError(BuiltinAssertionError): |  | ||||||
|     def __init__(self, *args): |  | ||||||
|         BuiltinAssertionError.__init__(self, *args) |  | ||||||
|         if args:  |  | ||||||
|             try: |  | ||||||
|                 self.msg = str(args[0]) |  | ||||||
|             except (KeyboardInterrupt, SystemExit): |  | ||||||
|                 raise |  | ||||||
|             except: |  | ||||||
|                 self.msg = "<[broken __repr__] %s at %0xd>" %( |  | ||||||
|                     args[0].__class__, id(args[0])) |  | ||||||
|              |  | ||||||
|         else:  |  | ||||||
|             f = sys._getframe(1) |  | ||||||
|             try: |  | ||||||
|                 source = py.code.Frame(f).statement |  | ||||||
|                 source = str(source.deindent()).strip() |  | ||||||
|             except py.error.ENOENT: |  | ||||||
|                 source = None |  | ||||||
|                 # this can also occur during reinterpretation, when the |  | ||||||
|                 # co_filename is set to "<run>". |  | ||||||
|             if source: |  | ||||||
|                 self.msg = exprinfo.interpret(source, f, should_fail=True) |  | ||||||
|                 if not self.args: |  | ||||||
|                     self.args = (self.msg,) |  | ||||||
|             else: |  | ||||||
|                 self.msg = None |  | ||||||
| 
 |  | ||||||
| def invoke(): |  | ||||||
|     py.magic.patch(__builtin__, 'AssertionError', AssertionError) |  | ||||||
| def revoke(): |  | ||||||
|     py.magic.revert(__builtin__, 'AssertionError') |  | ||||||
|  | @ -1,24 +0,0 @@ | ||||||
| import py  |  | ||||||
| import __builtin__ as cpy_builtin |  | ||||||
| 
 |  | ||||||
| def invoke(assertion=False, compile=False): |  | ||||||
|     """ invoke magic, currently you can specify: |  | ||||||
| 
 |  | ||||||
|         assertion  patches the builtin AssertionError to try to give |  | ||||||
|                    more meaningful AssertionErrors, which by means |  | ||||||
|                    of deploying a mini-interpreter constructs |  | ||||||
|                    a useful error message. |  | ||||||
|     """ |  | ||||||
|     if assertion: |  | ||||||
|         from py.__.magic import assertion |  | ||||||
|         assertion.invoke() |  | ||||||
|     if compile:  |  | ||||||
|         py.magic.patch(cpy_builtin, 'compile', py.code.compile ) |  | ||||||
| 
 |  | ||||||
| def revoke(assertion=False, compile=False): |  | ||||||
|     """ revoke previously invoked magic (see invoke()).""" |  | ||||||
|     if assertion: |  | ||||||
|         from py.__.magic import assertion |  | ||||||
|         assertion.revoke() |  | ||||||
|     if compile:  |  | ||||||
|         py.magic.revert(cpy_builtin, 'compile')  |  | ||||||
|  | @ -1,26 +0,0 @@ | ||||||
| 
 |  | ||||||
| patched = {} |  | ||||||
| 
 |  | ||||||
| def patch(namespace, name, value): |  | ||||||
|     """ rebind the 'name' on the 'namespace'  to the 'value', |  | ||||||
|         possibly and remember the original value. Multiple |  | ||||||
|         invocations to the same namespace/name pair will |  | ||||||
|         remember a list of old values. |  | ||||||
|     """ |  | ||||||
|     nref = (namespace, name) |  | ||||||
|     orig = getattr(namespace, name) |  | ||||||
|     patched.setdefault(nref, []).append(orig) |  | ||||||
|     setattr(namespace, name, value) |  | ||||||
|     return orig |  | ||||||
| 
 |  | ||||||
| def revert(namespace, name): |  | ||||||
|     """ revert to the orginal value the last patch modified. |  | ||||||
|         Raise ValueError if no such original value exists. |  | ||||||
|     """ |  | ||||||
|     nref = (namespace, name) |  | ||||||
|     if nref not in patched or not patched[nref]: |  | ||||||
|         raise ValueError, "No original value stored for %s.%s" % nref |  | ||||||
|     current = getattr(namespace, name) |  | ||||||
|     orig = patched[nref].pop() |  | ||||||
|     setattr(namespace, name, orig) |  | ||||||
|     return current |  | ||||||
|  | @ -1,106 +0,0 @@ | ||||||
| import py |  | ||||||
| 
 |  | ||||||
| def setup_module(mod): |  | ||||||
|     py.magic.invoke(assertion=1) |  | ||||||
| 
 |  | ||||||
| def teardown_module(mod): |  | ||||||
|     py.magic.revoke(assertion=1) |  | ||||||
| 
 |  | ||||||
| def f(): |  | ||||||
|     return 2 |  | ||||||
| 
 |  | ||||||
| def test_assert(): |  | ||||||
|     try: |  | ||||||
|         assert f() == 3 |  | ||||||
|     except AssertionError, e: |  | ||||||
|         s = str(e) |  | ||||||
|         assert s.startswith('assert 2 == 3\n') |  | ||||||
| 
 |  | ||||||
| def test_assert_with_explicit_message(): |  | ||||||
|     try: |  | ||||||
|         assert f() == 3, "hello" |  | ||||||
|     except AssertionError, e: |  | ||||||
|         assert e.msg == 'hello' |  | ||||||
| 
 |  | ||||||
| def test_assert_within_finally(): |  | ||||||
|     class A: |  | ||||||
|         def f(): |  | ||||||
|             pass |  | ||||||
|     excinfo = py.test.raises(TypeError, """ |  | ||||||
|         try: |  | ||||||
|             A().f() |  | ||||||
|         finally: |  | ||||||
|             i = 42 |  | ||||||
|     """) |  | ||||||
|     s = excinfo.exconly()  |  | ||||||
|     assert s.find("takes no argument") != -1 |  | ||||||
| 
 |  | ||||||
|     #def g(): |  | ||||||
|     #    A.f() |  | ||||||
|     #excinfo = getexcinfo(TypeError, g) |  | ||||||
|     #msg = getmsg(excinfo) |  | ||||||
|     #assert msg.find("must be called with A") != -1 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_assert_multiline_1(): |  | ||||||
|     try: |  | ||||||
|         assert (f() == |  | ||||||
|                 3) |  | ||||||
|     except AssertionError, e: |  | ||||||
|         s = str(e) |  | ||||||
|         assert s.startswith('assert 2 == 3\n') |  | ||||||
| 
 |  | ||||||
| def test_assert_multiline_2(): |  | ||||||
|     try: |  | ||||||
|         assert (f() == (4, |  | ||||||
|                    3)[-1]) |  | ||||||
|     except AssertionError, e: |  | ||||||
|         s = str(e) |  | ||||||
|         assert s.startswith('assert 2 ==') |  | ||||||
| 
 |  | ||||||
| def test_assert_non_string_message():  |  | ||||||
|     class A:  |  | ||||||
|         def __str__(self):  |  | ||||||
|             return "hello" |  | ||||||
|     try: |  | ||||||
|         assert 0 == 1, A() |  | ||||||
|     except AssertionError, e:  |  | ||||||
|         assert e.msg == "hello" |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| # These tests should both fail, but should fail nicely... |  | ||||||
| class WeirdRepr: |  | ||||||
|     def __repr__(self): |  | ||||||
|         return '<WeirdRepr\nsecond line>' |  | ||||||
|              |  | ||||||
| def bug_test_assert_repr(): |  | ||||||
|     v = WeirdRepr() |  | ||||||
|     try:  |  | ||||||
|         assert v == 1 |  | ||||||
|     except AssertionError, e:  |  | ||||||
|         assert e.msg.find('WeirdRepr') != -1 |  | ||||||
|         assert e.msg.find('second line') != -1 |  | ||||||
|         assert 0 |  | ||||||
|          |  | ||||||
| def test_assert_non_string(): |  | ||||||
|     try:  |  | ||||||
|         assert 0, ['list'] |  | ||||||
|     except AssertionError, e:  |  | ||||||
|         assert e.msg.find("list") != -1  |  | ||||||
| 
 |  | ||||||
| def test_assert_implicit_multiline(): |  | ||||||
|     try: |  | ||||||
|         x = [1,2,3] |  | ||||||
|         assert x != [1, |  | ||||||
|            2, 3] |  | ||||||
|     except AssertionError, e: |  | ||||||
|         assert e.msg.find('assert [1, 2, 3] !=') != -1 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_assert_with_brokenrepr_arg(): |  | ||||||
|     class BrokenRepr: |  | ||||||
|         def __repr__(self): 0 / 0 |  | ||||||
|     e = AssertionError(BrokenRepr()) |  | ||||||
|     if e.msg.find("broken __repr__") == -1: |  | ||||||
|         py.test.fail("broken __repr__ not handle correctly") |  | ||||||
| 
 |  | ||||||
|  | @ -1,156 +0,0 @@ | ||||||
| 
 |  | ||||||
| import sys |  | ||||||
| import py |  | ||||||
| from py.__.magic.exprinfo import getmsg, interpret |  | ||||||
| 
 |  | ||||||
| def getexcinfo(exc, obj, *args, **kwargs): |  | ||||||
|     try: |  | ||||||
|         obj(*args, **kwargs) |  | ||||||
|     except KeyboardInterrupt: |  | ||||||
|         raise |  | ||||||
|     except exc: |  | ||||||
|         return sys.exc_info() |  | ||||||
|     else: |  | ||||||
|         raise AssertionError, "%r(*%r, **%r) did not raise" %( |  | ||||||
|             obj, args, kwargs) |  | ||||||
| 
 |  | ||||||
| def test_assert_exprinfo(): |  | ||||||
|     def g(): |  | ||||||
|         a = 1 |  | ||||||
|         b = 2 |  | ||||||
|         assert a == b |  | ||||||
|     excinfo = getexcinfo(AssertionError, g) |  | ||||||
|     msg = getmsg(excinfo) |  | ||||||
|     assert msg == 'assert 1 == 2' |  | ||||||
| 
 |  | ||||||
| def test_nested_scopes(): |  | ||||||
|     def g(): |  | ||||||
|         a = 1 |  | ||||||
|         def h(): |  | ||||||
|             return a |  | ||||||
|         b = 2 |  | ||||||
|         assert h() == b |  | ||||||
|     excinfo = getexcinfo(AssertionError, g) |  | ||||||
|     msg = getmsg(excinfo) |  | ||||||
|     assert msg.startswith('assert 1 == 2\n +  where 1 = ') |  | ||||||
| 
 |  | ||||||
| def test_nested_scopes_2(): |  | ||||||
|     a = 1 |  | ||||||
|     def g(): |  | ||||||
|         b = 2 |  | ||||||
|         assert a == b |  | ||||||
|     excinfo = getexcinfo(AssertionError, g) |  | ||||||
|     msg = getmsg(excinfo) |  | ||||||
|     assert msg == 'assert 1 == 2' |  | ||||||
| 
 |  | ||||||
| def test_assert_func_argument_type_error(): |  | ||||||
|     def f (): |  | ||||||
|         pass |  | ||||||
|     def g(): |  | ||||||
|         f(1) |  | ||||||
|     excinfo = getexcinfo(TypeError, g) |  | ||||||
|     msg = getmsg(excinfo) |  | ||||||
|     assert msg.find("takes no argument") != -1 |  | ||||||
| 
 |  | ||||||
|     class A: |  | ||||||
|         def f(): |  | ||||||
|             pass |  | ||||||
|     def g(): |  | ||||||
|         A().f() |  | ||||||
|     excinfo = getexcinfo(TypeError, g) |  | ||||||
|     msg = getmsg(excinfo) |  | ||||||
|     assert msg.find("takes no argument") != -1 |  | ||||||
| 
 |  | ||||||
|     def g(): |  | ||||||
|         A.f() |  | ||||||
|     excinfo = getexcinfo(TypeError, g) |  | ||||||
|     msg = getmsg(excinfo) |  | ||||||
|     assert msg.find("must be called with A") != -1 |  | ||||||
| 
 |  | ||||||
| def global_f(u=6, v=7): |  | ||||||
|     return u*v |  | ||||||
| 
 |  | ||||||
| def test_exprinfo_funccall(): |  | ||||||
|     def g(): |  | ||||||
|         assert global_f() == 43 |  | ||||||
|     excinfo = getexcinfo(AssertionError, g) |  | ||||||
|     msg = getmsg(excinfo) |  | ||||||
|     assert msg == 'assert 42 == 43\n +  where 42 = global_f()' |  | ||||||
| 
 |  | ||||||
| def test_exprinfo_funccall_keywords(): |  | ||||||
|     def g(): |  | ||||||
|         assert global_f(v=11) == 67 |  | ||||||
|     excinfo = getexcinfo(AssertionError, g) |  | ||||||
|     msg = getmsg(excinfo) |  | ||||||
|     assert msg == 'assert 66 == 67\n +  where 66 = global_f(v=11)' |  | ||||||
| 
 |  | ||||||
| def test_interpretable_escapes_newlines(): |  | ||||||
|     class X(object): |  | ||||||
|         def __repr__(self): |  | ||||||
|             return '1\n2' |  | ||||||
|     def g(): |  | ||||||
|         assert X() == 'XXX' |  | ||||||
| 
 |  | ||||||
|     excinfo = getexcinfo(AssertionError, g) |  | ||||||
|     msg = getmsg(excinfo) |  | ||||||
|     assert msg == "assert 1\\n2 == 'XXX'\n +  where 1\\n2 = <class 'py.__.magic.testing.test_exprinfo.X'>()" |  | ||||||
| 
 |  | ||||||
| def test_keyboard_interrupt(): |  | ||||||
|     # XXX this test is slightly strange because it is not |  | ||||||
|     # clear that "interpret" should execute "raise" statements |  | ||||||
|     # ... but it apparently currently does and it's nice to |  | ||||||
|     # exercise the code because the exprinfo-machinery is |  | ||||||
|     # not much executed when all tests pass ... |  | ||||||
| 
 |  | ||||||
|     class DummyCode: |  | ||||||
|         co_filename = 'dummy' |  | ||||||
|         co_firstlineno = 0 |  | ||||||
|         co_name = 'dummy' |  | ||||||
|     class DummyFrame: |  | ||||||
|         f_globals = f_locals = {} |  | ||||||
|         f_code = DummyCode |  | ||||||
|         f_lineno = 0 |  | ||||||
| 
 |  | ||||||
|     for exstr in "SystemExit", "KeyboardInterrupt", "MemoryError": |  | ||||||
|         ex = eval(exstr) |  | ||||||
|         try: |  | ||||||
|             interpret("raise %s" % exstr, py.code.Frame(DummyFrame)) |  | ||||||
|         except ex: |  | ||||||
|             pass |  | ||||||
|         else: |  | ||||||
|             raise AssertionError, "ex %s didn't pass through" %(exstr, ) |  | ||||||
| 
 |  | ||||||
| def test_inconsistent_assert_result(testdir): |  | ||||||
|     p = testdir.makepyfile(""" |  | ||||||
|         def test_func(): |  | ||||||
|             def f(l=[1,0]):  |  | ||||||
|                 return l.pop() |  | ||||||
|             assert f() |  | ||||||
|     """) |  | ||||||
|     result = testdir.runpytest(p) |  | ||||||
|     s = result.stdout.str() |  | ||||||
|     assert s.find("re-run") != -1 |  | ||||||
| 
 |  | ||||||
| def test_twoarg_comparison_does_not_call_nonzero(): |  | ||||||
|     # this arises e.g. in numpy array comparisons  |  | ||||||
|     class X(object): |  | ||||||
|         def __eq__(self, other): |  | ||||||
|             return self |  | ||||||
| 
 |  | ||||||
|         def __nonzero__(self): |  | ||||||
|             raise ValueError |  | ||||||
| 
 |  | ||||||
|         def all(self): |  | ||||||
|             return False |  | ||||||
| 
 |  | ||||||
|     def f(): |  | ||||||
|         a = X() |  | ||||||
|         b = X() |  | ||||||
|         assert (a == b).all() |  | ||||||
| 
 |  | ||||||
|     excinfo = getexcinfo(AssertionError, f) |  | ||||||
|     msg = getmsg(excinfo) |  | ||||||
|     print msg |  | ||||||
|     assert "re-run" not in msg |  | ||||||
|     assert "ValueError" not in msg |  | ||||||
| 
 |  | ||||||
|  | @ -1,29 +0,0 @@ | ||||||
| import __builtin__ as bltin |  | ||||||
| import py |  | ||||||
| import inspect |  | ||||||
| 
 |  | ||||||
| def check_assertion(): |  | ||||||
|     excinfo = py.test.raises(AssertionError, "assert 1 == 2") |  | ||||||
|     assert excinfo.exconly(tryshort=True) == "assert 1 == 2" |  | ||||||
| 
 |  | ||||||
| def test_invoke_assertion(): |  | ||||||
|     py.magic.invoke(assertion=True) |  | ||||||
|     try: |  | ||||||
|         check_assertion() |  | ||||||
|     finally: |  | ||||||
|         py.magic.revoke(assertion=True) |  | ||||||
| 
 |  | ||||||
| def test_invoke_compile(): |  | ||||||
|     py.magic.invoke(compile=True) |  | ||||||
|     try: |  | ||||||
|         co = compile("""if 1:  |  | ||||||
|                     def f():  |  | ||||||
|                         return 1 |  | ||||||
|                     \n""", '', 'exec') |  | ||||||
|         d = {} |  | ||||||
|         exec co in d |  | ||||||
|         assert py.code.Source(d['f'])  |  | ||||||
|     finally: |  | ||||||
|         py.magic.revoke(compile=True) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|  | @ -1,31 +0,0 @@ | ||||||
| from py.test import raises |  | ||||||
| from py.magic import patch, revert |  | ||||||
| 
 |  | ||||||
| def test_patch_revert(): |  | ||||||
|     class a: |  | ||||||
|         pass |  | ||||||
|     raises(AttributeError, "patch(a, 'i', 42)") |  | ||||||
| 
 |  | ||||||
|     a.i = 42 |  | ||||||
|     patch(a, 'i', 23) |  | ||||||
|     assert a.i == 23 |  | ||||||
|     revert(a, 'i') |  | ||||||
|     assert a.i == 42 |  | ||||||
| 
 |  | ||||||
| def test_double_patch(): |  | ||||||
|     class a: |  | ||||||
|         i = 42 |  | ||||||
|     assert patch(a, 'i', 2) == 42 |  | ||||||
|     assert patch(a, 'i', 3) == 2 |  | ||||||
|     assert a.i == 3 |  | ||||||
|     assert revert(a, 'i') == 3 |  | ||||||
|     assert a.i == 2 |  | ||||||
|     assert revert(a, 'i') == 2 |  | ||||||
|     assert a.i == 42 |  | ||||||
| 
 |  | ||||||
| def test_valueerror(): |  | ||||||
|     class a: |  | ||||||
|         i = 2 |  | ||||||
|         pass |  | ||||||
|     raises(ValueError, "revert(a, 'i')") |  | ||||||
| 
 |  | ||||||
|  | @ -1,55 +0,0 @@ | ||||||
| from py.__.magic.viewtype import View |  | ||||||
| 
 |  | ||||||
| def test_class_dispatch(): |  | ||||||
|     ### Use a custom class hierarchy with existing instances |  | ||||||
| 
 |  | ||||||
|     class Picklable(View): |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
|     class Simple(Picklable): |  | ||||||
|         __view__ = object |  | ||||||
|         def pickle(self): |  | ||||||
|             return repr(self.__obj__) |  | ||||||
| 
 |  | ||||||
|     class Seq(Picklable): |  | ||||||
|         __view__ = list, tuple, dict |  | ||||||
|         def pickle(self): |  | ||||||
|             return ';'.join([Picklable(item).pickle() for item in self.__obj__]) |  | ||||||
| 
 |  | ||||||
|     class Dict(Seq): |  | ||||||
|         __view__ = dict |  | ||||||
|         def pickle(self): |  | ||||||
|             return Seq.pickle(self) + '!' + Seq(self.values()).pickle() |  | ||||||
| 
 |  | ||||||
|     assert Picklable(123).pickle() == '123' |  | ||||||
|     assert Picklable([1,[2,3],4]).pickle() == '1;2;3;4' |  | ||||||
|     assert Picklable({1:2}).pickle() == '1!2' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def test_custom_class_hierarchy(): |  | ||||||
|     ### Use a custom class hierarchy based on attributes of existing instances |  | ||||||
| 
 |  | ||||||
|     class Operation: |  | ||||||
|         "Existing class that I don't want to change." |  | ||||||
|         def __init__(self, opname, *args): |  | ||||||
|             self.opname = opname |  | ||||||
|             self.args = args |  | ||||||
| 
 |  | ||||||
|     existing = [Operation('+', 4, 5), |  | ||||||
|                 Operation('getitem', '', 'join'), |  | ||||||
|                 Operation('setattr', 'x', 'y', 3), |  | ||||||
|                 Operation('-', 12, 1)] |  | ||||||
| 
 |  | ||||||
|     class PyOp(View): |  | ||||||
|         def __viewkey__(self): |  | ||||||
|             return self.opname |  | ||||||
|         def generate(self): |  | ||||||
|             return '%s(%s)' % (self.opname, ', '.join(map(repr, self.args))) |  | ||||||
| 
 |  | ||||||
|     class PyBinaryOp(PyOp): |  | ||||||
|         __view__ = ('+', '-', '*', '/') |  | ||||||
|         def generate(self): |  | ||||||
|             return '%s %s %s' % (self.args[0], self.opname, self.args[1]) |  | ||||||
| 
 |  | ||||||
|     codelines = [PyOp(op).generate() for op in existing] |  | ||||||
|     assert codelines == ["4 + 5", "getitem('', 'join')", "setattr('x', 'y', 3)", "12 - 1"] |  | ||||||
|  | @ -1,94 +0,0 @@ | ||||||
| """ |  | ||||||
| The View base class for view-based programming. |  | ||||||
| 
 |  | ||||||
| A view of an object is an extension of this existing object. |  | ||||||
| This is useful to *locally* add methods or even attributes to objects |  | ||||||
| that you have obtained from elsewhere. |  | ||||||
| """ |  | ||||||
| from __future__ import generators |  | ||||||
| import inspect |  | ||||||
| 
 |  | ||||||
| class View(object): |  | ||||||
|     """View base class. |  | ||||||
| 
 |  | ||||||
|     If C is a subclass of View, then C(x) creates a proxy object around |  | ||||||
|     the object x.  The actual class of the proxy is not C in general, |  | ||||||
|     but a *subclass* of C determined by the rules below.  To avoid confusion |  | ||||||
|     we call view class the class of the proxy (a subclass of C, so of View) |  | ||||||
|     and object class the class of x. |  | ||||||
| 
 |  | ||||||
|     Attributes and methods not found in the proxy are automatically read on x. |  | ||||||
|     Other operations like setting attributes are performed on the proxy, as |  | ||||||
|     determined by its view class.  The object x is available from the proxy |  | ||||||
|     as its __obj__ attribute. |  | ||||||
| 
 |  | ||||||
|     The view class selection is determined by the __view__ tuples and the |  | ||||||
|     optional __viewkey__ method.  By default, the selected view class is the |  | ||||||
|     most specific subclass of C whose __view__ mentions the class of x. |  | ||||||
|     If no such subclass is found, the search proceeds with the parent |  | ||||||
|     object classes.  For example, C(True) will first look for a subclass |  | ||||||
|     of C with __view__ = (..., bool, ...) and only if it doesn't find any |  | ||||||
|     look for one with __view__ = (..., int, ...), and then ..., object,... |  | ||||||
|     If everything fails the class C itself is considered to be the default. |  | ||||||
| 
 |  | ||||||
|     Alternatively, the view class selection can be driven by another aspect |  | ||||||
|     of the object x, instead of the class of x, by overriding __viewkey__. |  | ||||||
|     See last example at the end of this module. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     _viewcache = {} |  | ||||||
|     __view__ = () |  | ||||||
| 
 |  | ||||||
|     def __new__(rootclass, obj, *args, **kwds): |  | ||||||
|         self = object.__new__(rootclass) |  | ||||||
|         self.__obj__ = obj |  | ||||||
|         self.__rootclass__ = rootclass |  | ||||||
|         key = self.__viewkey__() |  | ||||||
|         try: |  | ||||||
|             self.__class__ = self._viewcache[key] |  | ||||||
|         except KeyError: |  | ||||||
|             self.__class__ = self._selectsubclass(key) |  | ||||||
|         return self |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, attr): |  | ||||||
|         # attributes not found in the normal hierarchy rooted on View |  | ||||||
|         # are looked up in the object's real class |  | ||||||
|         return getattr(self.__obj__, attr) |  | ||||||
| 
 |  | ||||||
|     def __viewkey__(self): |  | ||||||
|         return self.__obj__.__class__ |  | ||||||
| 
 |  | ||||||
|     def __matchkey__(self, key, subclasses): |  | ||||||
|         if inspect.isclass(key): |  | ||||||
|             keys = inspect.getmro(key) |  | ||||||
|         else: |  | ||||||
|             keys = [key] |  | ||||||
|         for key in keys: |  | ||||||
|             result = [C for C in subclasses if key in C.__view__] |  | ||||||
|             if result: |  | ||||||
|                 return result |  | ||||||
|         return [] |  | ||||||
| 
 |  | ||||||
|     def _selectsubclass(self, key): |  | ||||||
|         subclasses = list(enumsubclasses(self.__rootclass__)) |  | ||||||
|         for C in subclasses: |  | ||||||
|             if not isinstance(C.__view__, tuple): |  | ||||||
|                 C.__view__ = (C.__view__,) |  | ||||||
|         choices = self.__matchkey__(key, subclasses) |  | ||||||
|         if not choices: |  | ||||||
|             return self.__rootclass__ |  | ||||||
|         elif len(choices) == 1: |  | ||||||
|             return choices[0] |  | ||||||
|         else: |  | ||||||
|             # combine the multiple choices |  | ||||||
|             return type('?', tuple(choices), {}) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def enumsubclasses(cls): |  | ||||||
|     for subcls in cls.__subclasses__(): |  | ||||||
|         for subsubclass in enumsubclasses(subcls): |  | ||||||
|             yield subsubclass |  | ||||||
|     yield cls |  | ||||||
|  | @ -5,7 +5,6 @@ import py | ||||||
| # | # | ||||||
| 
 | 
 | ||||||
| def main(args=None): | def main(args=None): | ||||||
|     warn_about_missing_assertion() |  | ||||||
|     if args is None: |     if args is None: | ||||||
|         args = py.std.sys.argv[1:] |         args = py.std.sys.argv[1:] | ||||||
|     config = py.test.config |     config = py.test.config | ||||||
|  | @ -20,11 +19,3 @@ def main(args=None): | ||||||
|         py.std.sys.stderr.write("ERROR: %s\n" %(e.args[0],)) |         py.std.sys.stderr.write("ERROR: %s\n" %(e.args[0],)) | ||||||
|         raise SystemExit(3) |         raise SystemExit(3) | ||||||
| 
 | 
 | ||||||
| def warn_about_missing_assertion(): |  | ||||||
|     try: |  | ||||||
|         assert False |  | ||||||
|     except AssertionError: |  | ||||||
|         pass |  | ||||||
|     else: |  | ||||||
|         py.std.warnings.warn("Assertions are turned off!" |  | ||||||
|                              " (are you using python -O?)") |  | ||||||
|  |  | ||||||
|  | @ -10,5 +10,5 @@ Generator = py.test.collect.Generator | ||||||
| Function = py.test.collect.Function | Function = py.test.collect.Function | ||||||
| Instance = py.test.collect.Instance | Instance = py.test.collect.Instance | ||||||
| 
 | 
 | ||||||
| pytest_plugins = "default runner capture terminal keyword xfail tmpdir execnetcleanup monkeypatch recwarn pdb pastebin unittest helpconfig nose".split() | pytest_plugins = "default runner capture terminal keyword xfail tmpdir execnetcleanup monkeypatch recwarn pdb pastebin unittest helpconfig nose assertion".split() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,68 @@ | ||||||
|  | import py | ||||||
|  | 
 | ||||||
|  | def pytest_addoption(parser): | ||||||
|  |     group = parser.getgroup("debugconfig") | ||||||
|  |     group._addoption('--no-assert', action="store_true", default=False,  | ||||||
|  |         dest="noassert",  | ||||||
|  |         help="disable python assert expression reinterpretation."), | ||||||
|  | 
 | ||||||
|  | def pytest_configure(config): | ||||||
|  |     if not config.getvalue("noassert"): | ||||||
|  |         warn_about_missing_assertion() | ||||||
|  |         config._oldassertion = py.std.__builtin__.AssertionError  | ||||||
|  |         py.std.__builtin__.AssertionError = py.code._AssertionError  | ||||||
|  | 
 | ||||||
|  | def pytest_unconfigure(config): | ||||||
|  |     if hasattr(config, '_oldassertion'): | ||||||
|  |         py.std.__builtin__.AssertionError = config._oldassertion | ||||||
|  |         del config._oldassertion | ||||||
|  | 
 | ||||||
|  | def warn_about_missing_assertion(): | ||||||
|  |     try: | ||||||
|  |         assert False | ||||||
|  |     except AssertionError: | ||||||
|  |         pass | ||||||
|  |     else: | ||||||
|  |         py.std.warnings.warn("Assertions are turned off!" | ||||||
|  |                              " (are you using python -O?)") | ||||||
|  | 
 | ||||||
|  | def test_functional(testdir): | ||||||
|  |     testdir.makepyfile(""" | ||||||
|  |         def test_hello(): | ||||||
|  |             x = 3 | ||||||
|  |             assert x == 4 | ||||||
|  |     """) | ||||||
|  |     result = testdir.runpytest() | ||||||
|  |     assert "3 == 4" in result.stdout.str()  | ||||||
|  |     result = testdir.runpytest("--no-assert") | ||||||
|  |     assert "3 == 4" not in result.stdout.str()  | ||||||
|  | 
 | ||||||
|  | def test_traceback_failure(testdir): | ||||||
|  |     p1 = testdir.makepyfile(""" | ||||||
|  |         def g(): | ||||||
|  |             return 2 | ||||||
|  |         def f(x): | ||||||
|  |             assert x == g() | ||||||
|  |         def test_onefails(): | ||||||
|  |             f(3) | ||||||
|  |     """) | ||||||
|  |     result = testdir.runpytest(p1) | ||||||
|  |     result.stdout.fnmatch_lines([ | ||||||
|  |         "*test_traceback_failure.py F",  | ||||||
|  |         "====* FAILURES *====", | ||||||
|  |         "____*____",  | ||||||
|  |         "", | ||||||
|  |         "    def test_onefails():", | ||||||
|  |         ">       f(3)", | ||||||
|  |         "", | ||||||
|  |         "*test_*.py:6: ", | ||||||
|  |         "_ _ _ *", | ||||||
|  |         #"", | ||||||
|  |         "    def f(x):", | ||||||
|  |         ">       assert x == g()", | ||||||
|  |         "E       assert 3 == 2", | ||||||
|  |         "E        +  where 2 = g()", | ||||||
|  |         "", | ||||||
|  |         "*test_traceback_failure.py:4: AssertionError" | ||||||
|  |     ]) | ||||||
|  | 
 | ||||||
|  | @ -564,36 +564,6 @@ class TestTerminalFunctional: | ||||||
|             "=* 1 passed in *.[0-9][0-9] seconds *=",  |             "=* 1 passed in *.[0-9][0-9] seconds *=",  | ||||||
|         ]) |         ]) | ||||||
| 
 | 
 | ||||||
|     def test_traceback_failure(self, testdir): |  | ||||||
|         p1 = testdir.makepyfile(""" |  | ||||||
|             def g(): |  | ||||||
|                 return 2 |  | ||||||
|             def f(x): |  | ||||||
|                 assert x == g() |  | ||||||
|             def test_onefails(): |  | ||||||
|                 f(3) |  | ||||||
|         """) |  | ||||||
|         result = testdir.runpytest(p1) |  | ||||||
|         result.stdout.fnmatch_lines([ |  | ||||||
|             "*test_traceback_failure.py F",  |  | ||||||
|             "====* FAILURES *====", |  | ||||||
|             "____*____",  |  | ||||||
|             "", |  | ||||||
|             "    def test_onefails():", |  | ||||||
|             ">       f(3)", |  | ||||||
|             "", |  | ||||||
|             "*test_*.py:6: ", |  | ||||||
|             "_ _ _ *", |  | ||||||
|             #"", |  | ||||||
|             "    def f(x):", |  | ||||||
|             ">       assert x == g()", |  | ||||||
|             "E       assert 3 == 2", |  | ||||||
|             "E        +  where 2 = g()", |  | ||||||
|             "", |  | ||||||
|             "*test_traceback_failure.py:4: AssertionError" |  | ||||||
|         ]) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     def test_showlocals(self, testdir):  |     def test_showlocals(self, testdir):  | ||||||
|         p1 = testdir.makepyfile(""" |         p1 = testdir.makepyfile(""" | ||||||
|             def test_showlocals(): |             def test_showlocals(): | ||||||
|  |  | ||||||
|  | @ -183,21 +183,13 @@ class Module(py.test.collect.File, PyCollectorMixin): | ||||||
|     def setup(self):  |     def setup(self):  | ||||||
|         if getattr(self.obj, 'disabled', 0): |         if getattr(self.obj, 'disabled', 0): | ||||||
|             py.test.skip("%r is disabled" %(self.obj,)) |             py.test.skip("%r is disabled" %(self.obj,)) | ||||||
|         if not self.config.option.nomagic: |  | ||||||
|             #print "*" * 20, "INVOKE assertion", self |  | ||||||
|             py.magic.invoke(assertion=1) |  | ||||||
|         mod = self.obj |         mod = self.obj | ||||||
|         #self.config.pluginmanager.register(mod) |  | ||||||
|         if hasattr(mod, 'setup_module'):  |         if hasattr(mod, 'setup_module'):  | ||||||
|             self.obj.setup_module(mod) |             self.obj.setup_module(mod) | ||||||
| 
 | 
 | ||||||
|     def teardown(self):  |     def teardown(self):  | ||||||
|         if hasattr(self.obj, 'teardown_module'):  |         if hasattr(self.obj, 'teardown_module'):  | ||||||
|             self.obj.teardown_module(self.obj)  |             self.obj.teardown_module(self.obj)  | ||||||
|         if not self.config.option.nomagic: |  | ||||||
|             #print "*" * 20, "revoke assertion", self |  | ||||||
|             py.magic.revoke(assertion=1) |  | ||||||
|         #self.config.pluginmanager.unregister(self.obj) |  | ||||||
| 
 | 
 | ||||||
| class Class(PyCollectorMixin, py.test.collect.Collector):  | class Class(PyCollectorMixin, py.test.collect.Collector):  | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -22,19 +22,6 @@ class TestModule: | ||||||
|         py.test.raises(SyntaxError, modcol.collect) |         py.test.raises(SyntaxError, modcol.collect) | ||||||
|         py.test.raises(SyntaxError, modcol.run) |         py.test.raises(SyntaxError, modcol.run) | ||||||
| 
 | 
 | ||||||
|     def test_module_assertion_setup(self, testdir, monkeypatch): |  | ||||||
|         modcol = testdir.getmodulecol("pass") |  | ||||||
|         from py.__.magic import assertion |  | ||||||
|         l = [] |  | ||||||
|         monkeypatch.setattr(assertion, "invoke", lambda: l.append(None)) |  | ||||||
|         modcol.setup() |  | ||||||
|         x = l.pop() |  | ||||||
|         assert x is None |  | ||||||
|         monkeypatch.setattr(assertion, "revoke", lambda: l.append(None)) |  | ||||||
|         modcol.teardown() |  | ||||||
|         x = l.pop() |  | ||||||
|         assert x is None |  | ||||||
| 
 |  | ||||||
|     def test_module_considers_pluginmanager_at_import(self, testdir): |     def test_module_considers_pluginmanager_at_import(self, testdir): | ||||||
|         modcol = testdir.getmodulecol("pytest_plugins='xasdlkj',") |         modcol = testdir.getmodulecol("pytest_plugins='xasdlkj',") | ||||||
|         py.test.raises(ImportError, "modcol.obj") |         py.test.raises(ImportError, "modcol.obj") | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue