[pypy-svn] r74597 - in pypy/branch/py131: lib-python py py/_cmdline py/_code py/_io py/_plugin py/_test

hpk at codespeak.net hpk at codespeak.net
Thu May 20 15:55:27 CEST 2010


Author: hpk
Date: Thu May 20 15:55:24 2010
New Revision: 74597

Removed:
   pypy/branch/py131/py/__init__.py.orig
   pypy/branch/py131/py/_plugin/pytest_pytester.py.orig
   pypy/branch/py131/py/_plugin/pytest_terminal.py.orig
Modified:
   pypy/branch/py131/lib-python/conftest.py
   pypy/branch/py131/py/__init__.py
   pypy/branch/py131/py/_builtin.py
   pypy/branch/py131/py/_cmdline/pytest.py
   pypy/branch/py131/py/_code/code.py
   pypy/branch/py131/py/_code/source.py
   pypy/branch/py131/py/_io/capture.py
   pypy/branch/py131/py/_plugin/pytest__pytest.py
   pypy/branch/py131/py/_plugin/pytest_capture.py
   pypy/branch/py131/py/_plugin/pytest_genscript.py
   pypy/branch/py131/py/_plugin/pytest_junitxml.py
   pypy/branch/py131/py/_plugin/pytest_resultlog.py
   pypy/branch/py131/py/_plugin/pytest_runner.py
   pypy/branch/py131/py/_plugin/pytest_skipping.py
   pypy/branch/py131/py/_plugin/pytest_terminal.py
   pypy/branch/py131/py/_test/cmdline.py
   pypy/branch/py131/py/_test/pycollect.py
Log:
upgrading to current py-trunk 1.3.1a1 series


Modified: pypy/branch/py131/lib-python/conftest.py
==============================================================================
--- pypy/branch/py131/lib-python/conftest.py	(original)
+++ pypy/branch/py131/lib-python/conftest.py	Thu May 20 15:55:24 2010
@@ -14,7 +14,6 @@
 
 # the following adds command line options as a side effect! 
 from pypy.conftest import gettestobjspace, option as pypy_option 
-from test import pystone
 
 from pypy.tool.pytest import appsupport 
 from pypy.tool.pytest.confpath import pypydir, libpythondir, \
@@ -40,6 +39,7 @@
 option = py.test.config.option 
 
 def gettimeout(): 
+    from test import pystone
     timeout = option.timeout.lower()
     if timeout.endswith('mp'): 
         megapystone = float(timeout[:-2])

Modified: pypy/branch/py131/py/__init__.py
==============================================================================
--- pypy/branch/py131/py/__init__.py	(original)
+++ pypy/branch/py131/py/__init__.py	Thu May 20 15:55:24 2010
@@ -8,7 +8,7 @@
 
 (c) Holger Krekel and others, 2004-2010
 """
-__version__ = version = "1.3.0"
+__version__ = version = "1.3.1a1"
 
 import py.apipkg
 
@@ -25,7 +25,6 @@
         'pytest':     '._cmdline.pytest:main',
         'pylookup':   '._cmdline.pylookup:main',
         'pycountloc': '._cmdline.pycountlog:main',
-        'pytest':     '._test.cmdline:main',
         'pylookup':   '._cmdline.pylookup:main',
         'pycountloc': '._cmdline.pycountloc:main',
         'pycleanup':  '._cmdline.pycleanup:main',

Modified: pypy/branch/py131/py/_builtin.py
==============================================================================
--- pypy/branch/py131/py/_builtin.py	(original)
+++ pypy/branch/py131/py/_builtin.py	Thu May 20 15:55:24 2010
@@ -151,7 +151,10 @@
         return getattr(function, "__dict__", None)
 
     def _getcode(function):
-        return getattr(function, "func_code", None)
+        try:
+            return getattr(function, "__code__")
+        except AttributeError:
+            return getattr(function, "func_code", None)
 
     def print_(*args, **kwargs):
         """ minimal backport of py3k print statement. """ 
@@ -175,6 +178,7 @@
 
     def exec_(obj, globals=None, locals=None):
         """ minimal backport of py3k exec statement. """ 
+        __tracebackhide__ = True
         if globals is None: 
             frame = sys._getframe(1)
             globals = frame.f_globals 
@@ -187,14 +191,17 @@
 if sys.version_info >= (3,0):
     exec ("""
 def _reraise(cls, val, tb):
+    __tracebackhide__ = True
     assert hasattr(val, '__traceback__')
     raise val
 """)
 else:
     exec ("""
 def _reraise(cls, val, tb):
+    __tracebackhide__ = True
     raise cls, val, tb
 def exec2(obj, globals, locals):
