Author: Ronan Lamy <ronan.l...@gmail.com> Branch: Changeset: r85078:18006cfc913c Date: 2016-06-10 14:44 +0100 http://bitbucket.org/pypy/pypy/changeset/18006cfc913c/
Log: Merge branch 'testing-cleanup' Simplify handling of interp-level tests and make it more forward- compatible. diff --git a/pypy/conftest.py b/pypy/conftest.py --- a/pypy/conftest.py +++ b/pypy/conftest.py @@ -76,6 +76,20 @@ def pytest_pycollect_makemodule(path, parent): return PyPyModule(path, parent) +def is_applevel(item): + from pypy.tool.pytest.apptest import AppTestFunction + return isinstance(item, AppTestFunction) + +def pytest_collection_modifyitems(config, items): + if config.option.runappdirect: + return + for item in items: + if isinstance(item, py.test.Function): + if is_applevel(item): + item.add_marker('applevel') + else: + item.add_marker('interplevel') + 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 @@ -110,9 +124,6 @@ if name.startswith('AppTest'): from pypy.tool.pytest.apptest import AppClassCollector return AppClassCollector(name, parent=self) - else: - from pypy.tool.pytest.inttest import IntClassCollector - return IntClassCollector(name, parent=self) elif hasattr(obj, 'func_code') and self.funcnamefilter(name): if name.startswith('app_test_'): @@ -120,11 +131,7 @@ "generator app level functions? you must be joking" from pypy.tool.pytest.apptest import AppTestFunction return AppTestFunction(name, parent=self) - elif obj.func_code.co_flags & 32: # generator function - return pytest.Generator(name, parent=self) - else: - from pypy.tool.pytest.inttest import IntTestFunction - return IntTestFunction(name, parent=self) + return super(PyPyModule, self).makeitem(name, obj) def skip_on_missing_buildoption(**ropts): __tracebackhide__ = True @@ -153,28 +160,19 @@ def pytest_runtest_setup(__multicall__, item): if isinstance(item, py.test.collect.Function): - appclass = item.getparent(PyPyClassCollector) + appclass = item.getparent(py.test.Class) if appclass is not None: # Make cls.space and cls.runappdirect available in tests. spaceconfig = getattr(appclass.obj, 'spaceconfig', None) if spaceconfig is not None: from pypy.tool.pytest.objspace import gettestobjspace appclass.obj.space = gettestobjspace(**spaceconfig) + else: + appclass.obj.space = LazyObjSpaceGetter() appclass.obj.runappdirect = option.runappdirect __multicall__.execute() -class PyPyClassCollector(py.test.collect.Class): - # All pypy Test classes have a "space" member. - def setup(self): - cls = self.obj - if not hasattr(cls, 'spaceconfig'): - cls.space = LazyObjSpaceGetter() - else: - assert hasattr(cls, 'space') # set by pytest_runtest_setup - super(PyPyClassCollector, self).setup() - - def pytest_ignore_collect(path): return path.check(link=1) diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -458,14 +458,17 @@ decl = str(decl) + "\n" yield self.st, decl, 'x', (1, 2, 3, 4) + def test_closure_error(self): source = """if 1: def f(a): del a def x(): a """ - exc = py.test.raises(SyntaxError, self.run, source).value - assert exc.msg == "Can't delete variable used in nested scopes: 'a'" + with py.test.raises(SyntaxError) as excinfo: + self.run(source) + msg = excinfo.value.msg + assert msg == "Can't delete variable used in nested scopes: 'a'" def test_try_except_finally(self): yield self.simple_test, """ @@ -879,7 +882,20 @@ """ self.simple_test(source, 'ok', 1) - def test_remove_docstring(self): + @py.test.mark.parametrize('expr, result', [ + ("f1.__doc__", None), + ("f2.__doc__", 'docstring'), + ("f2()", 'docstring'), + ("f3.__doc__", None), + ("f3()", 'bar'), + ("C1.__doc__", None), + ("C2.__doc__", 'docstring'), + ("C3.field", 'not docstring'), + ("C4.field", 'docstring'), + ("C4.__doc__", 'docstring'), + ("C4.__doc__", 'docstring'), + ("__doc__", None),]) + def test_remove_docstring(self, expr, result): source = '"module_docstring"\n' + """if 1: def f1(): 'docstring' @@ -903,19 +919,7 @@ code_w.remove_docstrings(self.space) dict_w = self.space.newdict(); code_w.exec_code(self.space, dict_w, dict_w) - - yield self.check, dict_w, "f1.__doc__", None - yield self.check, dict_w, "f2.__doc__", 'docstring' - yield self.check, dict_w, "f2()", 'docstring' - yield self.check, dict_w, "f3.__doc__", None - yield self.check, dict_w, "f3()", 'bar' - yield self.check, dict_w, "C1.__doc__", None - yield self.check, dict_w, "C2.__doc__", 'docstring' - yield self.check, dict_w, "C3.field", 'not docstring' - yield self.check, dict_w, "C4.field", 'docstring' - yield self.check, dict_w, "C4.__doc__", 'docstring' - yield self.check, dict_w, "C4.__doc__", 'docstring' - yield self.check, dict_w, "__doc__", None + self.check(dict_w, expr, result) def test_assert_skipping(self): space = self.space @@ -1111,7 +1115,7 @@ return d['f'](5) """) assert 'generator' in space.str_w(space.repr(w_generator)) - + def test_list_comprehension(self): source = "def f(): [i for i in l]" source2 = "def f(): [i for i in l for j in l]" diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py --- a/pypy/module/_socket/test/test_sock_app.py +++ b/pypy/module/_socket/test/test_sock_app.py @@ -671,13 +671,11 @@ class AppTestSocketTCP: HOST = 'localhost' - - def setup_class(cls): - cls.space = space + spaceconfig = {'usemodules': ['_socket', 'array']} def setup_method(self, method): - w_HOST = space.wrap(self.HOST) - self.w_serv = space.appexec([w_socket, w_HOST], + w_HOST = self.space.wrap(self.HOST) + self.w_serv =self.space.appexec([w_socket, w_HOST], '''(_socket, HOST): serv = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM) serv.bind((HOST, 0)) @@ -687,7 +685,7 @@ def teardown_method(self, method): if hasattr(self, 'w_serv'): - space.appexec([self.w_serv], '(serv): serv.close()') + self.space.appexec([self.w_serv], '(serv): serv.close()') self.w_serv = None def test_timeout(self): @@ -803,8 +801,7 @@ class AppTestErrno: - def setup_class(cls): - cls.space = space + spaceconfig = {'usemodules': ['_socket']} def test_errno(self): from socket import socket, AF_INET, SOCK_STREAM, error diff --git a/pypy/module/_vmprof/test/test__vmprof.py b/pypy/module/_vmprof/test/test__vmprof.py --- a/pypy/module/_vmprof/test/test__vmprof.py +++ b/pypy/module/_vmprof/test/test__vmprof.py @@ -3,8 +3,9 @@ from pypy.tool.pytest.objspace import gettestobjspace class AppTestVMProf(object): + spaceconfig = {'usemodules': ['_vmprof', 'struct']} + def setup_class(cls): - cls.space = gettestobjspace(usemodules=['_vmprof', 'struct']) cls.w_tmpfilename = cls.space.wrap(str(udir.join('test__vmprof.1'))) cls.w_tmpfilename2 = cls.space.wrap(str(udir.join('test__vmprof.2'))) @@ -17,7 +18,7 @@ import struct, sys, gc WORD = struct.calcsize('l') - + def count(s): i = 0 count = 0 @@ -44,7 +45,7 @@ else: raise AssertionError(ord(s[i])) return count - + import _vmprof gc.collect() # try to make the weakref list deterministic gc.collect() # by freeing all dead code objects diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -13,14 +13,15 @@ import sys import signal +USEMODULES = ['binascii', 'posix', 'struct', 'time'] +if os.name != 'nt': + USEMODULES += ['fcntl'] +else: + # On windows, os.popen uses the subprocess module + USEMODULES += ['_rawffi', 'thread', 'signal'] + def setup_module(mod): - usemodules = ['binascii', 'posix', 'struct', 'time'] - if os.name != 'nt': - usemodules += ['fcntl'] - else: - # On windows, os.popen uses the subprocess module - usemodules += ['_rawffi', 'thread', 'signal'] - mod.space = gettestobjspace(usemodules=usemodules) + mod.space = gettestobjspace(usemodules=USEMODULES) mod.path = udir.join('posixtestfile.txt') mod.path.write("this is a test") mod.path2 = udir.join('test_posix2-') @@ -49,9 +50,10 @@ class AppTestPosix: + spaceconfig = {'usemodules': USEMODULES} def setup_class(cls): - cls.space = space + space = cls.space cls.w_runappdirect = space.wrap(cls.runappdirect) cls.w_posix = space.appexec([], GET_POSIX) cls.w_path = space.wrap(str(path)) @@ -1145,14 +1147,10 @@ class AppTestEnvironment(object): def setup_class(cls): - cls.space = space - cls.w_posix = space.appexec([], "(): import %s as m ; return m" % os.name) - cls.w_os = space.appexec([], "(): import os; return os") cls.w_path = space.wrap(str(path)) def test_environ(self): - posix = self.posix - os = self.os + import posix assert posix.environ['PATH'] del posix.environ['PATH'] def fn(): posix.environ['PATH'] @@ -1160,7 +1158,7 @@ if hasattr(__import__(os.name), "unsetenv"): def test_unsetenv_nonexisting(self): - os = self.os + import os os.unsetenv("XYZABC") #does not raise try: os.environ["ABCABC"] @@ -1178,8 +1176,6 @@ class AppTestPosixUnicode: def setup_class(cls): - cls.space = space - cls.w_posix = space.appexec([], GET_POSIX) if cls.runappdirect: # Can't change encoding try: @@ -1187,8 +1183,8 @@ except UnicodeEncodeError: py.test.skip("encoding not good enough") else: - cls.save_fs_encoding = space.sys.filesystemencoding - space.sys.filesystemencoding = "utf-8" + cls.save_fs_encoding = cls.space.sys.filesystemencoding + cls.space.sys.filesystemencoding = "utf-8" def teardown_class(cls): try: @@ -1198,22 +1194,25 @@ def test_stat_unicode(self): # test that passing unicode would not raise UnicodeDecodeError + import posix try: - self.posix.stat(u"ą") + posix.stat(u"ą") except OSError: pass def test_open_unicode(self): # Ensure passing unicode doesn't raise UnicodeEncodeError + import posix try: - self.posix.open(u"ą", self.posix.O_WRONLY) + posix.open(u"ą", posix.O_WRONLY) except OSError: pass def test_remove_unicode(self): # See 2 above ;) + import posix try: - self.posix.remove(u"ą") + posix.remove(u"ą") except OSError: pass diff --git a/pypy/tool/pytest/apptest.py b/pypy/tool/pytest/apptest.py --- a/pypy/tool/pytest/apptest.py +++ b/pypy/tool/pytest/apptest.py @@ -13,7 +13,6 @@ from pypy.interpreter.function import Method from pypy.tool.pytest import appsupport from pypy.tool.pytest.objspace import gettestobjspace -from pypy.conftest import PyPyClassCollector from inspect import getmro @@ -21,13 +20,8 @@ def __init__(self, excinfo): self.excinfo = excinfo -marker = py.test.mark.applevel class AppTestFunction(py.test.collect.Function): - def __init__(self, *args, **kwargs): - super(AppTestFunction, self).__init__(*args, **kwargs) - self._request.applymarker(marker) - def _prunetraceback(self, traceback): return traceback @@ -122,7 +116,7 @@ self.w_instance = space.call_function(w_class) -class AppClassCollector(PyPyClassCollector): +class AppClassCollector(py.test.Class): Instance = AppClassInstance def setup(self): diff --git a/pypy/tool/pytest/inttest.py b/pypy/tool/pytest/inttest.py deleted file mode 100644 --- a/pypy/tool/pytest/inttest.py +++ /dev/null @@ -1,52 +0,0 @@ -# Collects and executes interpreter-level tests. -# -# Most pypy tests are of this kind. - -import py -import sys -from pypy.interpreter.error import OperationError -from pypy.conftest import PyPyClassCollector - - -def check_keyboard_interrupt(e): - # we cannot easily convert w_KeyboardInterrupt to KeyboardInterrupt - # in general without a space -- here is an approximation - try: - if e.w_type.name == 'KeyboardInterrupt': - tb = sys.exc_info()[2] - raise KeyboardInterrupt, KeyboardInterrupt(), tb - except AttributeError: - pass - - -marker = py.test.mark.interplevel - - -class IntTestFunction(py.test.collect.Function): - def __init__(self, *args, **kwargs): - super(IntTestFunction, self).__init__(*args, **kwargs) - self._request.applymarker(marker) - - def runtest(self): - try: - super(IntTestFunction, self).runtest() - except OperationError as e: - check_keyboard_interrupt(e) - raise - except Exception as e: - cls = e.__class__ - while cls is not Exception: - if cls.__name__ == 'DistutilsPlatformError': - from distutils.errors import DistutilsPlatformError - if isinstance(e, DistutilsPlatformError): - py.test.skip('%s: %s' % (e.__class__.__name__, e)) - cls = cls.__bases__[0] - raise - - -class IntInstanceCollector(py.test.collect.Instance): - Function = IntTestFunction - - -class IntClassCollector(PyPyClassCollector): - Instance = IntInstanceCollector diff --git a/pypy/tool/pytest/test/test_appsupport.py b/pypy/tool/pytest/test/test_appsupport.py --- a/pypy/tool/pytest/test/test_appsupport.py +++ b/pypy/tool/pytest/test/test_appsupport.py @@ -27,11 +27,11 @@ result = testdir.runpytest("--collectonly") assert result.ret == 0 result.stdout.fnmatch_lines([ - "*IntTestFunction*test_func*", - "*IntClassCollector*TestClassInt*", - "*IntTestFunction*test_method*", + "*Function*test_func*", + "*Class*TestClassInt*", + "*Function*test_method*", "*AppClassCollector*AppTestClass*", - "*AppTestMethod*", + "*AppTestMethod*", ]) class TestSpaceConfig: @@ -133,5 +133,5 @@ x = 43 info = raises(ZeroDivisionError, "x/0") - assert info.type is ZeroDivisionError - assert isinstance(info.value, ZeroDivisionError) + assert info.type is ZeroDivisionError + assert isinstance(info.value, ZeroDivisionError) diff --git a/pypy/tool/pytest/test/test_conftest1.py b/pypy/tool/pytest/test/test_conftest1.py --- a/pypy/tool/pytest/test/test_conftest1.py +++ b/pypy/tool/pytest/test/test_conftest1.py @@ -20,11 +20,3 @@ assert not skipped and not failed assert "app_test_something" in passed[0].nodeid assert "test_method_app" in passed[1].nodeid - - def test_appdirect(self, testdir): - sorter = testdir.inline_run(innertest, '-m', 'applevel', '--runappdirect') - passed, skipped, failed = sorter.listoutcomes() - assert len(passed) == 2 - print passed - assert "app_test_something" in passed[0].nodeid - assert "test_method_app" in passed[1].nodeid _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit