[pypy-svn] rev 1103 - in pypy/trunk/src/pypy: interpreter tool
mwh at codespeak.net
mwh at codespeak.net
Mon Jul 7 18:10:03 CEST 2003
Author: mwh
Date: Mon Jul 7 18:10:02 2003
New Revision: 1103
Added:
pypy/trunk/src/pypy/tool/ppdb.py
pypy/trunk/src/pypy/tool/testpm.py
Modified:
pypy/trunk/src/pypy/interpreter/unittest_w.py
pypy/trunk/src/pypy/tool/option.py
pypy/trunk/src/pypy/tool/test.py
Log:
Some fairly extensive changes to the test rig.
There are two conceptual changes, but they are two textually entangled
to be easily checked in separately :-(
The first change is allowing a test to skip, by raising a
pypy.tool.test.TestSkip exception.
test.objspace() raises TestSkip if it is asked for a specific flavour
of object space and that differs from the specific flavour of object
space that is being tested (as controlled by command-line arguments).
This change is all of the changes to interpreter/unittest_w.py and
some of the work in tool/test.py.
The other change is a new option (-k, for no good reason other than -i
already being taken) that drops you into a interactive session when a
test run has failures. From this you can list the errors ('l'), print
tracebacks ('tb') and drop into a pdb session for each failure ('d').
Blank lines and 'q' quit.
I've also added a sketal PyPy-specialized subclass of pdb.Pdb.
Modified: pypy/trunk/src/pypy/interpreter/unittest_w.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/unittest_w.py (original)
+++ pypy/trunk/src/pypy/interpreter/unittest_w.py Mon Jul 7 18:10:02 2003
@@ -57,6 +57,52 @@
class IntTestCase(unittest.TestCase):
""" enrich TestCase with wrapped-methods """
+ def __init__(self, methodName='runTest'):
+ self.methodName = methodName
+ unittest.TestCase.__init__(self, methodName)
+
+ def __call__(self, result=None):
+ from pypy.tool.test import TestSkip
+ if result is None: result = self.defaultTestResult()
+ result.startTest(self)
+ testMethod = getattr(self, self.methodName)
+ try:
+ try:
+ self.setUp()
+ except TestSkip:
+ result.addSkip(self)
+ return
+ except KeyboardInterrupt:
+ raise
+ except:
+ result.addError(self, self._TestCase__exc_info())
+ return
+
+ ok = 0
+ try:
+ testMethod()
+ ok = 1
+ except self.failureException, e:
+ result.addFailure(self, self._TestCase__exc_info())
+ except TestSkip:
+ result.addSkip(self)
+ return
+ except KeyboardInterrupt:
+ raise
+ except:
+ result.addError(self, self._TestCase__exc_info())
+
+ try:
+ self.tearDown()
+ except KeyboardInterrupt:
+ raise
+ except:
+ result.addError(self, self._TestCase__exc_info())
+ ok = 0
+ if ok: result.addSuccess(self)
+ finally:
+ result.stopTest(self)
+
def failUnless_w(self, w_condition, msg=None):
condition = self.space.is_true(w_condition)
@@ -100,15 +146,11 @@
class AppTestCase(IntTestCase):
- def __init__(self, methodName='runTest'):
- self.methodName = methodName
- unittest.TestCase.__init__(self, methodName)
-
def __call__(self, result=None):
if type(getattr(self, self.methodName)) != WrappedFunc:
setattr(self, self.methodName,
WrappedFunc(self, getattr(self, self.methodName)))
- return unittest.TestCase.__call__(self, result)
+ return IntTestCase.__call__(self, result)
def setUp(self):
from pypy.tool import test
Modified: pypy/trunk/src/pypy/tool/option.py
==============================================================================
--- pypy/trunk/src/pypy/tool/option.py (original)
+++ pypy/trunk/src/pypy/tool/option.py Mon Jul 7 18:10:02 2003
@@ -40,8 +40,6 @@
op = optik.OptionParser()
op.add_options(optionlist)
options, args = op.parse_args(argv, input_options)
- if not input_options.spaces:
- input_options.spaces.append(os.environ.get('OBJSPACE', 'trivial'))
return args
def objspace(name='', _spacecache={}):
@@ -49,12 +47,13 @@
this is configured via the environment variable OBJSPACE
"""
+
if not name:
- if hasattr(Options, 'spacename'):
- name = Options.spacename
- else:
+ if Options.spaces:
name = Options.spaces[-1]
-
+ else:
+ name = os.environ.get('OBJSPACE', 'trivial')
+
try:
return _spacecache[name]
except KeyError:
Added: pypy/trunk/src/pypy/tool/ppdb.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/tool/ppdb.py Mon Jul 7 18:10:02 2003
@@ -0,0 +1,22 @@
+# it had to happen: a customized version of pdb for pypy; Py Py
+# DeBugger, if you please.
+
+# i only plan to support post morterm debugging! my head hurts if my
+# thoughts even go near any alternative!
+
+import pdb, sys
+
+class PPdb(pdb.Pdb):
+ def do_bta(self, line):
+ self.operr.print_application_traceback(self.space, sys.stdout)
+
+def post_mortem(space, t, operr):
+ # need app-level tb too?
+ p = PPdb()
+ p.reset()
+ p.space = space
+ p.operr = operr
+ while t.tb_next is not None:
+ t = t.tb_next
+ p.interaction(t.tb_frame, t)
+
Modified: pypy/trunk/src/pypy/tool/test.py
==============================================================================
--- pypy/trunk/src/pypy/tool/test.py (original)
+++ pypy/trunk/src/pypy/tool/test.py Mon Jul 7 18:10:02 2003
@@ -1,11 +1,10 @@
import autopath
-import os, sys, unittest, re, warnings, unittest, traceback
+import os, sys, unittest, re, warnings, unittest, traceback, StringIO
from unittest import TestCase, TestLoader
import pypy.interpreter.unittest_w
from pypy.tool.optik import make_option
-from pypy.tool import optik, option
-from pypy.tool.option import objspace
+from pypy.tool import optik, option, ppdb
IntTestCase = pypy.interpreter.unittest_w.IntTestCase
AppTestCase = pypy.interpreter.unittest_w.AppTestCase
@@ -13,21 +12,13 @@
class MyTestSuite(unittest.TestSuite):
def __call__(self, result):
- """ execute the tests, invokes underlyning unittest.__call__"""
+ """ execute the tests, invokes underlying unittest.__call__"""
- # XXX here is probably not the best place
- # to check for test/objspace mismatch
count = self.countTestCases()
if not count:
return result
fm = getattr(self, 'frommodule','')
- for spacename in ('std','trivial','ann'):
- if fm and fm.startswith('pypy.objspace.' + spacename) and \
- Options.spacename != spacename:
- sys.stderr.write("\n%s skip for objspace %r" % (
- fm, Options.spacename))
- return result
if fm and Options.verbose==0:
sys.stderr.write('\n%s [%d]' %(fm, count))
@@ -60,21 +51,10 @@
unittest.TestResult.addError(self, test, err)
def addSuccess(self, test):
self.successes.append(test)
+ def addSkip(self, test):
+ self.testsRun -= 1
class MyTextTestResult(unittest._TextTestResult):
-
- def munge(self, list, test, err):
- import StringIO
- from pypy.interpreter.baseobjspace import OperationError
- text1 = list.pop()[1]
- if isinstance(err[1], OperationError):
- sio = StringIO.StringIO()
- err[1].print_application_traceback(test.space, sio)
- text2 = sio.getvalue()
-
- list.append((test, text1 + "\nand at app-level:\n\n" + text2))
- else:
- list.append((test, text1))
def addError(self, test, err):
from pypy.interpreter.baseobjspace import OperationError
@@ -83,11 +63,71 @@
self.addFailure(test, err)
return
unittest._TextTestResult.addError(self, test, err)
- self.munge(self.errors, test, err)
+ self.errors[-1] = (test, sys.exc_info())
def addFailure(self, test, err):
unittest._TextTestResult.addFailure(self, test, err)
- self.munge(self.failures, test, err)
+ self.failures[-1] = (test, sys.exc_info())
+
+ def addSkip(self, test):
+ self.testsRun -= 1
+ if self.showAll:
+ self.stream.writeln("skipped")
+ elif self.dots:
+ self.stream.write('s')
+
+ def interact(self):
+ efs = self.errors + self.failures
+ from pypy.tool.testpm import TestPM
+ c = TestPM(efs)
+ c.cmdloop()
+ return
+ def proc_input(input):
+ r = int(input)
+ if r < 0 or r >= len(efs):
+ raise ValueError
+ return r
+ while 1:
+ i = 0
+ for t, e in efs:
+ print i, t.methodName
+ i += 1
+ while 1:
+ input = raw_input('itr> ')
+ if not input:
+ return
+ try:
+ r = proc_input(input)
+ except ValueError:
+ continue
+ else:
+ break
+ s, (t, v, tb) = efs[r]
+ ppdb.post_mortem(s.space, tb, v)
+
+ def printErrors(self):
+ if Options.interactive:
+ print
+ if self.errors or self.failures:
+ self.interact()
+ else:
+ unittest._TextTestResult.printErrors(self)
+
+ def printErrorList(self, flavour, errors):
+ from pypy.interpreter.baseobjspace import OperationError
+ for test, err in errors:
+ self.stream.writeln(self.separator1)
+ self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
+ self.stream.writeln(self.separator2)
+ t1 = self._exc_info_to_string(err)
+ t2 = ''
+ if isinstance(err[1], OperationError):
+ t2 = '\nand at app-level:\n\n'
+ sio = StringIO.StringIO()
+ err[1].print_application_traceback(test.space, sio)
+ t2 += sio.getvalue()
+
+ self.stream.writeln("%s" % (t1 + t2,))
class CtsTestRunner:
def run(self, test):
@@ -197,11 +237,20 @@
testreldir = 0
runcts = 0
spacename = ''
- individualtime=0
+ individualtime = 0
+ interactive = 0
def ensure_value(*args):
return 0
ensure_value = staticmethod(ensure_value)
+class TestSkip(Exception):
+ pass
+
+def objspace(name=''):
+ if name and Options.spacename and name != Options.spacename:
+ raise TestSkip
+ return option.objspace(name)
+
class RegexFilterFunc:
""" stateful function to filter included/excluded strings via
a Regular Expression.
@@ -237,6 +286,9 @@
'-i', action="store_true", dest="individualtime",
help="time each test individually"))
options.append(make_option(
+ '-k', action="store_true", dest="interactive",
+ help="enter an interactive mode on failure or error"))
+ options.append(make_option(
'-c', action="store_true", dest="runcts",
help="run CtsTestRunner (catches stdout and prints report "
"after testing) [unix only, for now]"))
Added: pypy/trunk/src/pypy/tool/testpm.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/tool/testpm.py Mon Jul 7 18:10:02 2003
@@ -0,0 +1,79 @@
+# this file implements a little interactive loop that can be
+# optionally entered at the end of a test run to allow inspection (and
+# pdb-ing) of failures and/or errors.
+
+import autopath
+from pypy.tool import ppdb
+import cmd, traceback
+
+class TestPM(cmd.Cmd):
+ def __init__(self, efs):
+ cmd.Cmd.__init__(self)
+ self.efs = efs
+ self.prompt = 'tbi> '
+ def emptyline(self):
+ return 1
+
+ def do_EOF(self, line):
+ return 1
+ do_q = do_EOF
+
+ def print_tb(self, ef):
+ from pypy.interpreter.baseobjspace import OperationError
+ err = ef[1]
+ print ''.join(traceback.format_exception(*err))
+ if isinstance(err[1], OperationError):
+ print 'and at app-level:'
+ print
+ err[1].print_application_traceback(ef[0].space)
+
+ def do_l(self, line):
+ i = 0
+ for t, e in self.efs:
+ print i, t.__class__.__module__, t.__class__.__name__, t.methodName
+ i += 1
+
+ def do_tb(self, arg):
+ args = arg.split()
+ if len(args) == 0:
+ for x in self.efs:
+ t = x[0]
+ print t.__class__.__module__, t.__class__.__name__, t.methodName
+ print
+ self.print_tb(x)
+ print
+ elif len(args) == 1:
+ try:
+ tbi = int(args[0])
+ except ValueError:
+ print "error2"
+ else:
+ if 0 <= tbi < len(self.efs):
+ self.print_tb(self.efs[tbi])
+ else:
+ print "error3"
+ else:
+ print "error"
+
+ def do_d(self, arg):
+ args = arg.split()
+ if len(args) == 1:
+ try:
+ efi = int(args[0])
+ except ValueError:
+ print "error2"
+ else:
+ if 0 <= efi < len(self.efs):
+ s, (t, v, tb) = self.efs[efi]
+ ppdb.post_mortem(s.space, tb, v)
+ else:
+ print "error3"
+ else:
+ print "error"
+
+
+if __name__ == '__main__':
+ # just for testing
+ c = TestPM([])
+ c.cmdloop()
+
More information about the Pypy-commit
mailing list