+    __tracebackhide__ = True
     exec obj in globals, locals 
 """)
 

Modified: pypy/branch/py131/py/_cmdline/pytest.py
==============================================================================
--- pypy/branch/py131/py/_cmdline/pytest.py	(original)
+++ pypy/branch/py131/py/_cmdline/pytest.py	Thu May 20 15:55:24 2010
@@ -1,5 +1,5 @@
 #!/usr/bin/env python 
 import py
 
-def main(args):
-    py.test.cmdline.main(args) 
+def main(args=None):
+    raise SystemExit(py.test.cmdline.main(args))

Modified: pypy/branch/py131/py/_code/code.py
==============================================================================
--- pypy/branch/py131/py/_code/code.py	(original)
+++ pypy/branch/py131/py/_code/code.py	Thu May 20 15:55:24 2010
@@ -23,64 +23,14 @@
     def __ne__(self, other):
         return not self == other
 
-    def new(self, rec=False, **kwargs): 
-        """ return new code object with modified attributes. 
-            if rec-cursive is true then dive into code 
-            objects contained in co_consts. 
-        """ 
-        if sys.platform.startswith("java"):
-            # XXX jython does not support the below co_filename hack
-            return self.raw 
-        names = [x for x in dir(self.raw) if x[:3] == 'co_']
-        for name in kwargs: 
-            if name not in names: 
-                raise TypeError("unknown code attribute: %r" %(name, ))
-        if rec and hasattr(self.raw, 'co_consts'):  # jython 
-            newconstlist = []
-            co = self.raw
-            cotype = type(co)
-            for c in co.co_consts:
-                if isinstance(c, cotype):
-                    c = self.__class__(c).new(rec=True, **kwargs) 
-                newconstlist.append(c)
-            return self.new(rec=False, co_consts=tuple(newconstlist), **kwargs) 
-        for name in names:
-            if name not in kwargs:
-                kwargs[name] = getattr(self.raw, name)
-        arglist = [
-                 kwargs['co_argcount'],
-                 kwargs['co_nlocals'],
-                 kwargs.get('co_stacksize', 0), # jython
-                 kwargs.get('co_flags', 0), # jython
-                 kwargs.get('co_code', ''), # jython
-                 kwargs.get('co_consts', ()), # jython
-                 kwargs.get('co_names', []), # 
-                 kwargs['co_varnames'],
-                 kwargs['co_filename'],
-                 kwargs['co_name'],
-                 kwargs['co_firstlineno'],
-                 kwargs.get('co_lnotab', ''), #jython
-                 kwargs.get('co_freevars', None), #jython
-                 kwargs.get('co_cellvars', None), # jython
-        ]
-        if sys.version_info >= (3,0):
-            arglist.insert(1, kwargs['co_kwonlyargcount'])
-            return self.raw.__class__(*arglist)
-        else:
-            return py.std.new.code(*arglist)
-
     def path(self):
         """ return a path object pointing to source code"""
-        fn = self.raw.co_filename 
-        try:
-            return fn.__path__
-        except AttributeError:
-            p = py.path.local(self.raw.co_filename)
-            if not p.check():
-                # XXX maybe try harder like the weird logic 
-                # in the standard lib [linecache.updatecache] does? 
-                p = self.raw.co_filename
-            return p
+        p = py.path.local(self.raw.co_filename)
+        if not p.check():
+            # XXX maybe try harder like the weird logic 
+            # in the standard lib [linecache.updatecache] does? 
+            p = self.raw.co_filename
+        return p
                 
     path = property(path, None, None, "path of this code object")
 

Modified: pypy/branch/py131/py/_code/source.py
==============================================================================
--- pypy/branch/py131/py/_code/source.py	(original)
+++ pypy/branch/py131/py/_code/source.py	Thu May 20 15:55:24 2010
@@ -2,6 +2,7 @@
 import sys
 import inspect, tokenize
 import py
+from types import ModuleType
 cpy_compile = compile 
 
 try:
@@ -212,10 +213,17 @@
         else:
             if flag & _AST_FLAG:
                 return co
-            co_filename = MyStr(filename)
-            co_filename.__source__ = self
-            return py.code.Code(co).new(rec=1, co_filename=co_filename) 
-            #return newcode_withfilename(co, co_filename)
+            lines = [(x + "\n") for x in self.lines]
+            if sys.version_info[0] >= 3:
+                # XXX py3's inspect.getsourcefile() checks for a module
+                # and a pep302 __loader__ ... we don't have a module
+                # at code compile-time so we need to fake it here
+                m = ModuleType("_pycodecompile_pseudo_module")
+                py.std.inspect.modulesbyfile[filename] = None
+                py.std.sys.modules[None] = m
+                m.__loader__ = 1
+            py.std.linecache.cache[filename] = (1, None, lines, filename)
+            return co
 
 #
 # public API shortcut functions
@@ -224,11 +232,9 @@
 def compile_(source, filename=None, mode='exec', flags=
             generators.compiler_flag, dont_inherit=0):
     """ compile the given source to a raw code object,
