[pypy-svn] pypy default: Allow writing app-level helper functions on AppTests.

alex_gaynor commits-noreply at bitbucket.org
Sat Jan 8 09:52:13 CET 2011


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: 
Changeset: r40480:563412e706b1
Date: 2011-01-08 02:51 -0600
http://bitbucket.org/pypy/pypy/changeset/563412e706b1/

Log:	Allow writing app-level helper functions on AppTests.

diff --git a/pypy/conftest.py b/pypy/conftest.py
--- a/pypy/conftest.py
+++ b/pypy/conftest.py
@@ -1,6 +1,7 @@
-import py, sys, os
+import py, sys, os, textwrap, types
 from pypy.interpreter.gateway import app2interp_temp
 from pypy.interpreter.error import OperationError
+from pypy.interpreter.function import Method
 from pypy.tool.pytest import appsupport
 from pypy.tool.option import make_config, make_objspace
 from pypy.config.config import ConflictConfigError
@@ -14,8 +15,8 @@
 rsyncdirs = ['.', '../lib-python', '../lib_pypy', '../demo']
 rsyncignore = ['_cache']
 
-# PyPy's command line extra options (these are added 
-# to py.test's standard options) 
+# PyPy's command line extra options (these are added
+# to py.test's standard options)
 #
 
 def _set_platform(opt, opt_str, value, parser):
@@ -54,8 +55,8 @@
 
 _SPACECACHE={}
 def gettestobjspace(name=None, **kwds):
-    """ helper for instantiating and caching space's for testing. 
-    """ 
+    """ helper for instantiating and caching space's for testing.
+    """
     try:
         config = make_config(option, objspace=name, **kwds)
     except ConflictConfigError, e:
@@ -195,30 +196,30 @@
     except AttributeError:
         pass
 
