[pypy-svn] r7261 - in pypy/trunk/src: goal pypy/interpreter pypy/interpreter/test pypy/objspace/flow pypy/objspace/std pypy/objspace/test pypy/tool pypy/tool/test

hpk at codespeak.net hpk at codespeak.net
Mon Nov 15 19:40:16 CET 2004


Author: hpk
Date: Mon Nov 15 19:40:09 2004
New Revision: 7261

Added:
   pypy/trunk/src/pypy/tool/frozendict.py
Removed:
   pypy/trunk/src/pypy/tool/newtest.py
   pypy/trunk/src/pypy/tool/test/test_newtest.py
Modified:
   pypy/trunk/src/goal/testcachebuild.py
   pypy/trunk/src/pypy/interpreter/baseobjspace.py
   pypy/trunk/src/pypy/interpreter/extmodule.py
   pypy/trunk/src/pypy/interpreter/gateway.py
   pypy/trunk/src/pypy/interpreter/test/test_gateway.py
   pypy/trunk/src/pypy/interpreter/unittest_w.py
   pypy/trunk/src/pypy/objspace/flow/objspace.py
   pypy/trunk/src/pypy/objspace/std/objspace.py
   pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py
Log:
- reworked the "space.generalcache" into 

    space._typecache     # cache for types 
    space._faketypecache # cache for faked types 
    space._gatewaycache  # cache for gateway's interp2app/app2interp 

  and changed space.loadfromcache to require a third parameter 
  'cache' which the different users have to provide 

- the testing parts of pypy (unittest_w and test_gateway.py etc.pp) 
  don't participate in the above caches but use their own cache 

- the new goal/testcachebuild.py shows that we can run all 
  tests, then turn the above caches into frozendict(cache)'s 
  and still run all tests successfully (so no new building of
  cache content takes place anymore) 
   
- removed the unused newtest.py and related files 
  (some leftover from three sprints ago or so) 


Modified: pypy/trunk/src/goal/testcachebuild.py
==============================================================================
--- pypy/trunk/src/goal/testcachebuild.py	(original)
+++ pypy/trunk/src/goal/testcachebuild.py	Mon Nov 15 19:40:09 2004
@@ -1,5 +1,6 @@
-from pypy.tool import option, autopath, testit 
+from pypy.tool import option, autopath, testit
 from pypy.interpreter import gateway 
+from pypy.tool.frozendict import frozendict 
 
 #######################################################
 def app_triggergenerator():
@@ -19,5 +20,9 @@
     space = option.objspace('std') 
     #triggercachebuild(space) 
     testit.main(autopath.pypydir)
-    space.allowbuildcache = False 
+
+    space._typecache = frozendict(space._typecache) 
+    space._faketypecache = frozendict(space._faketypecache) 
+    space._gatewaycache = frozendict(space._gatewaycache) 
+
     testit.main(autopath.pypydir)

Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/trunk/src/pypy/interpreter/baseobjspace.py	Mon Nov 15 19:40:09 2004
@@ -2,6 +2,7 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.miscutils import getthreadlocals
 from pypy.interpreter.argument import Arguments
+from pypy.tool.frozendict import frozendict 
 
 __all__ = ['ObjSpace', 'OperationError', 'Wrappable', 'BaseWrappable',
            'W_Root']
@@ -32,20 +33,17 @@
 
     def __init__(self):
         "Basic initialization of objects."
-        self.generalcache = {}
-        self.allowbuildcache = True 
+        self._gatewaycache = {}
         # sets all the internal descriptors
         self.initialize()
 
-    def loadfromcache(self, key, builder):
+    def loadfromcache(self, key, builder, cache):
         try:
-            return self.generalcache[key]
+            return cache[key]
         except KeyError:
-            if self.allowbuildcache: 
-                #print "building for key %r" % key 
-                return self.generalcache.setdefault(key, builder(key, self))
-            raise 
-    loadfromcache.translated_version = lambda s, k, b: s.generalcache[k]
+            assert not isinstance(cache, frozendict)
+            #print "building for key %r" % key 
+            return cache.setdefault(key, builder(key, self))
 
     def make_builtins(self, for_builtins):
         # initializing builtins may require creating a frame which in

Modified: pypy/trunk/src/pypy/interpreter/extmodule.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/extmodule.py	(original)
+++ pypy/trunk/src/pypy/interpreter/extmodule.py	Mon Nov 15 19:40:09 2004
@@ -55,7 +55,7 @@
             ('__interplevel__eval',     self.interpleveleval.im_func),
             ('__interplevel__execfile', self.interplevelexecfile.im_func),
             ('__import__',              self.interplevelimport.im_func)]:
-            hook = gateway.interp2app(impl).get_method(self)
+            hook = gateway.interp2app_temp(impl).get_method(self)
             w_name = space.wrap(name)
             try:
                 self.__saved_hooks[name] = space.getitem(w_builtins, w_name)

Modified: pypy/trunk/src/pypy/interpreter/gateway.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/gateway.py	(original)
+++ pypy/trunk/src/pypy/interpreter/gateway.py	Mon Nov 15 19:40:09 2004
@@ -182,7 +182,9 @@
         return self.get_function(space)
 
     def get_function(self, space):
-        return space.loadfromcache(self, Gateway.build_all_functions)
+        return space.loadfromcache(self, 
+                                   Gateway.build_all_functions, 
+                                   self.getcache(space))
 
     def build_all_functions(self, space):
         # the construction is supposed to be done only once in advance,