-        which points back to the source code through
-        "co_filename.__source__".  All code objects
-        contained in the code object will recursively
-        also have this special subclass-of-string
-        filename.
+        and maintain an internal cache which allows later
+        retrieval of the source code for the code object 
+        and any recursively created code objects. 
     """
     if _ast is not None and isinstance(source, _ast.AST):
         # XXX should Source support having AST?
@@ -262,44 +268,26 @@
 #
 # helper functions
 #
-class MyStr(str):
-    """ custom string which allows to add attributes. """
 
 def findsource(obj):
-    obj = py.code.getrawcode(obj)
     try:
-        fullsource = obj.co_filename.__source__
-    except AttributeError:
-        try:
-            sourcelines, lineno = py.std.inspect.findsource(obj)
-        except (KeyboardInterrupt, SystemExit):
-            raise
-        except:
-            return None, None
-        source = Source()
-        source.lines = [line.rstrip() for line in sourcelines]
-        return source, lineno
-    else:
-        lineno = obj.co_firstlineno - 1        
-        return fullsource, lineno
-
+        sourcelines, lineno = py.std.inspect.findsource(obj)
+    except (KeyboardInterrupt, SystemExit):
+        raise
+    except:
+        return None, None
+    source = Source()
+    source.lines = [line.rstrip() for line in sourcelines]
+    return source, lineno
 
 def getsource(obj, **kwargs):
     obj = py.code.getrawcode(obj)
     try:
-        fullsource = obj.co_filename.__source__
-    except AttributeError:
-        try:
-            strsrc = inspect.getsource(obj)
-        except IndentationError:
-            strsrc = "\"Buggy python version consider upgrading, cannot get source\""
-        assert isinstance(strsrc, str)
-        return Source(strsrc, **kwargs)
-    else:
-        lineno = obj.co_firstlineno - 1
-        end = fullsource.getblockend(lineno)
-        return Source(fullsource[lineno:end+1], deident=True)
-
+        strsrc = inspect.getsource(obj)
+    except IndentationError:
+        strsrc = "\"Buggy python version consider upgrading, cannot get source\""
+    assert isinstance(strsrc, str)
+    return Source(strsrc, **kwargs)
 
 def deindent(lines, offset=None):
     if offset is None:

Modified: pypy/branch/py131/py/_io/capture.py
==============================================================================
--- pypy/branch/py131/py/_io/capture.py	(original)
+++ pypy/branch/py131/py/_io/capture.py	Thu May 20 15:55:24 2010
@@ -26,46 +26,56 @@
                 raise TypeError("not a byte value: %r" %(data,))
             StringIO.write(self, data)
 
+patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'}
+
 class FDCapture: 
     """ Capture IO to/from a given os-level filedescriptor. """
     
-    def __init__(self, targetfd, tmpfile=None): 
+    def __init__(self, targetfd, tmpfile=None, now=True, patchsys=False):
         """ save targetfd descriptor, and open a new 
             temporary file there.  If no tmpfile is 
             specified a tempfile.Tempfile() will be opened
             in text mode. 
         """
         self.targetfd = targetfd
-        if tmpfile is None: 
+        if tmpfile is None and targetfd != 0:
             f = tempfile.TemporaryFile('wb+')
             tmpfile = dupfile(f, encoding="UTF-8") 
             f.close()
         self.tmpfile = tmpfile 
-        self._savefd = os.dup(targetfd)
-        os.dup2(self.tmpfile.fileno(), targetfd) 
-        self._patched = []
-
-    def setasfile(self, name, module=sys): 
-        """ patch <module>.<name> to self.tmpfile
-        """
-        key = (module, name)
-        self._patched.append((key, getattr(module, name)))
-        setattr(module, name, self.tmpfile) 
+        self._savefd = os.dup(self.targetfd)
+        if patchsys:
+            self._oldsys = getattr(sys, patchsysdict[targetfd])
+        if now:
+            self.start()
 
-    def unsetfiles(self): 
-        """ unpatch all patched items
-        """
-        while self._patched: 
-            (module, name), value = self._patched.pop()
-            setattr(module, name, value) 
+    def start(self):
+        try:
+            os.fstat(self._savefd)
+        except OSError:
+            raise ValueError("saved filedescriptor not valid, "
+                "did you call start() twice?")
+        if self.targetfd == 0 and not self.tmpfile:
+            fd = os.open(devnullpath, os.O_RDONLY)
+            os.dup2(fd, 0)
+            os.close(fd)
+            if hasattr(self, '_oldsys'):
+                setattr(sys, patchsysdict[self.targetfd], DontReadFromInput())
+        else:
+            fd = self.tmpfile.fileno()
+            os.dup2(self.tmpfile.fileno(), self.targetfd) 
+            if hasattr(self, '_oldsys'):
+                setattr(sys, patchsysdict[self.targetfd], self.tmpfile)
 
     def done(self): 
         """ unpatch and clean up, returns the self.tmpfile (file object)
         """
         os.dup2(self._savefd, self.targetfd) 
-        self.unsetfiles() 
         os.close(self._savefd) 
-        self.tmpfile.seek(0)
+        if self.targetfd != 0:
+            self.tmpfile.seek(0)
+        if hasattr(self, '_oldsys'):
+            setattr(sys, patchsysdict[self.targetfd], self._oldsys)
         return self.tmpfile 
 
     def writeorg(self, data):
@@ -100,7 +110,7 @@
         if encoding is not None:
             mode = mode.replace("b", "")
             buffering = True
-        return os.fdopen(newfd, mode, buffering, encoding, closefd=False)
+        return os.fdopen(newfd, mode, buffering, encoding, closefd=True)
     else:
         f = os.fdopen(newfd, mode, buffering) 
         if encoding is not None:
@@ -146,90 +156,94 @@
 
     def reset(self):
         """ reset sys.stdout/stderr and return captured output as strings. """
-        if hasattr(self, '_suspended'):
-            outfile = self._kwargs['out']
-            errfile = self._kwargs['err']
-            del self._kwargs
-        else:
-            outfile, errfile = self.done() 
+        outfile, errfile = self.done() 
         out, err = "", ""
-        if outfile:
+        if outfile and not outfile.closed:
             out = outfile.read()
             outfile.close()
-        if errfile and errfile != outfile:
+        if errfile and errfile != outfile and not errfile.closed:
             err = errfile.read()
             errfile.close()
         return out, err
 
     def suspend(self):
         """ return current snapshot captures, memorize tempfiles. """
-        assert not hasattr(self, '_suspended')
-        self._suspended = True
         outerr = self.readouterr()
         outfile, errfile = self.done()
-        self._kwargs['out'] = outfile
-        self._kwargs['err'] = errfile
         return outerr
 
-    def resume(self):
-        """ resume capturing with original temp files. """
-        assert self._suspended
-        self._initialize(**self._kwargs)
-        del self._suspended
-
 
 class StdCaptureFD(Capture): 
     """ This class allows to capture writes to FD1 and FD2 
         and may connect a NULL file to FD0 (and prevent
-        reads from sys.stdin)
+        reads from sys.stdin).  If any of the 0,1,2 file descriptors 
+        is invalid it will not be captured. 
     """
-    def __init__(self, out=True, err=True, 
-                 mixed=False, in_=True, patchsys=True): 
-        self._kwargs = locals().copy()
-        del self._kwargs['self']
-        self._initialize(**self._kwargs)
-
-    def _initialize(self, out=True, err=True, 
-                    mixed=False, in_=True, patchsys=True): 
+    def __init__(self, out=True, err=True, mixed=False, 
+        in_=True, patchsys=True, now=True):
+        self._options = locals()
+        self._save()
+        if now:
+            self.startall()
+
+    def _save(self):
+        in_ = self._options['in_']
+        out = self._options['out']
+        err = self._options['err']
+        mixed = self._options['mixed']
+        patchsys = self._options['patchsys']
         if in_:
-            self._oldin = (sys.stdin, os.dup(0))
-            sys.stdin  = DontReadFromInput()
-            fd = os.open(devnullpath, os.O_RDONLY)
-            os.dup2(fd, 0)
-            os.close(fd)
-        if out: 
+            try:
+                self.in_ = FDCapture(0, tmpfile=None, now=False,
+                    patchsys=patchsys)
+            except OSError:
+                pass 
+        if out:
             tmpfile = None
             if hasattr(out, 'write'):
                 tmpfile = out
-            self.out = py.io.FDCapture(1, tmpfile=tmpfile)
-            if patchsys: 
-                self.out.setasfile('stdout')
-        if err: 
-            if mixed and out:
+            try:
+                self.out = FDCapture(1, tmpfile=tmpfile, 
+                           now=False, patchsys=patchsys)
+                self._options['out'] = self.out.tmpfile
+            except OSError:
+                pass 
+        if err:
+            if out and mixed:
                 tmpfile = self.out.tmpfile 
             elif hasattr(err, 'write'):
                 tmpfile = err
             else:
                 tmpfile = None
-            self.err = py.io.FDCapture(2, tmpfile=tmpfile) 
-            if patchsys: 
-                self.err.setasfile('stderr')
+            try:
+                self.err = FDCapture(2, tmpfile=tmpfile, 
+                           now=False, patchsys=patchsys) 
+                self._options['err'] = self.err.tmpfile
+            except OSError:
+                pass 
+
+    def startall(self):
+        if hasattr(self, 'in_'):
+            self.in_.start()
+        if hasattr(self, 'out'):
+            self.out.start()
+        if hasattr(self, 'err'):
+            self.err.start()
+
+    def resume(self):
+        """ resume capturing with original temp files. """
+        self.startall()
 
     def done(self):
         """ return (outfile, errfile) and stop capturing. """
-        if hasattr(self, 'out'): 
+        outfile = errfile = None
+        if hasattr(self, 'out') and not self.out.tmpfile.closed:
             outfile = self.out.done() 
-        else:
-            outfile = None
-        if hasattr(self, 'err'): 
+        if hasattr(self, 'err') and not self.err.tmpfile.closed:
             errfile = self.err.done() 
-        else:
-            errfile = None 
-        if hasattr(self, '_oldin'):
-            oldsys, oldfd = self._oldin 
-            os.dup2(oldfd, 0)
-            os.close(oldfd)
-            sys.stdin = oldsys 
+        if hasattr(self, 'in_'):
+            tmpfile = self.in_.done()
+        self._save()
         return outfile, errfile 
 
     def readouterr(self):
@@ -252,69 +266,61 @@
         modifies sys.stdout|stderr|stdin attributes and does not 
         touch underlying File Descriptors (use StdCaptureFD for that). 
     """
