Source

pypy / pypy / conftest.py

import py, pytest, sys, os, textwrap
from inspect import isclass

PYTHON3 = os.getenv('PYTHON3') or py.path.local.sysfind('python3')
if PYTHON3 is not None:
    PYTHON3 = str(PYTHON3)

# pytest settings
rsyncdirs = ['.', '../lib-python', '../lib_pypy', '../demo']
rsyncignore = ['_cache']

# PyPy's command line extra options (these are added
# to py.test's standard options)
#
option = None


def braindead_deindent(self):
    """monkeypatch that wont end up doing stupid in the python tokenizer"""
    text = '\n'.join(self.lines)
    short = py.std.textwrap.dedent(text)
    newsource = py.code.Source()
    newsource.lines[:] = short.splitlines()
    return newsource

py.code.Source.deindent = braindead_deindent

def pytest_report_header():
    return "pytest-%s from %s" % (pytest.__version__, pytest.__file__)


def pytest_addhooks(pluginmanager):
    if sys.version_info < (3,):
        from pypy.tool.pytest.plugins import LeakFinder
        pluginmanager.register(LeakFinder())


def pytest_configure(config):
    global option
    option = config.option
    def py3k_skip(message):
        py.test.skip('[py3k] %s' % message)
    py.test.py3k_skip = py3k_skip

def _set_platform(opt, opt_str, value, parser):
    from pypy.config.translationoption import PLATFORMS
    from pypy.translator.platform import set_platform
    if value not in PLATFORMS:
        raise ValueError("%s not in %s" % (value, PLATFORMS))
    set_platform(value, None)

def pytest_addoption(parser):
    group = parser.getgroup("pypy options")
    group.addoption('--view', action="store_true", dest="view", default=False,
           help="view translation tests' flow graphs with Pygame")
    group.addoption('-A', '--runappdirect', action="store_true",
           default=False, dest="runappdirect",
           help="run applevel tests directly on the python interpreter " +
                "specified by --python")
    group.addoption('--python', type="string", default=PYTHON3,
           help="python interpreter to run appdirect tests with")
    group.addoption('--direct', action="store_true",
           default=False, dest="rundirect",
           help="run pexpect tests directly")
    group.addoption('-P', '--platform', action="callback", type="string",
           default="host", callback=_set_platform,
           help="set up tests to use specified platform as compile/run target")
    group = parser.getgroup("JIT options")
    group.addoption('--viewloops', action="store_true",
           default=False, dest="viewloops",
           help="show only the compiled loops")

def pytest_sessionstart():
    # have python subprocesses avoid startup customizations by default
    try:
        del os.environ['PYTHONSTARTUP']
    except KeyError:
        pass

def pytest_funcarg__space(request):
    from pypy.tool.pytest.objspace import gettestobjspace
    spaceconfig = getattr(request.cls, 'spaceconfig', {})
    return gettestobjspace(**spaceconfig)


#
# 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
        apparently earlier on "raises" was already added
        to module's globals.
    """
    try:
        import builtins
    except ImportError:
        import __builtin__ as builtins
    for helper in helpers:
        if not hasattr(builtins, helper):
            setattr(builtins, helper, getattr(py.test, helper))

def pytest_sessionstart(session):
    """ before session.main() is called. """
    # stick py.test raise in module globals -- carefully
    ensure_pytest_builtin_helpers()

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.
    """
    def accept_regular_test(self):
        if self.config.option.runappdirect:
            # only collect regular tests if we are in an 'app_test' directory,
            # or in test_lib_pypy
            names = self.listnames()
            return "app_test" in names or "test_lib_pypy" in names
        else:
            return True

    def funcnamefilter(self, name):
        if name.startswith('test_'):
            return self.accept_regular_test()
        if name.startswith('app_test_'):
            return True
        return False

    def classnamefilter(self, name):
        if name.startswith('Test'):
            return self.accept_regular_test()
        if name.startswith('AppTest'):
            return True
        if name.startswith('ExpectTest'):
            return True
        #XXX todo
        #if name.startswith('AppExpectTest'):
        #    return True
        return False

    def makeitem(self, name, obj):
        if isclass(obj) and self.classnamefilter(name):
            if name.startswith('AppTest'):
                from pypy.tool.pytest.apptest import AppClassCollector
                return AppClassCollector(name, parent=self)
            elif name.startswith('ExpectTest'):
                if self.config.option.rundirect:
                    return py.test.collect.Class(name, parent=self)
                from pypy.tool.pytest.expecttest import ExpectClassCollector
                return ExpectClassCollector(name, parent=self)
            # XXX todo
            #elif name.startswith('AppExpectTest'):
            #    if option.rundirect:
            #        return AppClassCollector(name, parent=self)
            #    return AppExpectClassCollector(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_'):
                assert not obj.func_code.co_flags & 32, \
                    "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)

def skip_on_missing_buildoption(**ropts):
    __tracebackhide__ = True
    import sys
    options = getattr(sys, 'pypy_translation_info', None)
    if options is None:
        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]:
            break
    else:
        return
    py.test.skip("need translated pypy with: %s, got %s"
                 %(ropts,options))

class LazyObjSpaceGetter(object):
    def __get__(self, obj, cls=None):
        from pypy.tool.pytest.objspace import gettestobjspace
        space = gettestobjspace()
        if cls:
            cls.space = space
        return space


def pytest_runtest_setup(__multicall__, item):
    if isinstance(item, py.test.collect.Function):
        appclass = item.getparent(PyPyClassCollector)
        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)
            appclass.obj.runappdirect = option.runappdirect

    __multicall__.execute()

def pytest_runtest_teardown(__multicall__, item):
    __multicall__.execute()

    if 'pygame' in sys.modules:
        assert option.view, ("should not invoke Pygame "
                             "if conftest.option.view is False")


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)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.