@@ -197,25 +199,31 @@
         else:
             # is there another Gateway in staticglobals for which we
             # already have a w_globals for this space ?
+            cache = self.getcache(space) 
             for value in self.staticglobals.itervalues():
                 if isinstance(value, Gateway):
-                    if self in space.generalcache:
+                    if value in cache: 
                         # yes, we share its w_globals
-                        fn = space.generalcache[value]
+                        fn = cache[value] 
                         w_globals = fn.w_func_globals
                         break
             else:
                 # no, we build all Gateways in the staticglobals now.
                 w_globals = build_dict(self.staticglobals, space)
-        return self.build_function(space, w_globals)
+        return self._build_function(space, w_globals)
 
-    def build_function(self, space, w_globals):
-        if not space.allowbuildcache: 
-            return space.generalcache[self]
-        defs = self.getdefaults(space)  # needs to be implemented by subclass
-        fn = Function(space, self.code, w_globals, defs, forcename = self.name)
-        space.generalcache[self] = fn
-        return fn
+    def getcache(self, space):
+        return space._gatewaycache 
+
+    def _build_function(self, space, w_globals):
+        cache = self.getcache(space) 
+        try: 
+            return cache[self] 
+        except KeyError: 
+            defs = self.getdefaults(space)  # needs to be implemented by subclass
+            fn = Function(space, self.code, w_globals, defs, forcename = self.name)
+            cache[self] = fn 
+            return fn
 
     def get_method(self, obj):
         # to get the Gateway as a method out of an instance, we build a
@@ -289,8 +297,12 @@
     def getdefaults(self, space):
         return self.staticdefs
 
-def exportall(d):
+def exportall(d, temporary=False):
     """Publish every function from a dict."""
+    if temporary:
+        i2a = interp2app_temp
+    else:
+        i2a = interp2app
     for name, obj in d.items():
         if isinstance(obj, types.FunctionType):
             # names starting in 'app_' are supposedly already app-level
@@ -303,7 +315,7 @@
             if name.startswith('_') and not name.endswith('_'):
                 continue
             if 'app_'+name not in d:
-                d['app_'+name] = interp2app(obj, name)
+                d['app_'+name] = i2a(obj, name)
 
 def export_values(space, dic, w_namespace):
     for name, w_value in dic.items():
@@ -316,22 +328,40 @@
                 w_name = space.wrap(name[2:])
             space.setitem(w_namespace, w_name, w_value)
 
-def importall(d):
+def importall(d, temporary=False):
     """Import all app_-level functions as Gateways into a dict."""
+    if temporary:
+        a2i = app2interp_temp
+    else:
+        a2i = app2interp
     for name, obj in d.items():
         if name.startswith('app_') and name[4:] not in d:
             if isinstance(obj, types.FunctionType):
-                d[name[4:]] = app2interp(obj, name[4:])
+                d[name[4:]] = a2i(obj, name[4:])
 
 def build_dict(d, space):
     """Search all Gateways and put them into a wrapped dictionary."""
     w_globals = space.newdict([])
     for value in d.itervalues():
         if isinstance(value, Gateway):
-            fn = value.build_function(space, w_globals)
+            fn = value._build_function(space, w_globals)
             w_name = space.wrap(value.name)
             w_object = space.wrap(fn)
             space.setitem(w_globals, w_name, w_object)
     if hasattr(space, 'w_sys'):  # give them 'sys' if it exists already
         space.setitem(w_globals, space.wrap('sys'), space.w_sys)
     return w_globals
+
+
+# 
+# the next gateways are to be used only for 
+# temporary/initialization purposes 
+class app2interp_temp(app2interp): 
+    def getcache(self, space): 
+        return self.__dict__.setdefault(space, {}) 
+        #                               ^^^^^
+        #                          armin suggested this 
+     
+class interp2app_temp(interp2app): 
+    def getcache(self, space): 
+        return self.__dict__.setdefault(space, {}) 

Modified: pypy/trunk/src/pypy/interpreter/test/test_gateway.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/test/test_gateway.py	(original)
+++ pypy/trunk/src/pypy/interpreter/test/test_gateway.py	Mon Nov 15 19:40:09 2004
@@ -3,7 +3,6 @@
 from pypy.tool import testit
 from pypy.interpreter import gateway
 
-
 class TestBuiltinCode(testit.IntTestCase):
     def setUp(self):
         self.space = testit.objspace()
@@ -66,7 +65,7 @@
         w = self.space.wrap
         def app_g3(a, b):
             return a+b
-        g3 = gateway.app2interp(app_g3)
+        g3 = gateway.app2interp_temp(app_g3)
         self.assertEqual_w(g3(self.space, w('foo'), w('bar')), w('foobar'))
         
     def test_interp2app(self):
@@ -74,7 +73,7 @@
         w = space.wrap
         def g3(space, w_a, w_b):
             return space.add(w_a, w_b)