-    def __init__(self, out=True, err=True, in_=True, mixed=False):
-        self._kwargs = locals().copy()
-        del self._kwargs['self']
-        self._initialize(**self._kwargs)
-
-    def _initialize(self, out, err, in_, mixed):
-        self._out = out
-        self._err = err 
-        self._in = in_
-        if out: 
-            self._oldout = sys.stdout
-            if not hasattr(out, 'write'):
-                out = TextIO()
-            sys.stdout = self.out = out
-        if err: 
-            self._olderr = sys.stderr
-            if out and mixed: 
-                err = self.out 
+    def __init__(self, out=True, err=True, in_=True, mixed=False, now=True):
+        self._oldout = sys.stdout
+        self._olderr = sys.stderr
+        self._oldin  = sys.stdin
+        if out and not hasattr(out, 'file'):
+            out = TextIO()
+        self.out = out
+        if err:
+            if mixed:
+                err = out
             elif not hasattr(err, 'write'):
                 err = TextIO()
-            sys.stderr = self.err = err
-        if in_:
-            self._oldin  = sys.stdin
-            sys.stdin  = self.newin  = DontReadFromInput()
+        self.err = err
+        self.in_ = in_
+        if now:
+            self.startall()
+
+    def startall(self):
+        if self.out: 
+            sys.stdout = self.out
+        if self.err: 
+            sys.stderr = self.err
+        if self.in_:
+            sys.stdin  = self.in_  = DontReadFromInput()
 
     def done(self): 
         """ return (outfile, errfile) and stop capturing. """