-# 
-# Interfacing/Integrating with py.test's collection process 
+#
+# Interfacing/Integrating with py.test's collection process
 #
 #
 
 def ensure_pytest_builtin_helpers(helpers='skip raises'.split()):
     """ hack (py.test.) raises and skip into builtins, needed
-        for applevel tests to run directly on cpython but 
+        for applevel tests to run directly on cpython but
         apparently earlier on "raises" was already added
-        to module's globals. 
-    """ 
+        to module's globals.
+    """
     import __builtin__
-    for helper in helpers: 
+    for helper in helpers:
         if not hasattr(__builtin__, helper):
             setattr(__builtin__, helper, getattr(py.test, helper))
 
 def pytest_pycollect_makemodule(path, parent):
     return PyPyModule(path, parent)
 
-class PyPyModule(py.test.collect.Module): 
-    """ we take care of collecting classes both at app level 
-        and at interp-level (because we need to stick a space 
-        at the class) ourselves. 
-    """    
+class PyPyModule(py.test.collect.Module):
+    """ we take care of collecting classes both at app level
+        and at interp-level (because we need to stick a space
+        at the class) ourselves.
+    """
     def __init__(self, *args, **kwargs):
         if hasattr(sys, 'pypy_objspaceclass'):
             option.conf_iocapture = "sys" # pypy cannot do FD-based
@@ -252,16 +253,16 @@
         #    return True
         return False
 
-    def setup(self): 
+    def setup(self):
         # stick py.test raise in module globals -- carefully
-        ensure_pytest_builtin_helpers() 
-        super(PyPyModule, self).setup() 
-        #    if hasattr(mod, 'objspacename'): 
+        ensure_pytest_builtin_helpers()
+        super(PyPyModule, self).setup()
+        #    if hasattr(mod, 'objspacename'):
         #        mod.space = getttestobjspace(mod.objspacename)
 
-    def makeitem(self, name, obj): 
-        if isclass(obj) and self.classnamefilter(name): 
-            if name.startswith('AppTest'): 
+    def makeitem(self, name, obj):
+        if isclass(obj) and self.classnamefilter(name):
+            if name.startswith('AppTest'):
                 return AppClassCollector(name, parent=self)
             elif name.startswith('ExpectTest'):
                 if option.rundirect:
@@ -274,18 +275,18 @@
             #    return AppExpectClassCollector(name, parent=self)
             else:
                 return IntClassCollector(name, parent=self)
-            
-        elif hasattr(obj, 'func_code') and self.funcnamefilter(name): 
-            if name.startswith('app_test_'): 
+
+        elif hasattr(obj, 'func_code') and self.funcnamefilter(name):
+            if name.startswith('app_test_'):
                 assert not obj.func_code.co_flags & 32, \
-                    "generator app level functions? you must be joking" 
-                return AppTestFunction(name, parent=self) 
-            elif obj.func_code.co_flags & 32: # generator function 
-                return self.Generator(name, parent=self) 
-            else: 
-                return IntTestFunction(name, parent=self) 
+                    "generator app level functions? you must be joking"
+                return AppTestFunction(name, parent=self)
+            elif obj.func_code.co_flags & 32: # generator function
+                return self.Generator(name, parent=self)
+            else:
+                return IntTestFunction(name, parent=self)
 
-def skip_on_missing_buildoption(**ropts): 
+def skip_on_missing_buildoption(**ropts):
     __tracebackhide__ = True
     import sys
     options = getattr(sys, 'pypy_translation_info', None)
@@ -293,12 +294,12 @@
         py.test.skip("not running on translated pypy "
                      "(btw, i would need options: %s)" %
                      (ropts,))
-    for opt in ropts: 
-        if not options.has_key(opt) or options[opt] != ropts[opt]: 
+    for opt in ropts:
+        if not options.has_key(opt) or options[opt] != ropts[opt]:
             break
     else:
         return
-    py.test.skip("need translated pypy with: %s, got %s" 
+    py.test.skip("need translated pypy with: %s, got %s"
                  %(ropts,options))
 
 def getwithoutbinding(x, name):
@@ -361,8 +362,8 @@
             tb = sys.exc_info()[2]
             if e.match(space, space.w_KeyboardInterrupt):
                 raise OpErrKeyboardInterrupt, OpErrKeyboardInterrupt(), tb
-            appexcinfo = appsupport.AppExceptionInfo(space, e) 
-            if appexcinfo.traceback: 
+            appexcinfo = appsupport.AppExceptionInfo(space, e)
+            if appexcinfo.traceback:
                 raise AppError, AppError(appexcinfo), tb
             raise
 
@@ -420,7 +421,7 @@
         target = self.obj
         if option.runappdirect:
             return target()
-        space = gettestobjspace() 
+        space = gettestobjspace()
         filename = self._getdynfilename(target)
         func = app2interp_temp(target, filename=filename)
         print "executing", func
@@ -430,47 +431,56 @@
         code = getattr(func, 'im_func', func).func_code
         return "[%s:%s]" % (code.co_filename, code.co_firstlineno)
 
-class AppTestMethod(AppTestFunction): 
-
-    def setup(self): 
-        super(AppTestMethod, self).setup() 
-        instance = self.parent.obj 
-        w_instance = self.parent.w_instance 
-        space = instance.space  
-        for name in dir(instance): 
-            if name.startswith('w_'): 
+class AppTestMethod(AppTestFunction):
+    def setup(self):
+        super(AppTestMethod, self).setup()
+        instance = self.parent.obj
+        w_instance = self.parent.w_instance
+        space = instance.space
+        for name in dir(instance):
+            if name.startswith('w_'):
                 if option.runappdirect:
                     # if the value is a function living on the class,
                     # don't turn it into a bound method here
                     obj = getwithoutbinding(instance, name)
                     setattr(instance, name[2:], obj)
                 else:
-                    space.setattr(w_instance, space.wrap(name[2:]), 
-                                  getattr(instance, name)) 
+                    obj = getattr(instance, name)
+                    if isinstance(obj, types.MethodType):
+                        source = py.std.inspect.getsource(obj).lstrip()
+                        w_func = space.appexec([], textwrap.dedent("""
+                        ():
+                            %s
+                            return %s
+                        """) % (source, name))
+                        w_obj = Method(space, w_func, w_instance, space.w_None)
+                    else:
+                        w_obj = obj
+                    space.setattr(w_instance, space.wrap(name[2:]), w_obj)
 
     def runtest_perform(self):
         target = self.obj
         if option.runappdirect:
             return target()
-        space = target.im_self.space 
+        space = target.im_self.space
         filename = self._getdynfilename(target)
-        func = app2interp_temp(target.im_func, filename=filename) 
-        w_instance = self.parent.w_instance 
-        self.execute_appex(space, func, space, w_instance) 
+        func = app2interp_temp(target.im_func, filename=filename)
+        w_instance = self.parent.w_instance
+        self.execute_appex(space, func, space, w_instance)
 
 class PyPyClassCollector(py.test.collect.Class):
     def setup(self):
-        cls = self.obj 
+        cls = self.obj
         if not hasattr(cls, 'spaceconfig'):
-            cls.space = LazyObjSpaceGetter() 
+            cls.space = LazyObjSpaceGetter()
         else:
             assert hasattr(cls, 'space') # set by pytest_runtest_setup
-        super(PyPyClassCollector, self).setup() 
+        super(PyPyClassCollector, self).setup()
 
 class IntInstanceCollector(py.test.collect.Instance):
-    Function = IntTestFunction 
-    
-class IntClassCollector(PyPyClassCollector): 
+    Function = IntTestFunction
+
+class IntClassCollector(PyPyClassCollector):
     Instance = IntInstanceCollector
 
     def _haskeyword(self, keyword):
@@ -480,21 +490,21 @@
     def _keywords(self):
         return super(IntClassCollector, self)._keywords() + ['interplevel']
 
-class AppClassInstance(py.test.collect.Instance): 
-    Function = AppTestMethod 
+class AppClassInstance(py.test.collect.Instance):
+    Function = AppTestMethod
 
-    def setup(self): 
-        super(AppClassInstance, self).setup()         
-        instance = self.obj 
-        space = instance.space 
-        w_class = self.parent.w_class 
+    def setup(self):
+        super(AppClassInstance, self).setup()
+        instance = self.obj
+        space = instance.space
+        w_class = self.parent.w_class
         if option.runappdirect:
             self.w_instance = instance
         else:
             self.w_instance = space.call_function(w_class)
 
-class AppClassCollector(PyPyClassCollector): 
-    Instance = AppClassInstance 
+class AppClassCollector(PyPyClassCollector):
+    Instance = AppClassInstance
 
     def _haskeyword(self, keyword):
         return keyword == 'applevel' or \
@@ -503,11 +513,11 @@
     def _keywords(self):
         return super(AppClassCollector, self)._keywords() + ['applevel']
 
-    def setup(self): 
-        super(AppClassCollector, self).setup()        
-        cls = self.obj 
-        space = cls.space 
-        clsname = cls.__name__ 
+    def setup(self):
+        super(AppClassCollector, self).setup()
+        cls = self.obj
+        space = cls.space
+        clsname = cls.__name__
         if option.runappdirect:
             w_class = cls
         else:
@@ -515,7 +525,7 @@
                                           space.wrap(clsname),
                                           space.newtuple([]),
                                           space.newdict())
-        self.w_class = w_class 
+        self.w_class = w_class
 
 class ExpectTestMethod(py.test.collect.Function):
     def safe_name(target):

diff --git a/pypy/tool/pytest/test/test_pytestsupport.py b/pypy/tool/pytest/test/test_pytestsupport.py
--- a/pypy/tool/pytest/test/test_pytestsupport.py
+++ b/pypy/tool/pytest/test/test_pytestsupport.py
@@ -3,7 +3,8 @@
 from pypy.interpreter.argument import Arguments
 from pypy.interpreter.pycode import PyCode
 from pypy.interpreter.pyframe import PyFrame
-from pypy.tool.pytest.appsupport import AppFrame, build_pytest_assertion, AppExceptionInfo
+from pypy.tool.pytest.appsupport import (AppFrame, build_pytest_assertion,
+    AppExceptionInfo)
 import py
 from pypy.tool.udir import udir
 import os
@@ -33,7 +34,7 @@
         assert x == 43
     t = app2interp_temp(app_test_func)
     f = t.get_function(space)
-    space.setitem(space.builtin.w_dict, space.wrap('AssertionError'), 
+    space.setitem(space.builtin.w_dict, space.wrap('AssertionError'),
                   build_pytest_assertion(space))
     try:
         f.call_args(Arguments(None, []))
@@ -43,14 +44,14 @@
     else:
         assert False, "got no exception!"
 
-def app_test_exception(): 
-    try: 
+def app_test_exception():
+    try:
         raise AssertionError("42")
-    except AssertionError: 
-        pass 
-    else: 
+    except AssertionError:
+        pass
+    else:
         raise AssertionError, "app level AssertionError mixup!"
-    
+
 def app_test_exception_with_message():
     try:
         assert 0, "Failed"
@@ -58,20 +59,20 @@
         assert e.msg == "Failed"
 
 
-def test_appexecinfo(space): 
-    try: 
-        space.appexec([], "(): raise ValueError") 
-    except OperationError, e: 
+def test_appexecinfo(space):
+    try:
+        space.appexec([], "(): raise ValueError")
+    except OperationError, e:
         appex = AppExceptionInfo(space, e)
-    else: 
-        py.test.fail("did not raise!") 
-    assert appex.exconly().find('ValueError') != -1 
-    assert appex.exconly(tryshort=True).find('ValueError') != -1 
-    assert appex.errisinstance(ValueError) 
-    assert not appex.errisinstance(RuntimeError) 
-    class A: 
+    else:
+        py.test.fail("did not raise!")
+    assert appex.exconly().find('ValueError') != -1
+    assert appex.exconly(tryshort=True).find('ValueError') != -1
+    assert appex.errisinstance(ValueError)
+    assert not appex.errisinstance(RuntimeError)
+    class A:
         pass
-    assert not appex.errisinstance(A) 
+    assert not appex.errisinstance(A)
 
 
 def test_fakedexception(space):
@@ -80,7 +81,7 @@
         raise PicklingError("SomeMessage")
     space.setitem(space.builtin.w_dict, space.wrap('raise_error'),
                   space.wrap(raise_error))
-    
+
     try:
         space.appexec([], "(): raise_error()")
     except OperationError, e:
@@ -89,21 +90,27 @@
         py.test.fail("did not raise!")
     assert "PicklingError" in appex.exconly()
 
-class AppTestWithWrappedInterplevelAttributes: 
-    def setup_class(cls): 
+class AppTestWithWrappedInterplevelAttributes:
+    def setup_class(cls):
         space = cls.space
-        cls.w_some1 = space.wrap(42) 
+        cls.w_some1 = space.wrap(42)
 
-    def setup_method(self, meth): 
+    def setup_method(self, meth):
         self.w_some2 = self.space.wrap(23)
 
-    def test_values_arrive(self): 
-        assert self.some1 == 42  
-        assert self.some2 == 23 
+    def test_values_arrive(self):
+        assert self.some1 == 42
+        assert self.some2 == 23
 
-    def test_values_arrive2(self): 
+    def test_values_arrive2(self):
         assert self.some1 == 42
 
+    def w_compute(self, x):
+        return x + 2
+
+    def test_equal(self):
+        assert self.compute(3) == 5
+
 def test_expectcollect(testdir):
     py.test.importorskip("pexpect")
     conftestpath.copy(testdir.tmpdir)
@@ -132,7 +139,7 @@
                 pass
     """)
     ev, = sorter.getreports("pytest_runtest_logreport")
-    assert ev.passed 
+    assert ev.passed
     sfn = ev.item.safe_filename()
     print sfn
     assert sfn == 'test_safe_filename_test_safe_filename_ExpectTestOne_paren_test_one_1.py'
@@ -155,4 +162,4 @@
     ev, = sorter.getreports("pytest_runtest_logreport")
     assert ev.failed
     assert 'NameError' in ev.longrepr.reprcrash.message
-    assert 'blow' in ev.longrepr.reprcrash.message    
+    assert 'blow' in ev.longrepr.reprcrash.message


More information about the Pypy-commit mailing list