-        app_g3 = gateway.interp2app(g3)
+        app_g3 = gateway.interp2app_temp(g3)
         w_app_g3 = space.wrap(app_g3) 
         self.assertEqual_w(
             space.call(w_app_g3, 
@@ -94,7 +93,7 @@
 def app_g1(x):
     return g3('foo', x)
 """ in g
-        gateway.importall(g)
+        gateway.importall(g, temporary=True)
         g1 = g['g1']
         self.assertEqual_w(g1(self.space, w('bar')), w('foobar'))
 
@@ -107,8 +106,8 @@
 def app_g1(x):
     return g3('foo', x)
 """ in g
-        gateway.exportall(g)
-        g1 = gateway.app2interp(g['app_g1'])
+        gateway.exportall(g, temporary=True)
+        g1 = gateway.app2interp_temp(g['app_g1'])
         self.assertEqual_w(g1(self.space, w('bar')), w('foobar'))
 
 

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 Nov 15 19:40:09 2004
@@ -12,7 +12,6 @@
     IGNORE_TESTS = [s.strip() for s in f.readlines()]
     f.close()
 
-
 def make_testcase_class(space, tc_w):
     # XXX this is all a bit insane (but it works)
 
@@ -22,7 +21,7 @@
     for name in dir(AppTestCase):
         if ( name.startswith('assert') or name.startswith('fail')
              and name != 'failureException'):
-            fn = gateway.app2interp(getattr(tc_w, name).im_func, name)
+            fn = gateway.app2interp_temp(getattr(tc_w, name).im_func, name)
             space.setitem(w_dict, w(name), w(fn))
 
     # space-dependent part: make an object-space-level dictionary
@@ -52,7 +51,7 @@
             setattr(space, w_tc_attr, w_tc)
 
         f = self.testMethod.im_func
-        gway = gateway.app2interp(f, f.func_name)
+        gway = gateway.app2interp_temp(f, f.func_name)
         gway(space, w_tc)
 
 

Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/objspace.py	(original)
+++ pypy/trunk/src/pypy/objspace/flow/objspace.py	Mon Nov 15 19:40:09 2004
@@ -28,9 +28,9 @@
         #self.make_builtins()
         #self.make_sys()
 
-    def loadfromcache(self, key, builder):
+    def loadfromcache(self, key, builder, cache):
         try:
-            return self.generalcache[key]
+            return cache[key] 
         except KeyError:
             # this method is overloaded to allow the space to switch to
             # "concrete mode" when building the object that goes into
@@ -39,7 +39,7 @@
             self.executioncontext.crnt_ops = flowcontext.ConcreteNoOp()
             self.concrete_mode += 1
             try:
-                return self.generalcache.setdefault(key, builder(key, self))
+                return cache.setdefault(key, builder(key, self))
             finally:
                 self.executioncontext.crnt_ops = previous_ops
                 self.concrete_mode -= 1

Modified: pypy/trunk/src/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/objspace.py	(original)
+++ pypy/trunk/src/pypy/objspace/std/objspace.py	Mon Nov 15 19:40:09 2004
@@ -7,7 +7,6 @@
 from pypy.objspace.std import stdtypedef
 import types
 
-
 class W_Object(W_Root, object):
     "Parent base class for wrapped objects."
     typedef = None
@@ -136,6 +135,9 @@
         return done
                             
     def initialize(self):
+        self._typecache = {}
+        self._faketypecache = {}
+
         # The object implementations that we want to 'link' into PyPy must be
         # imported here.  This registers them into the multimethod tables,
         # *before* the type objects are built from these multimethod tables.
@@ -206,7 +208,9 @@
     def gettypeobject(self, typedef):
         # types_w maps each StdTypeDef instance to its
         # unique-for-this-space W_TypeObject instance
-        return self.loadfromcache(typedef, stdtypedef.buildtypeobject)
+        return self.loadfromcache(typedef, 
+                                  stdtypedef.buildtypeobject,
+                                  self._typecache)
 
     def wrap(self, x):
         "Wraps the Python value 'x' into one of the wrapper classes."
@@ -251,9 +255,9 @@
             if hasattr(self, 'w_' + x.__name__):
                 return getattr(self, 'w_' + x.__name__)
         if isinstance(x, type):
-            ft = self.loadfromcache(x, fake_type)
+            ft = self.loadfromcache(x, fake_type, self._faketypecache)
             return self.gettypeobject(ft.typedef)
-        ft = self.loadfromcache(type(x), fake_type)
+        ft = self.loadfromcache(type(x), fake_type, self._faketypecache)
         return ft(self, x)
 
     def newint(self, intval):

Modified: pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py	(original)
+++ pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py	Mon Nov 15 19:40:09 2004
@@ -1,8 +1,8 @@
 import autopath
 from pypy.tool import testit
 from pypy.objspace import trace 
-from pypy.interpreter.gateway import app2interp
 from pypy.tool import pydis
+from pypy.interpreter import gateway 
     
 class Test_TraceObjSpace(testit.IntTestCase):
 
@@ -15,7 +15,7 @@
 
     def perform_trace(self, app_func):
         tspace = self.space
-        func_gw = app2interp(app_func)
+        func_gw = gateway.app2interp_temp(app_func)
         func = func_gw.get_function(tspace)
         tspace.settrace()
         tspace.call_function(tspace.wrap(func))

Added: pypy/trunk/src/pypy/tool/frozendict.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/tool/frozendict.py	Mon Nov 15 19:40:09 2004
@@ -0,0 +1,7 @@
+
+# hacks += 1
+class frozendict(dict):
+    def __setitem__(self, *args): 
+        raise TypeError, "this dict is already frozen, you are too late!" 
+    __delitem__ = setdefault = update = pop = popitem = clear = __setitem__ 
+

Deleted: /pypy/trunk/src/pypy/tool/newtest.py
==============================================================================
--- /pypy/trunk/src/pypy/tool/newtest.py	Mon Nov 15 19:40:09 2004
+++ (empty file)
@@ -1,672 +0,0 @@
-"""
-Unit testing framework for PyPy.
-
-The following picture is an UML class diagram of the framework.
-
- +----------+ 1                    1 +------------+
- | TestItem |------------------------| TestResult |
- +----------+                        | (abstract) |
-      | *                            +------------+
-      |                                     A
-      |                                     -
-      | 1                                   |
- +-----------+         +-----------+--------+----------+
- | TestSuite |         |           |                   |
- +-----------+    +---------+ +---------+ +-------------------------+
-      A           | Success | | Skipped | | TestResultWithTraceback |
-      |           +---------+ +---------+ | (abstract)              |
-      | loaded by                         +-------------------------+
-      |                                          A            A
-      | *                                        -            -
- +------------+                                  |            |
- | TestCase   |                                  |            |
- | (abstract) |                              +-------+   +---------+
- +------------+                              | Error |   | Failure |
-      A                                      +-------+   +---------+
-      -
-      |
-      |
-  concrete test
-  case classes
-
-Like the unittest framework of Python, our framework implements
-tests as test methods in TestCase classes. Custom test case classes
-derive from the shown TestCase class, defined in this module. As in
-Python's unittest, a test case class can contain setUp and tearDown
-methods. Additionally, it contains a method 'skip' which can be
-called to stop a test prematurely. This won't be counted as a failure
-or error.
-
-Test cases are loaded by a TestSuite class via the method init_from_dir.
-This method will read all test modules in and below a specified
-directory, inspect them for classes derived from TestCase (i. e. _our_
-TestCase), and in turn inspect them for test methods (like in
-unittest, all methods which start with "test").
-
-For every found method, TestSuite will store its module, class and
-unbound method objects in a TestItem object. There are also other
-properties stored, e. g. the source code for each method and its
-docstring.
-
-When the TestSuite's method 'run' is called, all collected TestItems
-are run and, according to the outcome of the test, a TestResult object
-is generated which holds a reference to "its" TestItem object.
-
-The TestResult classes Success and Skipped denote a passed test. A
-skipped test means that not all test code has been run (and no error
-or failure occurred before the skip method was called). If a test
-fails, resulting in a Failure object, a test, e. g. tested with
-assertEqual, has failed. An Error object is generated if something
-else causes an unforeseen exception to be raised.
-"""
-
-# for Python 2.2 compatibilty
-from __future__ import generators
-
-import autopath
-
-import cStringIO as StringIO
-import inspect
-import os
-import sys
-import traceback
-import types
-from std import path 
-
-#TODO
-# - add support for ignored tests (do we need to differentiate between
-#   skipped and ignored tests at all?)
-# - support TestItem.run with different object spaces
-# - unify naming of methods/functions; what about the TestCase class?
-# - support for pickling and retrieving TestItems and TestResults?
-
-#
-# custom TestCase class (adapted from Python's unittest module)
-#
-class TestCase:
-    """A class whose instances are single test cases.
-
-    By default, the test code itself should be placed in a method named
-    'runTest'.
-
-    If the fixture may be used for many test cases, create as
-    many test methods as are needed. When instantiating such a TestCase
-    subclass, specify in the constructor arguments the name of the test method
-    that the instance is to execute.
-
-    Test authors should subclass TestCase for their own tests. Construction
-    and deconstruction of the test's environment ('fixture') can be
-    implemented by overriding the 'setUp' and 'tearDown' methods respectively.
-    """
-    def setUp(self):
-        "Hook method for setting up the test fixture before exercising it."
-        pass
-
-    def tearDown(self):
-        "Hook method for deconstructing the test fixture after testing it."
-        pass
-
-    def skip(self, msg=None):
-        """Skip this test by raising exception Skipped."""
-        raise Skipped(msg=msg)
-
-    def fail(self, msg=None):
-        """Fail immediately, with the given message."""
-        raise Failure(msg=msg)
-
-    def failIf(self, expr, msg=None):
-        """Fail the test if the expression is true."""
-        if expr:
-            raise Failure(msg=msg)
-
-    def failUnless(self, expr, msg=None):
-        """Fail the test unless the expression is true."""
-        if not expr:
-            raise Failure(msg=msg)
-
-    def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
-        """
-        Fail unless an exception of class excClass is thrown
-        by callableObj when invoked with arguments args and keyword
-        arguments kwargs. If a different type of exception is
-        thrown, it will not be caught, and the test case will be
-        deemed to have suffered an error, exactly as for an
-        unexpected exception.
-        """
-        try:
-            callableObj(*args, **kwargs)
-        except excClass:
-            return
-        else:
-            if hasattr(excClass,'__name__'):
-                excName = excClass.__name__
-            else:
-                excName = str(excClass)
-            raise Failure(msg=excName)
-
-    def failUnlessEqual(self, first, second, msg=None):
-        """
-        Fail if the two objects are unequal as determined by the '=='
-        operator.
-        """
-        if not first == second:
-            raise Failure(msg=(msg or '%s != %s' % (`first`, `second`)))
-
-    def failIfEqual(self, first, second, msg=None):
-        """
-        Fail if the two objects are equal as determined by the '=='
-        operator.
-        """
-        if first == second:
-            raise Failure(msg=(msg or '%s == %s' % (`first`, `second`)))
-
-    def failUnlessAlmostEqual(self, first, second, places=7, msg=None):
-        """
-        Fail if the two objects are unequal as determined by their
-        difference rounded to the given number of decimal places
-        (default 7) and comparing to zero.
-
-        Note that decimal places (from zero) is usually not the same
-        as significant digits (measured from the most signficant digit).
-        """
-        if round(second-first, places) != 0:
-            raise Failure(msg=(msg or '%s != %s within %s places' %
-                                      (`first`, `second`, `places`)))
-
-    def failIfAlmostEqual(self, first, second, places=7, msg=None):
-        """
-        Fail if the two objects are equal as determined by their
-        difference rounded to the given number of decimal places
-        (default 7) and comparing to zero.
-
-        Note that decimal places (from zero) is usually not the same
-        as significant digits (measured from the most signficant digit).
-        """
-        if round(second-first, places) == 0:
-            raise Failure(msg=(msg or '%s == %s within %s places' %
-                                      (`first`, `second`, `places`)))
-
-    # aliases
-    assertEqual = assertEquals = failUnlessEqual
-    assertNotEqual = assertNotEquals = failIfEqual
-    assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual
-    assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual
-    assertRaises = failUnlessRaises
-    assert_ = failUnless
-
-
-# provide services from TestCase class also to test functions, e. g.
-# def test_func4711():
-#     service.assertEqual(3, 3.0, msg="objects with same value should be equal")
-#XXX maybe use another name instead of 'service'
-service = TestCase()
-
-#
-# TestResult class family
-#
-class TestResult(Exception):
-    """Abstract class representing the outcome of a test."""
-    def __init__(self, msg="", item=None):
-        Exception.__init__(self, msg)
-        self.msg = msg
-        self.item = item
-        self.name = self.__class__.__name__
-        self.traceback = None
-
-    #XXX possibly, we need an attribute/method has_traceback?
-
-    def __eq__(self, other):
-        """
-        Return True if both TestResult objects are semantically the same.
-        Else, return False.
-        """
-        # trivial case
-        if (self is other) or (self.item is other.item):
-            return True
-        return False
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    def __hash__(self):
-        return id(self.item)
-
-class Success(TestResult):
-    pass
-
-class Skipped(TestResult):
-    pass
-
-class Ignored(TestResult):
-    pass
-
-
-class TestResultWithTraceback(TestResult):
-    def __init__(self, msg='', item=None):
-        TestResult.__init__(self, msg, item)
-        self.set_exception()
-
-    def __eq__(self, other):
-        return TestResult.__eq__(self, other) and \
-               self.formatted_traceback == other.formatted_traceback
-
-    def set_exception(self):
-        self.excinfo = sys.exc_info()
-        self.traceback = self.excinfo[2]
-        # store formatted traceback
-        output = StringIO.StringIO()
-        args = self.excinfo + (None, output)
-        traceback.print_exception(*args)
-        # strip trailing newline
-        self.formatted_traceback = output.getvalue().rstrip()
-
-class Error(TestResultWithTraceback):
-    pass
-
-class Failure(TestResultWithTraceback):
-    pass
-
-#
-# other classes
-#
-class TestItem:
-    """
-    Represent either a test function, or a single test method from a
-    TestCase class.
-    """
-    def __init__(self, callable_, name=None):
-        """
-        Construct a test item.
-
-        The argument callable_ must be a callable object, i. e. a
-        plain function, a bound or unbound method of a class, or an
-        object with __call__ attribute.
-
-        The optional argument name can be a string which will be used
-        as the object's name. Else, the name will be tried to be
-        determined from the object's __name__ attribute.
-        """
-        assert callable(callable_), \
-               "must get a callable item, but got '%s'" % callable_
-        self.callable = callable_
-        # determine additional attributes (e. g. for error reporting)
-        self.call_via_class = False
-        # - class
-        if hasattr(callable_, 'im_class'):
-            # unbound and bound methods; __class__ would be instancemethod,
-            # not the one containing the methods
-            self.cls = callable_.im_class
-            if callable_.im_self is None:
-                # unbound methods are not directly callable without
-                # arguments
-                self.call_via_class = True
-        elif hasattr(callable_, '__class__') and \
-          not inspect.isfunction(callable_):
-            # class instances with __call__ attribute
-            self.cls = callable_.__class__
-        else:
-            self.cls = None
-        # - module (sometimes, using the class works better than the callable)
-        self.module = inspect.getmodule(self.cls or callable_)
-        # - name
-        try:
-            self.name = name or callable_.__name__
-        except AttributeError:
-            self.name = '<unnamed object>'
-        # - full name (including module and class, if applicable)
-        try:
-            parts = [self.module.__name__]
-        except AttributeError:
-            parts = []
-        if self.cls:
-            parts.append(self.cls.__name__)
-        parts.append(self.name)
-        self.full_name = '.'.join(parts)
-        # - file
-        try:
-            if self.module is None:
-                self.file = inspect.getsourcefile(self.cls or callable_)
-            else:
-                self.file = inspect.getsourcefile(self.module)
-        except IOError:
-            self.file = '<unknown>'
-        except TypeError:
-            self.file = '<built-in or from __main__>'
-        # - docstrings
-        self.docs = (self._docstring(self.module), self._docstring(self.cls),
-                     self._docstring(self.callable))
-        # - source code properties
-        #XXX inspect.getsourcelines may fail if the file path stored
-        #  in a module's pyc/pyo file doesn't match the py file's
-        #  actual location. This can happen if a py file, together with
-        #  its pyc/pyo file is moved to a new location. See Python
-        #  bug "[570300] inspect.getmodule symlink-related failure":
-        #  http://sourceforge.net/tracker/index.php?func=detail&aid=570300&group_id=5470&atid=105470
-        try:
-            lines, self.lineno = inspect.getsourcelines(callable)
-            # removing trailing newline(s) but not the indentation
-            self.source = ''.join(lines).rstrip()
-        except IOError:
-            self.source, self.lineno = '<unknown>', None
-        except TypeError:
-            self.source, self.lineno = '<built-in or from __main__>', None
-
-    def _docstring(self, obj):
-        """
-        Return the docstring of object obj or an empty string, if the
-        docstring doesn't exist, i. e. is None.
-        """
-        if obj is None:
-            return None
-        return inspect.getdoc(obj) or ""
-
-    def __eq__(self, other):
-        """
-        Return True if this and the other item compare equal. (This doesn't
-        necessarily mean that they are the same object.) Else, return False.
-        """
-        # trivial case
-        if self is other:
-            return True
-        # If module, cls and unbound method are the same, the files must
-        # also be equal. For the methods, we compare the names, not the
-        # methods themselves; see
-        # http://mail.python.org/pipermail/python-list/2002-September/121655.html
-        # for an explanation.
-        if (self.module is other.module) and (self.cls is other.cls) and \
-          (self.callable.__name__ == other.callable.__name__):
-            return True
-        return False
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    def __hash__(self):
-        return id(self.module) ^ id(self.cls)
-
-    # credit: adapted from Python's unittest.TestCase.run
-    def run(self, test_runner=lambda callable: callable()):
-        """
-        Run this TestItem and return a corresponding TestResult object.
-
-        If the test item corresponds to a class method, the setUp and
-        tearDown methods of the associated class are called before and
-        after the invocation of the test method, repectively.
-
-        If the optional argument test_runner is absent, the test function
-        or method is merely called with no arguments. Else, test_runner
-        must be a callable accepting one argument. Instead of only calling
-        the test callable, the test_runner object will be called with the
-        test function/method as its argument.
-        """
-        if self.call_via_class:
-            # turn the test callable, an unbound method, into a bound method
-            cls_object = self.cls()
-            test = getattr(cls_object, self.callable.__name__)
-        else:
-            # use the test function directly
-            test = self.callable
-
-        try:
-            # call setUp only for a class
-            self.call_via_class and cls_object.setUp()
-        except KeyboardInterrupt:
-            raise
-        except TestResult, result:
-            # reconstruct TestResult object, implicitly set exception
-            return result.__class__(msg=result.msg, item=self)
-        except Exception, exc:
-            return Error(msg=str(exc), item=self)
-
-        try:
-            test_runner(test)
-            result = Success(msg='success', item=self)
-        except KeyboardInterrupt:
-            raise
-        except TestResult, result:
-            # reconstruct TestResult object, implicitly set exception
-            result = result.__class__(msg=result.msg, item=self)
-        except Exception, exc:
-            result = Error(msg=str(exc), item=self)
-
-        try:
-            # call tearDown only for a class
-            self.call_via_class and cls_object.tearDown()
-        except KeyboardInterrupt:
-            raise
-        except Exception, exc:
-            # if we already had an exception in the test method,
-            # don't overwrite/mask it
-            if result.traceback is None:
-                result = Error(msg=str(exc), item=self)
-        return result
-
-    def __str__(self):
-        return "TestItem from %s" % self.full_name
-
-    def __repr__(self):
-        return "<%s at %#x>" % (str(self), id(self))
-
-
-class TestSuite:
-    """Represent a collection of test items."""
-    def __init__(self):
-        self.reset()
-
-    def reset(self):
-        """
-        Clear this TestSuite instance from all stored items and
-        test results.
-        """
-        self.items = []
-        self.last_results = {}
-
-    #
-    # get lists of TestItems from a class, a module, or a directory tree
-    #
-    def _module_from_modpath(self, modpath):
-        """
-        Return a module object derived from the module path
-        (e. g. "pypy.module.builtin.test.test_minmax").
-        """
-        # This __import__ call is only used to ensure that the module
-        # is present in sys.modules. Unfortunately, the module returned
-        # from the __import__ function doesn't correspond to the last
-        # component of the module path but the first. In the example
-        # listed in the docstring we thus would get the pypy module
-        # (i. e. package), not the test_minmax module.
-        __import__(modpath)
-        return sys.modules[modpath]
-
-    def _add_items(self, items):
-        """Add TestItems from list 'items' to TestSuite."""
-        self.items.extend(items)
-
-    def _items_from_class(self, cls):
-        """
-        Return TestItems extracted from class cls.
-
-        This includes all unbound methods whose names start with
-        "test_".
-        """
-        items = []
-        for attrname in cls.__dict__:
-            # don't use cls.__dict__[attrname]; for unbound methods,
-            # we would get function objects, i. e.
-            # cls.__dict__[attrname] != getattr(cls, attrname)
-            attr = getattr(cls, attrname)
-            if callable(attr) and attrname.startswith("test_"):
-                items.append(TestItem(attr, attrname))
-        return items
-
-    def _items_from_module(self, module):
-        """
-        Return TestItems extracted from module.
-
-        This includes all TestItems of classes derived from
-        TestCase and functions whose names start with "test_".
-        """
-        items = []
-        for attrname in module.__dict__:
-            # see comment in _items_from_class
-            attr = getattr(module, attrname)
-            if inspect.isclass(attr) and issubclass(attr, TestCase):
-                items.extend(self._items_from_class(attr))
-            elif inspect.isfunction(attr) and attrname.startswith("test_"):
-                items.append(TestItem(attr, attrname))
-        return items
-
-    def _items_from_dir(self, dirname, filterfunc=None, recursive=True):
-        """
-        Return a list of TestItems found by reading the directory denoted
-        by dirname. Find all test modules in it. Test modules are files that
-        comply with the shell pattern "test_*.py".
-
-        filterfunc is a callable that can be used to filter the test
-        modules by module path. By default, all test modules are used.
-
-        If recursive is true, which is the default, find all test modules
-        by scanning the start directory recursively.
-        """
-        items = []
-        dirname = path.local(dirname)
-
-        def testfilefilter(path):
-            return path.check(file=1, fnmatch='test_*.py')
-        def recfilter(path):
-            return recursive and path.check(dotfile=0) 
-
-        for testfn in dirname.visit(testfilefilter, recfilter):
-            # strip the leading pypy directory and the .py suffix
-            modpath = str(testfn)[len(autopath.pypydir)+1:-3]
-            modpath = 'pypy.' + modpath.replace(os.sep, '.')
-            if (filterfunc is None) or filterfunc(modpath):
-                try:
-                    module = self._module_from_modpath(modpath)
-                    module_items = self._items_from_module(module)
-                except:
-                    print >> sys.stderr, \
-                          "Warning: can't load module %s" % modpath
-                    #raise
-                else:
-                    items.extend(module_items)
-        return items
-
-    def add(self, *args):
-        """
-        Extract TestItems from the given args and add them to this
-        TestSuite.
-
-        The given objects can be:
-        - callable (function, unbound or bound method, class instance
-          with __call__ attribute): convert to TestItem
-        - class: extract all test methods, i. e. whose names start
-          with "test_"
-        - module: extract all test classes, i. e. classes derived
-          from newtest.TestCase, and all functions whose names
-          start with "test_"
-        - string: interpret the string as a file system path and
-          search it for Python files located in (sub)directories
-          named "test" and matching the shell pattern "test_*.py"
-        """
-        for arg in args:
-            if isinstance(arg, (types.ClassType, types.TypeType)):
-                self._add_items(self._items_from_class(arg))
-            elif callable(arg):
-                self._add_items([TestItem(arg)])
-            elif isinstance(arg, types.ModuleType):
-                self._add_items(self._items_from_module(arg))
-            elif isinstance(arg, (str, unicode)):
-                self._add_items(self._items_from_dir(arg))
-            else:
-                raise TypeError("unsupported TestItem source '%s'" % arg)
-
-    #
-    # running tests and getting results
-    #
-    def result_generator(self,
-                         classify=lambda result: result.item.module.__name__):
-        """
-        Return a generator to get the test result for each test item.
-
-        The optional argument classify must be callable which accepts
-        a TestResult instance as the argument and returns something
-        that can be used as a dictionary key.
-
-        During the iteration over the generator, the TestSuite object
-        will contain a dictionary named lastresult which maps these
-        keys to a list of TestResult objects that correspond to the key.
-        """
-        self.last_results = {}
-        for item in self.items:
-            result = item.run()
-            key = classify(result)
-            self.last_results.setdefault(key, []).append(result)
-            yield result
-
-    def run(self):
-        """
-        Run all the test items and return a list of the results. After
-        that, the results are available via the attribute last_results.
-        """
-        # perform all the tests by using the existing generator; discard
-        # the results; they are then available via self.last_results
-        return [result for result in self.result_generator()]
-
-
-def _print_results(suite):
-    """Print results for the items in a test suite."""
-    # iterate over tests and collect data
-    for result in suite.result_generator():
-        if result.traceback is None:
-            continue
-        print 79 * '-'
-        # print a line with the qualified name of the bad callable
-        item = result.item
-        print "%s: %s" % (item.full_name, result.name.upper())
-        print
-        print result.formatted_traceback
-    # emit a summary
-    print 79 * '='
-    modules = suite.last_results.keys()
-    modules.sort()
-    for module in modules:
-        results = suite.last_results[module]
-        resultstring = ''
-        for result in results:
-            status_char = {Success: '.', Ignored: 'i', Skipped: 's',
-                           Error: 'E', Failure: 'F'}[result.__class__]
-            resultstring += status_char
-        print "%s [%d] %s" % (module, len(results), resultstring)
-
-def main():
-    """
-    Find all tests in the current module (i. e. the module from which this
-    function is called), execute them and print results.
-    """
-    import __main__
-    from pypy.tool import newtest
-    suite = TestSuite()
-    suite.add(__main__)
-    _print_results(suite)
-
-def test(do_selftest=False):
-    # possibly ignore dummy unit tests
-    if do_selftest:
-        # include only selftest module
-        filterfunc = lambda m: m.find("pypy.tool.testdata.") != -1
-    else:
-        # exclude selftest module
-        filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1
-    # collect tests
-    suite = TestSuite()
-    print "Loading test modules ..."
-    suite.init_from_dir(autopath.pypydir, filterfunc=filterfunc)
-    _print_results(suite)
-
-
-if __name__ == '__main__':
-    # used to avoid subtle problems with class matching after different
-    # import statements
-    from pypy.tool import newtest
-    newtest.test(do_selftest=True)

Deleted: /pypy/trunk/src/pypy/tool/test/test_newtest.py
==============================================================================
--- /pypy/trunk/src/pypy/tool/test/test_newtest.py	Mon Nov 15 19:40:09 2004
+++ (empty file)
@@ -1,135 +0,0 @@
-import inspect
-import new
-import unittest
-
-import autopath
-from pypy.tool import newtest
-
-#TODO test(s) for adding TestItems from directory
-
-
-class TestTestItem(unittest.TestCase):
-    def _test_function(self, func, expected_name):
-        item = newtest.TestItem(func)
-        self.assertEqual(item.name, expected_name)
-        self.assertEqual(item.call_via_class, False)
-        self.assertEqual(item.cls, None)
-        self.failUnless(item.module is module)
-        self.assertEqual(item.file, file)
-
-    def test_plain_function(self):
-        f = lambda: 'anything'
-        self._test_function(f, expected_name='<lambda>')
-        def f(): pass
-        self._test_function(f, expected_name='f')
-
-    def test_bound_method(self):
-        class X:
-            def f(self): pass
-        x = X()
-        item = newtest.TestItem(x.f)
-        self.assertEqual(item.name, 'f')
-        self.assertEqual(item.call_via_class, False)
-        self.failUnless(item.cls is X)
-        self.failUnless(item.module is module)
-        self.assertEqual(item.file, file)
-
-    def test_unbound_method(self):
-        class X:
-            def f(self): pass
-        item = newtest.TestItem(X.f)
-        self.assertEqual(item.name, 'f')
-        self.assertEqual(item.call_via_class, True)
-        self.failUnless(item.cls is X)
-        self.failUnless(item.module is module)
-        self.assertEqual(item.file, file)
-
-    def test_class_instance(self):
-        class X:
-            def __call__(self): pass
-        item = newtest.TestItem(X())
-        self.assertEqual(item.name, '<unnamed object>')
-        self.assertEqual(item.call_via_class, False)
-        self.failUnless(item.cls is X)
-        self.failUnless(item.module is module)
-        self.assertEqual(item.file, file)
-
-    #XXX best way to trigger execptions in TestItem's constructor
-    # without getting rather complicated?
-
-    def test_docstrings(self):
-        class X:
-            def f(self):
-                "Method docstring"
-        item = newtest.TestItem(X.f)
-        self.assertEqual(item.docs, ('', '', "Method docstring"))
-
-        class X:
-            "Class docstring"
-            def f(self): pass
-        item = newtest.TestItem(X.f)
-        self.assertEqual(item.docs, ('', "Class docstring", ''))
-
-    def test_name_argument(self):
-        def f(): pass
-        item = newtest.TestItem(f, 'g')
-        self.assertEqual(item.name, 'g')
-
-
-class TestTestSuite(unittest.TestCase):
-    def check_names(self, test_suite, expected_item_names):
-        item_names = [item.name for item in test_suite.items]
-        item_names.sort()
-        expected_item_names.sort()
-        self.assertEqual(item_names, expected_item_names)
-
-    def test_items_from_callables(self):
-        def f(): pass
-        g = lambda: None
-        class X:
-            def thisone(self): pass
-        ts = newtest.TestSuite()
-        ts.add(f, g, X.thisone)
-        self.check_names(ts, ['f', '<lambda>', 'thisone'])
-        # add a bound method and an instance with __call__ attribute
-        class Y:
-            def thatone(self): pass
-        class Z:
-            def __call__(self): pass
-        ts.add(Y().thatone, Z())
-        self.check_names(ts, ['f', '<lambda>', 'thisone', 'thatone',
-                              '<unnamed object>'])
-
-    def test_items_from_class(self):
-        class X:
-            """Docstring - don't find it."""
-            def test_this(self): pass
-            def no_test(self): pass
-            def test_that(self): pass
-        ts = newtest.TestSuite()
-        ts.add(X)
-        self.check_names(ts, ['test_this', 'test_that'])
-
-    def test_items_from_module(self):
-        mod = new.module('new_module')
-        class X(newtest.TestCase):
-            "Don't add docstring."
-            def dont_add_method(self): pass
-            def test_this_method(self): pass
-        def dont_add(): pass
-        def add_this(): pass
-        for name, object in [('X', X), ('dont_add', dont_add),
-                             ('test_other_name', add_this)]:
-            setattr(mod, name, object)
-        ts = newtest.TestSuite()
-        ts.add(mod)
-        self.check_names(ts, ['test_this_method', 'test_other_name'])
-
-
-# used in unit tests above; placed here, so that TestTestItem is accessible
-module = inspect.getmodule(TestTestItem)
-file = inspect.getsourcefile(TestTestItem)
-
-
-if __name__ == '__main__':
-    unittest.main()



More information about the Pypy-commit mailing list