-        o,e = sys.stdout, sys.stderr
-        if self._out: 
-            try:
-                sys.stdout = self._oldout 
-            except AttributeError:
-                raise IOError("stdout capturing already reset")
-            del self._oldout
+        outfile = errfile = None
+        if self.out and not self.out.closed:
+            sys.stdout = self._oldout 
             outfile = self.out
             outfile.seek(0)
-        else:
-            outfile = None
-        if self._err: 
-            try:
-                sys.stderr = self._olderr 
-            except AttributeError:
-                raise IOError("stderr capturing already reset")
-            del self._olderr 
+        if self.err and not self.err.closed: 
+            sys.stderr = self._olderr 
             errfile = self.err 
             errfile.seek(0)
-        else:
-            errfile = None
-        if self._in:
+        if self.in_:
             sys.stdin = self._oldin 
         return outfile, errfile
 
+    def resume(self):
+        """ resume capturing with original temp files. """
+        self.startall()
+
     def readouterr(self):
         """ return snapshot value of stdout/stderr capturings. """
         out = err = ""
-        if self._out:
-            out = sys.stdout.getvalue()
-            sys.stdout.truncate(0)
-            sys.stdout.seek(0)
-        if self._err:
-            err = sys.stderr.getvalue()
-            sys.stderr.truncate(0)
-            sys.stderr.seek(0)
+        if self.out:
+            out = self.out.getvalue()
+            self.out.truncate(0)
+            self.out.seek(0)
+        if self.err:
+            err = self.err.getvalue()
+            self.err.truncate(0)
+            self.err.seek(0)
         return out, err 
 
 class DontReadFromInput:
@@ -344,5 +350,3 @@
         devnullpath = 'NUL'
     else:
         devnullpath = '/dev/null'
-
-

Modified: pypy/branch/py131/py/_plugin/pytest__pytest.py
==============================================================================
--- pypy/branch/py131/py/_plugin/pytest__pytest.py	(original)
+++ pypy/branch/py131/py/_plugin/pytest__pytest.py	Thu May 20 15:55:24 2010
@@ -46,7 +46,8 @@
             recorder = RecordCalls()
             self._recorders[hookspec] = recorder
             self._registry.register(recorder)
-        self.hook = HookRelay(hookspecs, registry=self._registry)
+        self.hook = HookRelay(hookspecs, registry=self._registry, 
+            prefix="pytest_")
 
     def finish_recording(self):
         for recorder in self._recorders.values():

Modified: pypy/branch/py131/py/_plugin/pytest_capture.py
==============================================================================
--- pypy/branch/py131/py/_plugin/pytest_capture.py	(original)
+++ pypy/branch/py131/py/_plugin/pytest_capture.py	Thu May 20 15:55:24 2010
@@ -106,6 +106,14 @@
 def pytest_configure(config):
     config.pluginmanager.register(CaptureManager(), 'capturemanager')
 
+class NoCapture:
+    def startall(self):
+        pass
+    def resume(self):
+        pass
+    def suspend(self):
+        return "", ""
+
 class CaptureManager:
     def __init__(self):
         self._method2capture = {}
@@ -118,15 +126,17 @@
     def _makestringio(self):
         return py.io.TextIO() 
 
-    def _startcapture(self, method):
+    def _getcapture(self, method):
         if method == "fd": 
-            return py.io.StdCaptureFD(
+            return py.io.StdCaptureFD(now=False,
                 out=self._maketempfile(), err=self._maketempfile()
             )
         elif method == "sys":
-            return py.io.StdCapture(
+            return py.io.StdCapture(now=False,
                 out=self._makestringio(), err=self._makestringio()
             )
+        elif method == "no":
+            return NoCapture()
         else:
             raise ValueError("unknown capturing method: %r" % method)
 
@@ -152,27 +162,25 @@
         if hasattr(self, '_capturing'):
             raise ValueError("cannot resume, already capturing with %r" % 
                 (self._capturing,))
-        if method != "no":
-            cap = self._method2capture.get(method)
-            if cap is None:
-                cap = self._startcapture(method)
-                self._method2capture[method] = cap 
-            else:
-                cap.resume()
+        cap = self._method2capture.get(method)
         self._capturing = method 
+        if cap is None:
+            self._method2capture[method] = cap = self._getcapture(method)
+            cap.startall()
+        else:
+            cap.resume()
 
     def suspendcapture(self, item=None):
         self.deactivate_funcargs()
         if hasattr(self, '_capturing'):
             method = self._capturing
-            if method != "no":
-                cap = self._method2capture[method]
+            cap = self._method2capture.get(method)
+            if cap is not None:
                 outerr = cap.suspend()
-            else:
-                outerr = "", ""
             del self._capturing
             if item:
-                outerr = (item.outerr[0] + outerr[0], item.outerr[1] + outerr[1])
+                outerr = (item.outerr[0] + outerr[0], 
+                          item.outerr[1] + outerr[1])
             return outerr 
         return "", ""
 
@@ -180,19 +188,17 @@
         if not hasattr(pyfuncitem, 'funcargs'):
             return
         assert not hasattr(self, '_capturing_funcargs')
-        l = []
-        for name, obj in pyfuncitem.funcargs.items():
-            if name == 'capfd' and not hasattr(os, 'dup'):
-                py.test.skip("capfd funcarg needs os.dup")
+        self._capturing_funcargs = capturing_funcargs = []
+        for name, capfuncarg in pyfuncitem.funcargs.items():
             if name in ('capsys', 'capfd'):
-                obj._start()
-                l.append(obj)
-        if l:
-            self._capturing_funcargs = l
+                capturing_funcargs.append(capfuncarg)
+                capfuncarg._start()
 
     def deactivate_funcargs(self):
-        if hasattr(self, '_capturing_funcargs'):
-            for capfuncarg in self._capturing_funcargs:
+        capturing_funcargs = getattr(self, '_capturing_funcargs', None)
+        if capturing_funcargs is not None:
+            while capturing_funcargs:
+                capfuncarg = capturing_funcargs.pop()
                 capfuncarg._finalize()
             del self._capturing_funcargs
 
@@ -256,16 +262,19 @@
     platform does not have ``os.dup`` (e.g. Jython) tests using
     this funcarg will automatically skip. 
     """ 
+    if not hasattr(os, 'dup'):
+        py.test.skip("capfd funcarg needs os.dup")
     return CaptureFuncarg(request, py.io.StdCaptureFD)
 
 
 class CaptureFuncarg:
     def __init__(self, request, captureclass):
         self._cclass = captureclass
+        self.capture = self._cclass(now=False)
         #request.addfinalizer(self._finalize)
 
     def _start(self):
-        self.capture = self._cclass()
+        self.capture.startall()
 
     def _finalize(self):
         if hasattr(self, 'capture'):
@@ -276,6 +285,4 @@
         return self.capture.readouterr()
 
     def close(self):
-        self.capture.reset()
-        del self.capture
-
+        self._finalize()

Modified: pypy/branch/py131/py/_plugin/pytest_genscript.py
==============================================================================
--- pypy/branch/py131/py/_plugin/pytest_genscript.py	(original)
+++ pypy/branch/py131/py/_plugin/pytest_genscript.py	Thu May 20 15:55:24 2010
@@ -4,14 +4,7 @@
 """
 
 import os
-import zlib
-import base64
 import sys
-try:
-    import pickle
-except Importerror:
-    import cPickle as pickle
-
 def pytest_addoption(parser):
     group = parser.getgroup("debugconfig")
     group.addoption("--genscript", action="store", default=None, 
@@ -30,6 +23,13 @@
         raise SystemExit(0)
 
 def main(pybasedir, outfile, infile):
+    import base64
+    import zlib
+    try:
+        import pickle
+    except Importerror:
+        import cPickle as pickle
+
     outfile = str(outfile)
     infile = str(infile)
     assert os.path.isabs(outfile)

Modified: pypy/branch/py131/py/_plugin/pytest_junitxml.py
==============================================================================
--- pypy/branch/py131/py/_plugin/pytest_junitxml.py	(original)
+++ pypy/branch/py131/py/_plugin/pytest_junitxml.py	Thu May 20 15:55:24 2010
@@ -56,10 +56,15 @@
     def append_failure(self, report):
         self._opentestcase(report)
         #msg = str(report.longrepr.reprtraceback.extraline)
-        self.appendlog('<failure message="test failure">%s</failure>', 
-            report.longrepr)
+        if "xfail" in report.keywords:
+            self.appendlog(
+                '<skipped message="xfail-marked test passes unexpectedly"/>')
+            self.skipped += 1
+        else:
+            self.appendlog('<failure message="test failure">%s</failure>', 
+                report.longrepr)
+            self.failed += 1
         self._closetestcase()
-        self.failed += 1
 
     def _opentestcase_collectfailure(self, report):
         node = report.collector
@@ -95,7 +100,12 @@
 
     def append_skipped(self, report):
         self._opentestcase(report)
-        self.appendlog("<skipped/>")
+        if "xfail" in report.keywords:
+            self.appendlog(
+                '<skipped message="expected test failure">%s</skipped>', 
+                report.keywords['xfail'])
+        else:
+            self.appendlog("<skipped/>")
         self._closetestcase()
         self.skipped += 1
 

Modified: pypy/branch/py131/py/_plugin/pytest_resultlog.py
==============================================================================
--- pypy/branch/py131/py/_plugin/pytest_resultlog.py	(original)
+++ pypy/branch/py131/py/_plugin/pytest_resultlog.py	Thu May 20 15:55:24 2010
@@ -73,7 +73,7 @@
             code = report.shortrepr
         if code == 'x':
             longrepr = str(report.longrepr)
-        elif code == 'P':
+        elif code == 'X':
             longrepr = ''
         elif report.passed:
             longrepr = ""

Modified: pypy/branch/py131/py/_plugin/pytest_runner.py
==============================================================================
--- pypy/branch/py131/py/_plugin/pytest_runner.py	(original)
+++ pypy/branch/py131/py/_plugin/pytest_runner.py	Thu May 20 15:55:24 2010
@@ -10,6 +10,7 @@
         'skip'         : skip,
         'importorskip' : importorskip,
         'fail'         : fail, 
+        'xfail'        : xfail, 
         'exit'         : exit, 
     }
 
@@ -295,6 +296,10 @@
     """ raised from an explicit call to py.test.fail() """
     __module__ = 'builtins'
 
+class XFailed(OutcomeException): 
+    """ raised from an explicit call to py.test.xfail() """
+    __module__ = 'builtins'
+
 class ExceptionFailure(Failed): 
     """ raised by py.test.raises on an exception-assertion mismatch. """
     def __init__(self, expr, expected, msg=None, excinfo=None): 
@@ -335,6 +340,14 @@
 
 fail.Exception = Failed
 
+def xfail(reason=""):
+    """ xfail an executing test or setup functions, taking an optional 
+    reason string.
+    """
+    __tracebackhide__ = True
+    raise XFailed(reason)
+xfail.Exception = XFailed
+
 def raises(ExpectedException, *args, **kwargs):
     """ if args[0] is callable: raise AssertionError if calling it with 
         the remaining arguments does not raise the expected exception.  

Modified: pypy/branch/py131/py/_plugin/pytest_skipping.py
==============================================================================
--- pypy/branch/py131/py/_plugin/pytest_skipping.py	(original)
+++ pypy/branch/py131/py/_plugin/pytest_skipping.py	Thu May 20 15:55:24 2010
@@ -82,10 +82,17 @@
 depending on platform::
 
     @py.test.mark.xfail("sys.version_info >= (3,0)")
-
     def test_function():
         ...
 
+To not run a test and still regard it as "xfailed"::
+
+    @py.test.mark.xfail(..., run=False)
+
+To specify an explicit reason to be shown with xfailure detail::
+
+    @py.test.mark.xfail(..., reason="my reason")
+
 
 skipping on a missing import dependency
 --------------------------------------------------
@@ -115,11 +122,14 @@
             py.test.skip("unsuppored configuration")
 
 """
-# XXX py.test.skip, .importorskip and the Skipped class 
-# should also be defined in this plugin, requires thought/changes
 
 import py
 
+def pytest_addoption(parser):
+    group = parser.getgroup("general")
+    group.addoption('--runxfail', 
+           action="store_true", dest="runxfail", default=False,
+           help="run tests even if they are marked xfail")
 
 class MarkEvaluator:
     def __init__(self, item, name):
@@ -161,27 +171,53 @@
         
 
 def pytest_runtest_setup(item):
-    expr, result = evalexpression(item, 'skipif')
-    if result:
-        py.test.skip(expr)
+    if not isinstance(item, py.test.collect.Function):
+        return
+    evalskip = MarkEvaluator(item, 'skipif')
+    if evalskip.istrue():
+        py.test.skip(evalskip.getexplanation())
+    item._evalxfail = MarkEvaluator(item, 'xfail')
+    if not item.config.getvalue("runxfail"):
+        if item._evalxfail.istrue():
+            if not item._evalxfail.get('run', True):
+                py.test.skip("xfail")
 
 def pytest_runtest_makereport(__multicall__, item, call):
-    if call.when != "call":
+    if not isinstance(item, py.test.collect.Function):
         return
-    expr, result = evalexpression(item, 'xfail')
-    rep = __multicall__.execute()
-    if result:
-        if call.excinfo:
-            rep.skipped = True
-            rep.failed = rep.passed = False
+    if not (call.excinfo and 
+        call.excinfo.errisinstance(py.test.xfail.Exception)):
+        evalxfail = getattr(item, '_evalxfail', None)
+        if not evalxfail:
+            return
+    if call.excinfo and call.excinfo.errisinstance(py.test.xfail.Exception):
+        rep = __multicall__.execute()
+        rep.keywords['xfail'] = "reason: " + call.excinfo.value.msg
+        rep.skipped = True
+        rep.failed = False
+        return rep
+    if call.when == "setup":
+        rep = __multicall__.execute()
+        if rep.skipped and evalxfail.istrue():
+            expl = evalxfail.getexplanation()
+            if not evalxfail.get("run", True):
+                expl = "[NOTRUN] " + expl
+            rep.keywords['xfail'] = expl
+        return rep
+    elif call.when == "call":
+        rep = __multicall__.execute()
+        if not item.config.getvalue("runxfail") and evalxfail.istrue():
+            if call.excinfo:
+                rep.skipped = True
+                rep.failed = rep.passed = False
+            else:
+                rep.skipped = rep.passed = False
+                rep.failed = True
+            rep.keywords['xfail'] = evalxfail.getexplanation()
         else:
-            rep.skipped = rep.passed = False
-            rep.failed = True
-        rep.keywords['xfail'] = expr 
-    else:
-        if 'xfail' in rep.keywords:
-            del rep.keywords['xfail']
-    return rep
+            if 'xfail' in rep.keywords:
+                del rep.keywords['xfail']
+        return rep
 
 # called by terminalreporter progress reporting
 def pytest_report_teststatus(report):
@@ -189,7 +225,7 @@
         if report.skipped:
             return "xfailed", "x", "xfail"
         elif report.failed:
-            return "xpassed", "P", "xpass"
+            return "xpassed", "X", "XPASS"
 
 # called by the terminalreporter instance/plugin
 def pytest_terminal_summary(terminalreporter):
@@ -229,13 +265,8 @@
     xfailed = terminalreporter.stats.get("xfailed")
     if xfailed:
         for rep in xfailed:
-            entry = rep.longrepr.reprcrash
-            modpath = rep.item.getmodpath(includemodule=True)
-            pos = "%s %s:%d: " %(modpath, entry.path, entry.lineno)
-            reason = rep.longrepr.reprcrash.message
-            i = reason.find("\n")
-            if i != -1:
-                reason = reason[:i]
+            pos = terminalreporter.gettestid(rep.item)
+            reason = rep.keywords['xfail']
             lines.append("XFAIL %s %s" %(pos, reason))
 
 def show_xpassed(terminalreporter, lines):
@@ -246,24 +277,6 @@
             reason = rep.keywords['xfail']
             lines.append("XPASS %s %s" %(pos, reason))
 
-
-def evalexpression(item, keyword):
-    if isinstance(item, py.test.collect.Function):
-        markholder = getattr(item.obj, keyword, None)
-        result = False
-        if markholder:
-            d = {'os': py.std.os, 'sys': py.std.sys, 'config': item.config}
-            expr, result = None, True
-            for expr in markholder.args:
-                if isinstance(expr, str):
-                    result = cached_eval(item.config, expr, d)
-                else:
-                    result = expr
-                if not result:
-                    break
-            return expr, result
-    return None, False
-
 def cached_eval(config, expr, d):
     if not hasattr(config, '_evalcache'):
         config._evalcache = {}

Modified: pypy/branch/py131/py/_plugin/pytest_terminal.py
==============================================================================
--- pypy/branch/py131/py/_plugin/pytest_terminal.py	(original)
+++ pypy/branch/py131/py/_plugin/pytest_terminal.py	Thu May 20 15:55:24 2010
@@ -141,6 +141,20 @@
         else: 
             return "???", dict(red=True)
 
+    def gettestid(self, item, relative=True):
+        fspath = item.fspath
+        chain = [x for x in item.listchain() if x.fspath == fspath]
+        chain = chain[1:]
+        names = [x.name for x in chain if x.name != "()"]
+        path = item.fspath
+        if relative:
+            relpath = path.relto(self.curdir)
+            if relpath:
+                path = relpath
+        names.insert(0, str(path))
+        return "::".join(names)
+
+
     def pytest_internalerror(self, excrepr):
         for line in str(excrepr).split("\n"):
             self.write_line("INTERNALERROR> " + line)

Modified: pypy/branch/py131/py/_test/cmdline.py
==============================================================================
--- pypy/branch/py131/py/_test/cmdline.py	(original)
+++ pypy/branch/py131/py/_test/cmdline.py	Thu May 20 15:55:24 2010
@@ -16,8 +16,9 @@
         colitems = config.getinitialnodes()
         exitstatus = session.main(colitems)
         config.pluginmanager.do_unconfigure(config)
-        raise SystemExit(exitstatus)
     except config.Error:
         e = sys.exc_info()[1]
         sys.stderr.write("ERROR: %s\n" %(e.args[0],))
-        raise SystemExit(3)
+        exitstatus = 3
+    py.test.config = py.test.config.__class__()
+    return exitstatus

Modified: pypy/branch/py131/py/_test/pycollect.py
==============================================================================
--- pypy/branch/py131/py/_test/pycollect.py	(original)
+++ pypy/branch/py131/py/_test/pycollect.py	Thu May 20 15:55:24 2010
@@ -393,5 +393,5 @@
 def hasinit(obj):
     init = getattr(obj, '__init__', None)
     if init:
-        if not isinstance(init, type(object.__init__)):
+        if init != object.__init__:
             return True



More information about the Pypy-commit mailing list