Blame runtests.py

Packit 562c7a
#!/usr/bin/env python
Packit 562c7a
Packit 562c7a
import atexit
Packit 562c7a
import os
Packit 562c7a
import sys
Packit 562c7a
import re
Packit 562c7a
import gc
Packit 562c7a
import locale
Packit 562c7a
import shutil
Packit 562c7a
import time
Packit 562c7a
import unittest
Packit 562c7a
import doctest
Packit 562c7a
import operator
Packit 562c7a
import subprocess
Packit 562c7a
import tempfile
Packit 562c7a
import traceback
Packit 562c7a
import warnings
Packit 562c7a
import zlib
Packit 562c7a
Packit 562c7a
try:
Packit 562c7a
    import platform
Packit 562c7a
    IS_PYPY = platform.python_implementation() == 'PyPy'
Packit 562c7a
    IS_CPYTHON = platform.python_implementation() == 'CPython'
Packit 562c7a
except (ImportError, AttributeError):
Packit 562c7a
    IS_CPYTHON = True
Packit 562c7a
    IS_PYPY = False
Packit 562c7a
Packit 562c7a
from io import open as io_open
Packit 562c7a
try:
Packit 562c7a
    from StringIO import StringIO
Packit 562c7a
except ImportError:
Packit 562c7a
    from io import StringIO  # doesn't accept 'str' in Py2
Packit 562c7a
Packit 562c7a
try:
Packit 562c7a
    import cPickle as pickle
Packit 562c7a
except ImportError:
Packit 562c7a
    import pickle
Packit 562c7a
Packit 562c7a
try:
Packit 562c7a
    import threading
Packit 562c7a
except ImportError: # No threads, no problems
Packit 562c7a
    threading = None
Packit 562c7a
Packit 562c7a
try:
Packit 562c7a
    from collections import defaultdict
Packit 562c7a
except ImportError:
Packit 562c7a
    class defaultdict(object):
Packit 562c7a
        def __init__(self, default_factory=lambda : None):
Packit 562c7a
            self._dict = {}
Packit 562c7a
            self.default_factory = default_factory
Packit 562c7a
        def __getitem__(self, key):
Packit 562c7a
            if key not in self._dict:
Packit 562c7a
                self._dict[key] = self.default_factory()
Packit 562c7a
            return self._dict[key]
Packit 562c7a
        def __setitem__(self, key, value):
Packit 562c7a
            self._dict[key] = value
Packit 562c7a
        def __contains__(self, key):
Packit 562c7a
            return key in self._dict
Packit 562c7a
        def __repr__(self):
Packit 562c7a
            return repr(self._dict)
Packit 562c7a
        def __nonzero__(self):
Packit 562c7a
            return bool(self._dict)
Packit 562c7a
Packit 562c7a
try:
Packit 562c7a
    basestring
Packit 562c7a
except NameError:
Packit 562c7a
    basestring = str
Packit 562c7a
Packit 562c7a
WITH_CYTHON = True
Packit 562c7a
CY3_DIR = None
Packit 562c7a
Packit 562c7a
from distutils.command.build_ext import build_ext as _build_ext
Packit 562c7a
from distutils import sysconfig
Packit 562c7a
from distutils import ccompiler
Packit 562c7a
_to_clean = []
Packit 562c7a
Packit 562c7a
@atexit.register
Packit 562c7a
def _cleanup_files():
Packit 562c7a
    """
Packit 562c7a
    This is only used on Cygwin to clean up shared libraries that are unsafe
Packit 562c7a
    to delete while the test suite is running.
Packit 562c7a
    """
Packit 562c7a
Packit 562c7a
    for filename in _to_clean:
Packit 562c7a
        if os.path.isdir(filename):
Packit 562c7a
            shutil.rmtree(filename, ignore_errors=True)
Packit 562c7a
        else:
Packit 562c7a
            try:
Packit 562c7a
                os.remove(filename)
Packit 562c7a
            except OSError:
Packit 562c7a
                pass
Packit 562c7a
Packit 562c7a
Packit 562c7a
def get_distutils_distro(_cache=[]):
Packit 562c7a
    if _cache:
Packit 562c7a
        return _cache[0]
Packit 562c7a
    # late import to accommodate for setuptools override
Packit 562c7a
    from distutils.dist import Distribution
Packit 562c7a
    distutils_distro = Distribution()
Packit 562c7a
Packit 562c7a
    if sys.platform == 'win32':
Packit 562c7a
        # TODO: Figure out why this hackery (see http://thread.gmane.org/gmane.comp.python.cython.devel/8280/).
Packit 562c7a
        config_files = distutils_distro.find_config_files()
Packit 562c7a
        try: config_files.remove('setup.cfg')
Packit 562c7a
        except ValueError: pass
Packit 562c7a
        distutils_distro.parse_config_files(config_files)
Packit 562c7a
Packit 562c7a
        cfgfiles = distutils_distro.find_config_files()
Packit 562c7a
        try: cfgfiles.remove('setup.cfg')
Packit 562c7a
        except ValueError: pass
Packit 562c7a
        distutils_distro.parse_config_files(cfgfiles)
Packit 562c7a
    _cache.append(distutils_distro)
Packit 562c7a
    return distutils_distro
Packit 562c7a
Packit 562c7a
Packit 562c7a
EXT_DEP_MODULES = {
Packit 562c7a
    'tag:numpy':    'numpy',
Packit 562c7a
    'tag:pythran':  'pythran',
Packit 562c7a
    'tag:setuptools':  'setuptools.sandbox',
Packit 562c7a
    'tag:asyncio':  'asyncio',
Packit 562c7a
    'tag:pstats':   'pstats',
Packit 562c7a
    'tag:posix':    'posix',
Packit 562c7a
    'tag:array':    'array',
Packit 562c7a
    'tag:coverage': 'Cython.Coverage',
Packit 562c7a
    'Coverage':     'Cython.Coverage',
Packit 562c7a
    'tag:ipython':  'IPython.testing.globalipapp',
Packit 562c7a
    'tag:jedi':     'jedi_BROKEN_AND_DISABLED',
Packit 562c7a
}
Packit 562c7a
Packit 562c7a
def patch_inspect_isfunction():
Packit 562c7a
    import inspect
Packit 562c7a
    orig_isfunction = inspect.isfunction
Packit 562c7a
    def isfunction(obj):
Packit 562c7a
        return orig_isfunction(obj) or type(obj).__name__ == 'cython_function_or_method'
Packit 562c7a
    isfunction._orig_isfunction = orig_isfunction
Packit 562c7a
    inspect.isfunction = isfunction
Packit 562c7a
Packit 562c7a
def unpatch_inspect_isfunction():
Packit 562c7a
    import inspect
Packit 562c7a
    try:
Packit 562c7a
        orig_isfunction = inspect.isfunction._orig_isfunction
Packit 562c7a
    except AttributeError:
Packit 562c7a
        pass
Packit 562c7a
    else:
Packit 562c7a
        inspect.isfunction = orig_isfunction
Packit 562c7a
Packit 562c7a
def def_to_cdef(source):
Packit 562c7a
    '''
Packit 562c7a
    Converts the module-level def methods into cdef methods, i.e.
Packit 562c7a
Packit 562c7a
        @decorator
Packit 562c7a
        def foo([args]):
Packit 562c7a
            """
Packit 562c7a
            [tests]
Packit 562c7a
            """
Packit 562c7a
            [body]
Packit 562c7a
Packit 562c7a
    becomes
Packit 562c7a
Packit 562c7a
        def foo([args]):
Packit 562c7a
            """
Packit 562c7a
            [tests]
Packit 562c7a
            """
Packit 562c7a
            return foo_c([args])
Packit 562c7a
Packit 562c7a
        cdef foo_c([args]):
Packit 562c7a
            [body]
Packit 562c7a
    '''
Packit 562c7a
    output = []
Packit 562c7a
    skip = False
Packit 562c7a
    def_node = re.compile(r'def (\w+)\(([^()*]*)\):').match
Packit 562c7a
    lines = iter(source.split('\n'))
Packit 562c7a
    for line in lines:
Packit 562c7a
        if not line.strip():
Packit 562c7a
            output.append(line)
Packit 562c7a
            continue
Packit 562c7a
Packit 562c7a
        if skip:
Packit 562c7a
            if line[0] != ' ':
Packit 562c7a
                skip = False
Packit 562c7a
            else:
Packit 562c7a
                continue
Packit 562c7a
Packit 562c7a
        if line[0] == '@':
Packit 562c7a
            skip = True
Packit 562c7a
            continue
Packit 562c7a
Packit 562c7a
        m = def_node(line)
Packit 562c7a
        if m:
Packit 562c7a
            name = m.group(1)
Packit 562c7a
            args = m.group(2)
Packit 562c7a
            if args:
Packit 562c7a
                args_no_types = ", ".join(arg.split()[-1] for arg in args.split(','))
Packit 562c7a
            else:
Packit 562c7a
                args_no_types = ""
Packit 562c7a
            output.append("def %s(%s):" % (name, args_no_types))
Packit 562c7a
            line = next(lines)
Packit 562c7a
            if '"""' in line:
Packit 562c7a
                has_docstring = True
Packit 562c7a
                output.append(line)
Packit 562c7a
                for line in lines:
Packit 562c7a
                    output.append(line)
Packit 562c7a
                    if '"""' in line:
Packit 562c7a
                        break
Packit 562c7a
            else:
Packit 562c7a
                has_docstring = False
Packit 562c7a
            output.append("    return %s_c(%s)" % (name, args_no_types))
Packit 562c7a
            output.append('')
Packit 562c7a
            output.append("cdef %s_c(%s):" % (name, args))
Packit 562c7a
            if not has_docstring:
Packit 562c7a
                output.append(line)
Packit 562c7a
Packit 562c7a
        else:
Packit 562c7a
            output.append(line)
Packit 562c7a
Packit 562c7a
    return '\n'.join(output)
Packit 562c7a
Packit 562c7a
Packit 562c7a
def exclude_extension_in_pyver(*versions):
Packit 562c7a
    def check(ext):
Packit 562c7a
        return EXCLUDE_EXT if sys.version_info[:2] in versions else ext
Packit 562c7a
    return check
Packit 562c7a
Packit 562c7a
Packit 562c7a
def update_linetrace_extension(ext):
Packit 562c7a
    ext.define_macros.append(('CYTHON_TRACE', 1))
Packit 562c7a
    return ext
Packit 562c7a
Packit 562c7a
Packit 562c7a
def update_numpy_extension(ext):
Packit 562c7a
    import numpy
Packit 562c7a
    from numpy.distutils.misc_util import get_info
Packit 562c7a
Packit 562c7a
    ext.include_dirs.append(numpy.get_include())
Packit 562c7a
Packit 562c7a
    # We need the npymath library for numpy.math.
Packit 562c7a
    # This is typically a static-only library.
Packit 562c7a
    for attr, value in get_info('npymath').items():
Packit 562c7a
        getattr(ext, attr).extend(value)
Packit 562c7a
Packit 562c7a
Packit 562c7a
def update_openmp_extension(ext):
Packit 562c7a
    ext.openmp = True
Packit 562c7a
    language = ext.language
Packit 562c7a
Packit 562c7a
    if language == 'cpp':
Packit 562c7a
        flags = OPENMP_CPP_COMPILER_FLAGS
Packit 562c7a
    else:
Packit 562c7a
        flags = OPENMP_C_COMPILER_FLAGS
Packit 562c7a
Packit 562c7a
    if flags:
Packit 562c7a
        compile_flags, link_flags = flags
Packit 562c7a
        ext.extra_compile_args.extend(compile_flags.split())
Packit 562c7a
        ext.extra_link_args.extend(link_flags.split())
Packit 562c7a
        return ext
Packit 562c7a
    elif sys.platform == 'win32':
Packit 562c7a
        return ext
Packit 562c7a
Packit 562c7a
    return EXCLUDE_EXT
Packit 562c7a
Packit 562c7a
Packit 562c7a
def update_cpp11_extension(ext):
Packit 562c7a
    """
Packit 562c7a
        update cpp11 extensions that will run on versions of gcc >4.8
Packit 562c7a
    """
Packit 562c7a
    gcc_version = get_gcc_version(ext.language)
Packit 562c7a
    if gcc_version is not None:
Packit 562c7a
        compiler_version = gcc_version.group(1)
Packit 562c7a
        if float(compiler_version) > 4.8:
Packit 562c7a
            ext.extra_compile_args.append("-std=c++11")
Packit 562c7a
        return ext    
Packit 562c7a
    return EXCLUDE_EXT
Packit 562c7a
Packit 562c7a
Packit 562c7a
def get_gcc_version(language):
Packit 562c7a
    """
Packit 562c7a
        finds gcc version using Popen
Packit 562c7a
    """
Packit 562c7a
    if language == 'cpp':
Packit 562c7a
        cc = sysconfig.get_config_var('CXX')
Packit 562c7a
    else:
Packit 562c7a
        cc = sysconfig.get_config_var('CC')
Packit 562c7a
    if not cc:
Packit 562c7a
       cc = ccompiler.get_default_compiler()
Packit 562c7a
Packit 562c7a
    if not cc:
Packit 562c7a
        return None
Packit 562c7a
Packit 562c7a
    # For some reason, cc can be e.g. 'gcc -pthread'
Packit 562c7a
    cc = cc.split()[0]
Packit 562c7a
Packit 562c7a
    # Force english output
Packit 562c7a
    env = os.environ.copy()
Packit 562c7a
    env['LC_MESSAGES'] = 'C'
Packit 562c7a
    matcher = re.compile(r"gcc version (\d+\.\d+)").search
Packit 562c7a
    try:
Packit 562c7a
        p = subprocess.Popen([cc, "-v"], stderr=subprocess.PIPE, env=env)
Packit 562c7a
    except EnvironmentError:
Packit 562c7a
        # Be compatible with Python 3
Packit 562c7a
        warnings.warn("Unable to find the %s compiler: %s: %s" %
Packit 562c7a
                      (language, os.strerror(sys.exc_info()[1].errno), cc))
Packit 562c7a
        return None
Packit 562c7a
    _, output = p.communicate()
Packit 562c7a
    output = output.decode(locale.getpreferredencoding() or 'ASCII', 'replace')
Packit 562c7a
    gcc_version = matcher(output)
Packit 562c7a
    return gcc_version
Packit 562c7a
Packit 562c7a
Packit 562c7a
def get_openmp_compiler_flags(language):
Packit 562c7a
    """
Packit 562c7a
    As of gcc 4.2, it supports OpenMP 2.5. Gcc 4.4 implements 3.0. We don't
Packit 562c7a
    (currently) check for other compilers.
Packit 562c7a
Packit 562c7a
    returns a two-tuple of (CFLAGS, LDFLAGS) to build the OpenMP extension
Packit 562c7a
    """
Packit 562c7a
    gcc_version = get_gcc_version(language)
Packit 562c7a
Packit 562c7a
    if not gcc_version:
Packit 562c7a
        if sys.platform == 'win32':
Packit 562c7a
            return '/openmp', ''
Packit 562c7a
        else:
Packit 562c7a
            return None # not gcc - FIXME: do something about other compilers
Packit 562c7a
Packit 562c7a
    # gcc defines "__int128_t", assume that at least all 64 bit architectures have it
Packit 562c7a
    global COMPILER_HAS_INT128
Packit 562c7a
    COMPILER_HAS_INT128 = getattr(sys, 'maxsize', getattr(sys, 'maxint', 0)) > 2**60
Packit 562c7a
Packit 562c7a
    compiler_version = gcc_version.group(1)
Packit 562c7a
    if compiler_version and compiler_version.split('.') >= ['4', '2']:
Packit 562c7a
        return '-fopenmp', '-fopenmp'
Packit 562c7a
Packit 562c7a
try:
Packit 562c7a
    locale.setlocale(locale.LC_ALL, '')
Packit 562c7a
except locale.Error:
Packit 562c7a
    pass
Packit 562c7a
Packit 562c7a
COMPILER = None
Packit 562c7a
COMPILER_HAS_INT128 = False
Packit 562c7a
OPENMP_C_COMPILER_FLAGS = get_openmp_compiler_flags('c')
Packit 562c7a
OPENMP_CPP_COMPILER_FLAGS = get_openmp_compiler_flags('cpp')
Packit 562c7a
Packit 562c7a
# Return this from the EXT_EXTRAS matcher callback to exclude the extension
Packit 562c7a
EXCLUDE_EXT = object()
Packit 562c7a
Packit 562c7a
EXT_EXTRAS = {
Packit 562c7a
    'tag:numpy' : update_numpy_extension,
Packit 562c7a
    'tag:openmp': update_openmp_extension,
Packit 562c7a
    'tag:cpp11': update_cpp11_extension,
Packit 562c7a
    'tag:trace' : update_linetrace_extension,
Packit 562c7a
    'tag:bytesformat':  exclude_extension_in_pyver((3, 3), (3, 4)),  # no %-bytes formatting
Packit 562c7a
}
Packit 562c7a
Packit 562c7a
Packit 562c7a
# TODO: use tags
Packit 562c7a
VER_DEP_MODULES = {
Packit 562c7a
    # tests are excluded if 'CurrentPythonVersion OP VersionTuple', i.e.
Packit 562c7a
    # (2,4) : (operator.lt, ...) excludes ... when PyVer < 2.4.x
Packit 562c7a
    (2,7) : (operator.lt, lambda x: x in ['run.withstat_py27', # multi context with statement
Packit 562c7a
                                          'run.yield_inside_lambda',
Packit 562c7a
                                          'run.test_dictviews',
Packit 562c7a
                                          'run.pyclass_special_methods',
Packit 562c7a
                                          'run.set_literals',
Packit 562c7a
                                          ]),
Packit 562c7a
    # The next line should start (3,); but this is a dictionary, so
Packit 562c7a
    # we can only have one (3,) key.  Since 2.7 is supposed to be the
Packit 562c7a
    # last 2.x release, things would have to change drastically for this
Packit 562c7a
    # to be unsafe...
Packit 562c7a
    (2,999): (operator.lt, lambda x: x in ['run.special_methods_T561_py3',
Packit 562c7a
                                           'run.test_raisefrom',
Packit 562c7a
                                           ]),
Packit 562c7a
    (3,): (operator.ge, lambda x: x in ['run.non_future_division',
Packit 562c7a
                                        'compile.extsetslice',
Packit 562c7a
                                        'compile.extdelslice',
Packit 562c7a
                                        'run.special_methods_T561_py2'
Packit 562c7a
                                        ]),
Packit 562c7a
    (3,3) : (operator.lt, lambda x: x in ['build.package_compilation',
Packit 562c7a
                                          'run.yield_from_py33',
Packit 562c7a
                                          ]),
Packit 562c7a
    (3,4): (operator.lt, lambda x: x in ['run.py34_signature',
Packit 562c7a
                                         ]),
Packit 562c7a
    (3,4,999): (operator.gt, lambda x: x in ['run.initial_file_path',
Packit 562c7a
                                             ]),
Packit 562c7a
    (3,5): (operator.lt, lambda x: x in ['run.py35_pep492_interop',
Packit 562c7a
                                         'run.py35_asyncio_async_def',
Packit 562c7a
                                         'run.mod__spec__',
Packit 562c7a
                                         'run.pep526_variable_annotations',  # typing module
Packit 562c7a
                                         ]),
Packit 562c7a
}
Packit 562c7a
Packit 562c7a
INCLUDE_DIRS = [ d for d in os.getenv('INCLUDE', '').split(os.pathsep) if d ]
Packit 562c7a
CFLAGS = os.getenv('CFLAGS', '').split()
Packit 562c7a
CCACHE = os.getenv('CYTHON_RUNTESTS_CCACHE', '').split()
Packit 562c7a
TEST_SUPPORT_DIR = 'testsupport'
Packit 562c7a
Packit 562c7a
BACKENDS = ['c', 'cpp']
Packit 562c7a
Packit 562c7a
UTF8_BOM_BYTES = r'\xef\xbb\xbf'.encode('ISO-8859-1').decode('unicode_escape')
Packit 562c7a
Packit 562c7a
Packit 562c7a
def memoize(f):
Packit 562c7a
    uncomputed = object()
Packit 562c7a
    f._cache = {}
Packit 562c7a
    def func(*args):
Packit 562c7a
        res = f._cache.get(args, uncomputed)
Packit 562c7a
        if res is uncomputed:
Packit 562c7a
            res = f._cache[args] = f(*args)
Packit 562c7a
        return res
Packit 562c7a
    return func
Packit 562c7a
Packit 562c7a
Packit 562c7a
@memoize
Packit 562c7a
def parse_tags(filepath):
Packit 562c7a
    tags = defaultdict(list)
Packit 562c7a
    parse_tag = re.compile(r'#\s*(\w+)\s*:(.*)$').match
Packit 562c7a
    f = io_open(filepath, encoding='ISO-8859-1', errors='ignore')
Packit 562c7a
    try:
Packit 562c7a
        for line in f:
Packit 562c7a
            # ignore BOM-like bytes and whitespace
Packit 562c7a
            line = line.lstrip(UTF8_BOM_BYTES).strip()
Packit 562c7a
            if not line:
Packit 562c7a
                if tags:
Packit 562c7a
                    break  # assume all tags are in one block
Packit 562c7a
                else:
Packit 562c7a
                    continue
Packit 562c7a
            if line[0] != '#':
Packit 562c7a
                break
Packit 562c7a
            parsed = parse_tag(line)
Packit 562c7a
            if parsed:
Packit 562c7a
                tag, values = parsed.groups()
Packit 562c7a
                if tag in ('coding', 'encoding'):
Packit 562c7a
                    continue
Packit 562c7a
                if tag == 'tags':
Packit 562c7a
                    tag = 'tag'
Packit 562c7a
                    print("WARNING: test tags use the 'tag' directive, not 'tags' (%s)" % filepath)
Packit 562c7a
                if tag not in ('mode', 'tag', 'ticket', 'cython', 'distutils', 'preparse'):
Packit 562c7a
                    print("WARNING: unknown test directive '%s' found (%s)" % (tag, filepath))
Packit 562c7a
                values = values.split(',')
Packit 562c7a
                tags[tag].extend(filter(None, [value.strip() for value in values]))
Packit 562c7a
            elif tags:
Packit 562c7a
                break  # assume all tags are in one block
Packit 562c7a
    finally:
Packit 562c7a
        f.close()
Packit 562c7a
    return tags
Packit 562c7a
Packit 562c7a
Packit 562c7a
list_unchanging_dir = memoize(lambda x: os.listdir(x))
Packit 562c7a
Packit 562c7a
Packit 562c7a
@memoize
Packit 562c7a
def _list_pyregr_data_files(test_directory):
Packit 562c7a
    is_data_file = re.compile('(?:[.](txt|pem|db|html)|^bad.*[.]py)$').search
Packit 562c7a
    return ['__init__.py'] + [
Packit 562c7a
        filename for filename in list_unchanging_dir(test_directory)
Packit 562c7a
        if is_data_file(filename)]
Packit 562c7a
Packit 562c7a
Packit 562c7a
def import_ext(module_name, file_path=None):
Packit 562c7a
    if file_path:
Packit 562c7a
        import imp
Packit 562c7a
        return imp.load_dynamic(module_name, file_path)
Packit 562c7a
    else:
Packit 562c7a
        try:
Packit 562c7a
            from importlib import invalidate_caches
Packit 562c7a
        except ImportError:
Packit 562c7a
            pass
Packit 562c7a
        else:
Packit 562c7a
            invalidate_caches()
Packit 562c7a
        return __import__(module_name, globals(), locals(), ['*'])
Packit 562c7a
Packit 562c7a
Packit 562c7a
class build_ext(_build_ext):
Packit 562c7a
    def build_extension(self, ext):
Packit 562c7a
        try:
Packit 562c7a
            try: # Py2.7+ & Py3.2+
Packit 562c7a
                compiler_obj = self.compiler_obj
Packit 562c7a
            except AttributeError:
Packit 562c7a
                compiler_obj = self.compiler
Packit 562c7a
            if ext.language == 'c++':
Packit 562c7a
                compiler_obj.compiler_so.remove('-Wstrict-prototypes')
Packit 562c7a
            if CCACHE:
Packit 562c7a
                compiler_obj.compiler_so = CCACHE + compiler_obj.compiler_so
Packit 562c7a
            if getattr(ext, 'openmp', None) and compiler_obj.compiler_type == 'msvc':
Packit 562c7a
                ext.extra_compile_args.append('/openmp')
Packit 562c7a
        except Exception:
Packit 562c7a
            pass
Packit 562c7a
        _build_ext.build_extension(self, ext)
Packit 562c7a
Packit 562c7a
Packit 562c7a
class ErrorWriter(object):
Packit 562c7a
    match_error = re.compile('(warning:)?(?:.*:)?\s*([-0-9]+)\s*:\s*([-0-9]+)\s*:\s*(.*)').match
Packit 562c7a
Packit 562c7a
    def __init__(self):
Packit 562c7a
        self.output = []
Packit 562c7a
        self.write = self.output.append
Packit 562c7a
Packit 562c7a
    def _collect(self):
Packit 562c7a
        s = ''.join(self.output)
Packit 562c7a
        results = {'errors': [], 'warnings': []}
Packit 562c7a
        for line in s.splitlines():
Packit 562c7a
            match = self.match_error(line)
Packit 562c7a
            if match:
Packit 562c7a
                is_warning, line, column, message = match.groups()
Packit 562c7a
                results['warnings' if is_warning else 'errors'].append((int(line), int(column), message.strip()))
Packit 562c7a
Packit 562c7a
        return [["%d:%d: %s" % values for values in sorted(results[key])] for key in ('errors', 'warnings')]
Packit 562c7a
Packit 562c7a
    def geterrors(self):
Packit 562c7a
        return self._collect()[0]
Packit 562c7a
Packit 562c7a
    def getwarnings(self):
Packit 562c7a
        return self._collect()[1]
Packit 562c7a
Packit 562c7a
    def getall(self):
Packit 562c7a
        return self._collect()
Packit 562c7a
Packit 562c7a
    def close(self):
Packit 562c7a
        pass  # ignore, only to match file-like interface
Packit 562c7a
Packit 562c7a
Packit 562c7a
class TestBuilder(object):
Packit 562c7a
    def __init__(self, rootdir, workdir, selectors, exclude_selectors, annotate,
Packit 562c7a
                 cleanup_workdir, cleanup_sharedlibs, cleanup_failures,
Packit 562c7a
                 with_pyregr, cython_only, languages, test_bugs, fork, language_level,
Packit 562c7a
                 test_determinism,
Packit 562c7a
                 common_utility_dir, pythran_dir=None):
Packit 562c7a
        self.rootdir = rootdir
Packit 562c7a
        self.workdir = workdir
Packit 562c7a
        self.selectors = selectors
Packit 562c7a
        self.exclude_selectors = exclude_selectors
Packit 562c7a
        self.annotate = annotate
Packit 562c7a
        self.cleanup_workdir = cleanup_workdir
Packit 562c7a
        self.cleanup_sharedlibs = cleanup_sharedlibs
Packit 562c7a
        self.cleanup_failures = cleanup_failures
Packit 562c7a
        self.with_pyregr = with_pyregr
Packit 562c7a
        self.cython_only = cython_only
Packit 562c7a
        self.languages = languages
Packit 562c7a
        self.test_bugs = test_bugs
Packit 562c7a
        self.fork = fork
Packit 562c7a
        self.language_level = language_level
Packit 562c7a
        self.test_determinism = test_determinism
Packit 562c7a
        self.common_utility_dir = common_utility_dir
Packit 562c7a
        self.pythran_dir = pythran_dir
Packit 562c7a
Packit 562c7a
    def build_suite(self):
Packit 562c7a
        suite = unittest.TestSuite()
Packit 562c7a
        filenames = os.listdir(self.rootdir)
Packit 562c7a
        filenames.sort()
Packit 562c7a
        for filename in filenames:
Packit 562c7a
            path = os.path.join(self.rootdir, filename)
Packit 562c7a
            if os.path.isdir(path) and filename != TEST_SUPPORT_DIR:
Packit 562c7a
                if filename == 'pyregr' and not self.with_pyregr:
Packit 562c7a
                    continue
Packit 562c7a
                if filename == 'broken' and not self.test_bugs:
Packit 562c7a
                    continue
Packit 562c7a
                suite.addTest(
Packit 562c7a
                    self.handle_directory(path, filename))
Packit 562c7a
        if sys.platform not in ['win32']:
Packit 562c7a
            # Non-Windows makefile.
Packit 562c7a
            if [1 for selector in self.selectors if selector("embedded")] \
Packit 562c7a
                and not [1 for selector in self.exclude_selectors if selector("embedded")]:
Packit 562c7a
                suite.addTest(unittest.makeSuite(EmbedTest))
Packit 562c7a
        return suite
Packit 562c7a
Packit 562c7a
    def handle_directory(self, path, context):
Packit 562c7a
        workdir = os.path.join(self.workdir, context)
Packit 562c7a
        if not os.path.exists(workdir):
Packit 562c7a
            os.makedirs(workdir)
Packit 562c7a
Packit 562c7a
        suite = unittest.TestSuite()
Packit 562c7a
        filenames = list_unchanging_dir(path)
Packit 562c7a
        filenames.sort()
Packit 562c7a
        for filename in filenames:
Packit 562c7a
            filepath = os.path.join(path, filename)
Packit 562c7a
            module, ext = os.path.splitext(filename)
Packit 562c7a
            if ext not in ('.py', '.pyx', '.srctree'):
Packit 562c7a
                continue
Packit 562c7a
            if filename.startswith('.'):
Packit 562c7a
                continue # certain emacs backup files
Packit 562c7a
            if context == 'pyregr':
Packit 562c7a
                tags = defaultdict(list)
Packit 562c7a
            else:
Packit 562c7a
                tags = parse_tags(filepath)
Packit 562c7a
            fqmodule = "%s.%s" % (context, module)
Packit 562c7a
            if not [ 1 for match in self.selectors
Packit 562c7a
                     if match(fqmodule, tags) ]:
Packit 562c7a
                continue
Packit 562c7a
            if self.exclude_selectors:
Packit 562c7a
                if [1 for match in self.exclude_selectors
Packit 562c7a
                        if match(fqmodule, tags)]:
Packit 562c7a
                    continue
Packit 562c7a
Packit 562c7a
            mode = 'run' # default
Packit 562c7a
            if tags['mode']:
Packit 562c7a
                mode = tags['mode'][0]
Packit 562c7a
            elif context == 'pyregr':
Packit 562c7a
                mode = 'pyregr'
Packit 562c7a
Packit 562c7a
            if ext == '.srctree':
Packit 562c7a
                if 'cpp' not in tags['tag'] or 'cpp' in self.languages:
Packit 562c7a
                    suite.addTest(EndToEndTest(filepath, workdir, self.cleanup_workdir))
Packit 562c7a
                continue
Packit 562c7a
Packit 562c7a
            # Choose the test suite.
Packit 562c7a
            if mode == 'pyregr':
Packit 562c7a
                if not filename.startswith('test_'):
Packit 562c7a
                    continue
Packit 562c7a
                test_class = CythonPyregrTestCase
Packit 562c7a
            elif mode == 'run':
Packit 562c7a
                if module.startswith("test_"):
Packit 562c7a
                    test_class = CythonUnitTestCase
Packit 562c7a
                else:
Packit 562c7a
                    test_class = CythonRunTestCase
Packit 562c7a
            else:
Packit 562c7a
                test_class = CythonCompileTestCase
Packit 562c7a
Packit 562c7a
            for test in self.build_tests(test_class, path, workdir,
Packit 562c7a
                                         module, mode == 'error', tags):
Packit 562c7a
                suite.addTest(test)
Packit 562c7a
Packit 562c7a
            if mode == 'run' and ext == '.py' and not self.cython_only and not filename.startswith('test_'):
Packit 562c7a
                # additionally test file in real Python
Packit 562c7a
                min_py_ver = [
Packit 562c7a
                    (int(pyver.group(1)), int(pyver.group(2)))
Packit 562c7a
                    for pyver in map(re.compile(r'pure([0-9]+)[.]([0-9]+)').match, tags['tag'])
Packit 562c7a
                    if pyver
Packit 562c7a
                ]
Packit 562c7a
                if not min_py_ver or any(sys.version_info >= min_ver for min_ver in min_py_ver):
Packit 562c7a
                    suite.addTest(PureDoctestTestCase(module, os.path.join(path, filename)))
Packit 562c7a
Packit 562c7a
        return suite
Packit 562c7a
Packit 562c7a
    def build_tests(self, test_class, path, workdir, module, expect_errors, tags):
Packit 562c7a
        warning_errors = 'werror' in tags['tag']
Packit 562c7a
        expect_warnings = 'warnings' in tags['tag']
Packit 562c7a
Packit 562c7a
        if expect_errors:
Packit 562c7a
            if 'cpp' in tags['tag'] and 'cpp' in self.languages:
Packit 562c7a
                languages = ['cpp']
Packit 562c7a
            else:
Packit 562c7a
                languages = self.languages[:1]
Packit 562c7a
        else:
Packit 562c7a
            languages = self.languages
Packit 562c7a
Packit 562c7a
        if 'cpp' in tags['tag'] and 'c' in languages:
Packit 562c7a
            languages = list(languages)
Packit 562c7a
            languages.remove('c')
Packit 562c7a
        elif 'no-cpp' in tags['tag'] and 'cpp' in self.languages:
Packit 562c7a
            languages = list(languages)
Packit 562c7a
            languages.remove('cpp')
Packit 562c7a
Packit 562c7a
        pythran_dir = self.pythran_dir
Packit 562c7a
        if 'pythran' in tags['tag'] and not pythran_dir and 'cpp' in languages:
Packit 562c7a
            import pythran.config
Packit 562c7a
            pythran_ext = pythran.config.make_extension()
Packit 562c7a
            pythran_dir = pythran_ext['include_dirs'][0]
Packit 562c7a
Packit 562c7a
        preparse_list = tags.get('preparse', ['id'])
Packit 562c7a
        tests = [ self.build_test(test_class, path, workdir, module, tags, language,
Packit 562c7a
                                  expect_errors, expect_warnings, warning_errors, preparse,
Packit 562c7a
                                  pythran_dir if language == "cpp" else None)
Packit 562c7a
                  for language in languages
Packit 562c7a
                  for preparse in preparse_list ]
Packit 562c7a
        return tests
Packit 562c7a
Packit 562c7a
    def build_test(self, test_class, path, workdir, module, tags, language,
Packit 562c7a
                   expect_errors, expect_warnings, warning_errors, preparse, pythran_dir):
Packit 562c7a
        language_workdir = os.path.join(workdir, language)
Packit 562c7a
        if not os.path.exists(language_workdir):
Packit 562c7a
            os.makedirs(language_workdir)
Packit 562c7a
        workdir = os.path.join(language_workdir, module)
Packit 562c7a
        if preparse != 'id':
Packit 562c7a
            workdir += '_%s' % str(preparse)
Packit 562c7a
        return test_class(path, workdir, module, tags,
Packit 562c7a
                          language=language,
Packit 562c7a
                          preparse=preparse,
Packit 562c7a
                          expect_errors=expect_errors,
Packit 562c7a
                          expect_warnings=expect_warnings,
Packit 562c7a
                          annotate=self.annotate,
Packit 562c7a
                          cleanup_workdir=self.cleanup_workdir,
Packit 562c7a
                          cleanup_sharedlibs=self.cleanup_sharedlibs,
Packit 562c7a
                          cleanup_failures=self.cleanup_failures,
Packit 562c7a
                          cython_only=self.cython_only,
Packit 562c7a
                          fork=self.fork,
Packit 562c7a
                          language_level=self.language_level,
Packit 562c7a
                          warning_errors=warning_errors,
Packit 562c7a
                          test_determinism=self.test_determinism,
Packit 562c7a
                          common_utility_dir=self.common_utility_dir,
Packit 562c7a
                          pythran_dir=pythran_dir)
Packit 562c7a
Packit 562c7a
Packit 562c7a
class CythonCompileTestCase(unittest.TestCase):
Packit 562c7a
    def __init__(self, test_directory, workdir, module, tags, language='c', preparse='id',
Packit 562c7a
                 expect_errors=False, expect_warnings=False, annotate=False, cleanup_workdir=True,
Packit 562c7a
                 cleanup_sharedlibs=True, cleanup_failures=True, cython_only=False,
Packit 562c7a
                 fork=True, language_level=2, warning_errors=False,
Packit 562c7a
                 test_determinism=False,
Packit 562c7a
                 common_utility_dir=None, pythran_dir=None):
Packit 562c7a
        self.test_directory = test_directory
Packit 562c7a
        self.tags = tags
Packit 562c7a
        self.workdir = workdir
Packit 562c7a
        self.module = module
Packit 562c7a
        self.language = language
Packit 562c7a
        self.preparse = preparse
Packit 562c7a
        self.name = module if self.preparse == "id" else "%s_%s" % (module, preparse)
Packit 562c7a
        self.expect_errors = expect_errors
Packit 562c7a
        self.expect_warnings = expect_warnings
Packit 562c7a
        self.annotate = annotate
Packit 562c7a
        self.cleanup_workdir = cleanup_workdir
Packit 562c7a
        self.cleanup_sharedlibs = cleanup_sharedlibs
Packit 562c7a
        self.cleanup_failures = cleanup_failures
Packit 562c7a
        self.cython_only = cython_only
Packit 562c7a
        self.fork = fork
Packit 562c7a
        self.language_level = language_level
Packit 562c7a
        self.warning_errors = warning_errors
Packit 562c7a
        self.test_determinism = test_determinism
Packit 562c7a
        self.common_utility_dir = common_utility_dir
Packit 562c7a
        self.pythran_dir = pythran_dir
Packit 562c7a
        unittest.TestCase.__init__(self)
Packit 562c7a
Packit 562c7a
    def shortDescription(self):
Packit 562c7a
        return "compiling (%s%s) %s" % (self.language, "/pythran" if self.pythran_dir is not None else "", self.name)
Packit 562c7a
Packit 562c7a
    def setUp(self):
Packit 562c7a
        from Cython.Compiler import Options
Packit 562c7a
        self._saved_options = [
Packit 562c7a
            (name, getattr(Options, name))
Packit 562c7a
            for name in ('warning_errors', 'clear_to_none', 'error_on_unknown_names', 'error_on_uninitialized')
Packit 562c7a
        ]
Packit 562c7a
        self._saved_default_directives = list(Options.get_directive_defaults().items())
Packit 562c7a
        Options.warning_errors = self.warning_errors
Packit 562c7a
        if sys.version_info >= (3, 4):
Packit 562c7a
            Options._directive_defaults['autotestdict'] = False
Packit 562c7a
Packit 562c7a
        if not os.path.exists(self.workdir):
Packit 562c7a
            os.makedirs(self.workdir)
Packit 562c7a
        if self.workdir not in sys.path:
Packit 562c7a
            sys.path.insert(0, self.workdir)
Packit 562c7a
Packit 562c7a
    def tearDown(self):
Packit 562c7a
        from Cython.Compiler import Options
Packit 562c7a
        for name, value in self._saved_options:
Packit 562c7a
            setattr(Options, name, value)
Packit 562c7a
        Options._directive_defaults = dict(self._saved_default_directives)
Packit 562c7a
        unpatch_inspect_isfunction()
Packit 562c7a
Packit 562c7a
        try:
Packit 562c7a
            sys.path.remove(self.workdir)
Packit 562c7a
        except ValueError:
Packit 562c7a
            pass
Packit 562c7a
        try:
Packit 562c7a
            del sys.modules[self.module]
Packit 562c7a
        except KeyError:
Packit 562c7a
            pass
Packit 562c7a
        cleanup = self.cleanup_failures or self.success
Packit 562c7a
        cleanup_c_files = WITH_CYTHON and self.cleanup_workdir and cleanup
Packit 562c7a
        cleanup_lib_files = self.cleanup_sharedlibs and cleanup
Packit 562c7a
        is_cygwin = sys.platform == 'cygwin'
Packit 562c7a
Packit 562c7a
        if os.path.exists(self.workdir):
Packit 562c7a
            if cleanup_c_files and cleanup_lib_files and not is_cygwin:
Packit 562c7a
                shutil.rmtree(self.workdir, ignore_errors=True)
Packit 562c7a
            else:
Packit 562c7a
                for rmfile in os.listdir(self.workdir):
Packit 562c7a
                    if not cleanup_c_files:
Packit 562c7a
                        if (rmfile[-2:] in (".c", ".h") or
Packit 562c7a
                                rmfile[-4:] == ".cpp" or
Packit 562c7a
                                rmfile.endswith(".html") and rmfile.startswith(self.module)):
Packit 562c7a
                            continue
Packit 562c7a
Packit 562c7a
                    is_shared_obj = rmfile.endswith(".so") or rmfile.endswith(".dll")
Packit 562c7a
Packit 562c7a
                    if not cleanup_lib_files and is_shared_obj:
Packit 562c7a
                        continue
Packit 562c7a
Packit 562c7a
                    try:
Packit 562c7a
                        rmfile = os.path.join(self.workdir, rmfile)
Packit 562c7a
                        if os.path.isdir(rmfile):
Packit 562c7a
                            shutil.rmtree(rmfile, ignore_errors=True)
Packit 562c7a
                        elif is_cygwin and is_shared_obj:
Packit 562c7a
                            # Delete later
Packit 562c7a
                            _to_clean.append(rmfile)
Packit 562c7a
                        else:
Packit 562c7a
                            os.remove(rmfile)
Packit 562c7a
                    except IOError:
Packit 562c7a
                        pass
Packit 562c7a
Packit 562c7a
                if cleanup_c_files and cleanup_lib_files and is_cygwin:
Packit 562c7a
                    # Finally, remove the work dir itself
Packit 562c7a
                    _to_clean.append(self.workdir)
Packit 562c7a
Packit 562c7a
        if cleanup_c_files and os.path.exists(self.workdir + '-again'):
Packit 562c7a
            shutil.rmtree(self.workdir + '-again', ignore_errors=True)
Packit 562c7a
Packit 562c7a
Packit 562c7a
    def runTest(self):
Packit 562c7a
        self.success = False
Packit 562c7a
        self.runCompileTest()
Packit 562c7a
        self.success = True
Packit 562c7a
Packit 562c7a
    def runCompileTest(self):
Packit 562c7a
        return self.compile(
Packit 562c7a
            self.test_directory, self.module, self.workdir,
Packit 562c7a
            self.test_directory, self.expect_errors, self.expect_warnings, self.annotate)
Packit 562c7a
Packit 562c7a
    def find_module_source_file(self, source_file):
Packit 562c7a
        if not os.path.exists(source_file):
Packit 562c7a
            source_file = source_file[:-1]
Packit 562c7a
        return source_file
Packit 562c7a
Packit 562c7a
    def build_target_filename(self, module_name):
Packit 562c7a
        target = '%s.%s' % (module_name, self.language)
Packit 562c7a
        return target
Packit 562c7a
Packit 562c7a
    def related_files(self, test_directory, module_name):
Packit 562c7a
        is_related = re.compile('%s_.*[.].*' % module_name).match
Packit 562c7a
        return [filename for filename in list_unchanging_dir(test_directory)
Packit 562c7a
                if is_related(filename)]
Packit 562c7a
Packit 562c7a
    def copy_files(self, test_directory, target_directory, file_list):
Packit 562c7a
        if self.preparse and self.preparse != 'id':
Packit 562c7a
            preparse_func = globals()[self.preparse]
Packit 562c7a
            def copy(src, dest):
Packit 562c7a
                open(dest, 'w').write(preparse_func(open(src).read()))
Packit 562c7a
        else:
Packit 562c7a
            # use symlink on Unix, copy on Windows
Packit 562c7a
            try:
Packit 562c7a
                copy = os.symlink
Packit 562c7a
            except AttributeError:
Packit 562c7a
                copy = shutil.copy
Packit 562c7a
Packit 562c7a
        join = os.path.join
Packit 562c7a
        for filename in file_list:
Packit 562c7a
            file_path = join(test_directory, filename)
Packit 562c7a
            if os.path.exists(file_path):
Packit 562c7a
                copy(file_path, join(target_directory, filename))
Packit 562c7a
Packit 562c7a
    def source_files(self, workdir, module_name, file_list):
Packit 562c7a
        return ([self.build_target_filename(module_name)] +
Packit 562c7a
            [filename for filename in file_list
Packit 562c7a
             if not os.path.isfile(os.path.join(workdir, filename))])
Packit 562c7a
Packit 562c7a
    def split_source_and_output(self, test_directory, module, workdir):
Packit 562c7a
        source_file = self.find_module_source_file(os.path.join(test_directory, module) + '.pyx')
Packit 562c7a
        source_and_output = io_open(source_file, 'rU', encoding='ISO-8859-1')
Packit 562c7a
        error_writer = warnings_writer = None
Packit 562c7a
        try:
Packit 562c7a
            out = io_open(os.path.join(workdir, module + os.path.splitext(source_file)[1]),
Packit 562c7a
                          'w', encoding='ISO-8859-1')
Packit 562c7a
            for line in source_and_output:
Packit 562c7a
                if line.startswith("_ERRORS"):
Packit 562c7a
                    out.close()
Packit 562c7a
                    out = error_writer = ErrorWriter()
Packit 562c7a
                elif line.startswith("_WARNINGS"):
Packit 562c7a
                    out.close()
Packit 562c7a
                    out = warnings_writer = ErrorWriter()
Packit 562c7a
                else:
Packit 562c7a
                    out.write(line)
Packit 562c7a
        finally:
Packit 562c7a
            source_and_output.close()
Packit 562c7a
Packit 562c7a
        return (error_writer.geterrors() if error_writer else [],
Packit 562c7a
                warnings_writer.geterrors() if warnings_writer else [])
Packit 562c7a
Packit 562c7a
    def run_cython(self, test_directory, module, targetdir, incdir, annotate,
Packit 562c7a
                   extra_compile_options=None):
Packit 562c7a
        include_dirs = INCLUDE_DIRS + [os.path.join(test_directory, '..', TEST_SUPPORT_DIR)]
Packit 562c7a
        if incdir:
Packit 562c7a
            include_dirs.append(incdir)
Packit 562c7a
        source = self.find_module_source_file(
Packit 562c7a
            os.path.join(test_directory, module + '.pyx'))
Packit 562c7a
        if self.preparse == 'id':
Packit 562c7a
            source = self.find_module_source_file(
Packit 562c7a
                os.path.join(test_directory, module + '.pyx'))
Packit 562c7a
        else:
Packit 562c7a
            self.copy_files(test_directory, targetdir, [module + '.pyx'])
Packit 562c7a
            source = os.path.join(targetdir, module + '.pyx')
Packit 562c7a
        target = os.path.join(targetdir, self.build_target_filename(module))
Packit 562c7a
Packit 562c7a
        if extra_compile_options is None:
Packit 562c7a
            extra_compile_options = {}
Packit 562c7a
Packit 562c7a
        if 'allow_unknown_names' in self.tags['tag']:
Packit 562c7a
            from Cython.Compiler import Options
Packit 562c7a
            Options.error_on_unknown_names = False
Packit 562c7a
Packit 562c7a
        try:
Packit 562c7a
            CompilationOptions
Packit 562c7a
        except NameError:
Packit 562c7a
            from Cython.Compiler.Main import CompilationOptions
Packit 562c7a
            from Cython.Compiler.Main import compile as cython_compile
Packit 562c7a
            from Cython.Compiler.Main import default_options
Packit 562c7a
        common_utility_include_dir = self.common_utility_dir
Packit 562c7a
Packit 562c7a
        options = CompilationOptions(
Packit 562c7a
            default_options,
Packit 562c7a
            include_path = include_dirs,
Packit 562c7a
            output_file = target,
Packit 562c7a
            annotate = annotate,
Packit 562c7a
            use_listing_file = False,
Packit 562c7a
            cplus = self.language == 'cpp',
Packit 562c7a
            np_pythran = self.pythran_dir is not None,
Packit 562c7a
            language_level = self.language_level,
Packit 562c7a
            generate_pxi = False,
Packit 562c7a
            evaluate_tree_assertions = True,
Packit 562c7a
            common_utility_include_dir = common_utility_include_dir,
Packit 562c7a
            **extra_compile_options
Packit 562c7a
            )
Packit 562c7a
        cython_compile(source, options=options,
Packit 562c7a
                       full_module_name=module)
Packit 562c7a
Packit 562c7a
    def run_distutils(self, test_directory, module, workdir, incdir,
Packit 562c7a
                      extra_extension_args=None):
Packit 562c7a
        cwd = os.getcwd()
Packit 562c7a
        os.chdir(workdir)
Packit 562c7a
        try:
Packit 562c7a
            build_extension = build_ext(get_distutils_distro())
Packit 562c7a
            build_extension.include_dirs = INCLUDE_DIRS[:]
Packit 562c7a
            if incdir:
Packit 562c7a
                build_extension.include_dirs.append(incdir)
Packit 562c7a
            build_extension.finalize_options()
Packit 562c7a
            if COMPILER:
Packit 562c7a
                build_extension.compiler = COMPILER
Packit 562c7a
Packit 562c7a
            ext_compile_flags = CFLAGS[:]
Packit 562c7a
Packit 562c7a
            if  build_extension.compiler == 'mingw32':
Packit 562c7a
                ext_compile_flags.append('-Wno-format')
Packit 562c7a
            if extra_extension_args is None:
Packit 562c7a
                extra_extension_args = {}
Packit 562c7a
Packit 562c7a
            related_files = self.related_files(test_directory, module)
Packit 562c7a
            self.copy_files(test_directory, workdir, related_files)
Packit 562c7a
Packit 562c7a
            from distutils.core import Extension
Packit 562c7a
            extension = Extension(
Packit 562c7a
                module,
Packit 562c7a
                sources=self.source_files(workdir, module, related_files),
Packit 562c7a
                extra_compile_args=ext_compile_flags,
Packit 562c7a
                **extra_extension_args
Packit 562c7a
                )
Packit 562c7a
Packit 562c7a
            if self.language == 'cpp':
Packit 562c7a
                # Set the language now as the fixer might need it
Packit 562c7a
                extension.language = 'c++'
Packit 562c7a
Packit 562c7a
            if 'distutils' in self.tags:
Packit 562c7a
                from Cython.Build.Dependencies import DistutilsInfo
Packit 562c7a
                from Cython.Utils import open_source_file
Packit 562c7a
                pyx_path = os.path.join(self.test_directory, self.module + ".pyx")
Packit 562c7a
                with open_source_file(pyx_path) as f:
Packit 562c7a
                    DistutilsInfo(f).apply(extension)
Packit 562c7a
Packit 562c7a
            if self.pythran_dir:
Packit 562c7a
                from Cython.Build.Dependencies import update_pythran_extension
Packit 562c7a
                update_pythran_extension(extension)
Packit 562c7a
Packit 562c7a
            for matcher, fixer in list(EXT_EXTRAS.items()):
Packit 562c7a
                if isinstance(matcher, str):
Packit 562c7a
                    # lazy init
Packit 562c7a
                    del EXT_EXTRAS[matcher]
Packit 562c7a
                    matcher = string_selector(matcher)
Packit 562c7a
                    EXT_EXTRAS[matcher] = fixer
Packit 562c7a
                if matcher(module, self.tags):
Packit 562c7a
                    newext = fixer(extension)
Packit 562c7a
                    if newext is EXCLUDE_EXT:
Packit 562c7a
                        return
Packit 562c7a
                    extension = newext or extension
Packit 562c7a
            if self.language == 'cpp':
Packit 562c7a
                extension.language = 'c++'
Packit 562c7a
            build_extension.extensions = [extension]
Packit 562c7a
            build_extension.build_temp = workdir
Packit 562c7a
            build_extension.build_lib  = workdir
Packit 562c7a
            build_extension.run()
Packit 562c7a
        finally:
Packit 562c7a
            os.chdir(cwd)
Packit 562c7a
Packit 562c7a
        try:
Packit 562c7a
            get_ext_fullpath = build_extension.get_ext_fullpath
Packit 562c7a
        except AttributeError:
Packit 562c7a
            def get_ext_fullpath(ext_name, self=build_extension):
Packit 562c7a
                # copied from distutils.command.build_ext (missing in Py2.[45])
Packit 562c7a
                fullname = self.get_ext_fullname(ext_name)
Packit 562c7a
                modpath = fullname.split('.')
Packit 562c7a
                filename = self.get_ext_filename(modpath[-1])
Packit 562c7a
                if not self.inplace:
Packit 562c7a
                    filename = os.path.join(*modpath[:-1]+[filename])
Packit 562c7a
                    return os.path.join(self.build_lib, filename)
Packit 562c7a
                package = '.'.join(modpath[0:-1])
Packit 562c7a
                build_py = self.get_finalized_command('build_py')
Packit 562c7a
                package_dir = os.path.abspath(build_py.get_package_dir(package))
Packit 562c7a
                return os.path.join(package_dir, filename)
Packit 562c7a
Packit 562c7a
        return get_ext_fullpath(module)
Packit 562c7a
Packit 562c7a
    def compile(self, test_directory, module, workdir, incdir,
Packit 562c7a
                expect_errors, expect_warnings, annotate):
Packit 562c7a
        expected_errors = expected_warnings = errors = warnings = ()
Packit 562c7a
        if expect_errors or expect_warnings:
Packit 562c7a
            expected_errors, expected_warnings = self.split_source_and_output(
Packit 562c7a
                test_directory, module, workdir)
Packit 562c7a
            test_directory = workdir
Packit 562c7a
Packit 562c7a
        if WITH_CYTHON:
Packit 562c7a
            old_stderr = sys.stderr
Packit 562c7a
            try:
Packit 562c7a
                sys.stderr = ErrorWriter()
Packit 562c7a
                self.run_cython(test_directory, module, workdir, incdir, annotate)
Packit 562c7a
                errors, warnings = sys.stderr.getall()
Packit 562c7a
            finally:
Packit 562c7a
                sys.stderr = old_stderr
Packit 562c7a
            if self.test_determinism and not expect_errors:
Packit 562c7a
                workdir2 = workdir + '-again'
Packit 562c7a
                os.mkdir(workdir2)
Packit 562c7a
                self.run_cython(test_directory, module, workdir2, incdir, annotate)
Packit 562c7a
                diffs = []
Packit 562c7a
                for file in os.listdir(workdir2):
Packit 562c7a
                    if (open(os.path.join(workdir, file)).read()
Packit 562c7a
                        != open(os.path.join(workdir2, file)).read()):
Packit 562c7a
                        diffs.append(file)
Packit 562c7a
                        os.system('diff -u %s/%s %s/%s > %s/%s.diff' % (
Packit 562c7a
                            workdir, file,
Packit 562c7a
                            workdir2, file,
Packit 562c7a
                            workdir2, file))
Packit 562c7a
                if diffs:
Packit 562c7a
                    self.fail('Nondeterministic file generation: %s' % ', '.join(diffs))
Packit 562c7a
Packit 562c7a
        tostderr = sys.__stderr__.write
Packit 562c7a
        if expected_warnings or (expect_warnings and warnings):
Packit 562c7a
            self._match_output(expected_warnings, warnings, tostderr)
Packit 562c7a
        if 'cerror' in self.tags['tag']:
Packit 562c7a
            if errors:
Packit 562c7a
                tostderr("\n=== Expected C compile error ===\n")
Packit 562c7a
                tostderr("\n=== Got Cython errors: ===\n")
Packit 562c7a
                tostderr('\n'.join(errors))
Packit 562c7a
                tostderr('\n\n')
Packit 562c7a
                raise RuntimeError('should have generated extension code')
Packit 562c7a
        elif errors or expected_errors:
Packit 562c7a
            self._match_output(expected_errors, errors, tostderr)
Packit 562c7a
            return None
Packit 562c7a
Packit 562c7a
        so_path = None
Packit 562c7a
        if not self.cython_only:
Packit 562c7a
            from Cython.Utils import captured_fd, print_bytes
Packit 562c7a
            from distutils.errors import CompileError, LinkError
Packit 562c7a
            show_output = True
Packit 562c7a
            get_stderr = get_stdout = None
Packit 562c7a
            try:
Packit 562c7a
                with captured_fd(1) as get_stdout:
Packit 562c7a
                    with captured_fd(2) as get_stderr:
Packit 562c7a
                        so_path = self.run_distutils(test_directory, module, workdir, incdir)
Packit 562c7a
            except Exception as exc:
Packit 562c7a
                if ('cerror' in self.tags['tag'] and
Packit 562c7a
                    ((get_stderr and get_stderr()) or
Packit 562c7a
                     isinstance(exc, (CompileError, LinkError)))):
Packit 562c7a
                    show_output = False  # expected C compiler failure
Packit 562c7a
                else:
Packit 562c7a
                    raise
Packit 562c7a
            else:
Packit 562c7a
                if 'cerror' in self.tags['tag']:
Packit 562c7a
                    raise RuntimeError('should have failed C compile')
Packit 562c7a
            finally:
Packit 562c7a
                if show_output:
Packit 562c7a
                    stdout = get_stdout and get_stdout().strip()
Packit 562c7a
                    if stdout:
Packit 562c7a
                        tostderr("\n=== C/C++ compiler output: ===\n")
Packit 562c7a
                        print_bytes(stdout, end=None, file=sys.__stderr__)
Packit 562c7a
                    stderr = get_stderr and get_stderr().strip()
Packit 562c7a
                    if stderr:
Packit 562c7a
                        tostderr("\n=== C/C++ compiler error output: ===\n")
Packit 562c7a
                        print_bytes(stderr, end=None, file=sys.__stderr__)
Packit 562c7a
                    if stdout or stderr:
Packit 562c7a
                        tostderr("\n==============================\n")
Packit 562c7a
        return so_path
Packit 562c7a
Packit 562c7a
    def _match_output(self, expected_output, actual_output, write):
Packit 562c7a
        try:
Packit 562c7a
            for expected, actual in zip(expected_output, actual_output):
Packit 562c7a
                self.assertEqual(expected, actual)
Packit 562c7a
            if len(actual_output) < len(expected_output):
Packit 562c7a
                expected = expected_output[len(actual_output)]
Packit 562c7a
                self.assertEqual(expected, None)
Packit 562c7a
            elif len(actual_output) > len(expected_output):
Packit 562c7a
                unexpected = actual_output[len(expected_output)]
Packit 562c7a
                self.assertEqual(None, unexpected)
Packit 562c7a
        except AssertionError:
Packit 562c7a
            write("\n=== Expected: ===\n")
Packit 562c7a
            write('\n'.join(expected_output))
Packit 562c7a
            write("\n\n=== Got: ===\n")
Packit 562c7a
            write('\n'.join(actual_output))
Packit 562c7a
            write('\n\n')
Packit 562c7a
            raise
Packit 562c7a
Packit 562c7a
Packit 562c7a
class CythonRunTestCase(CythonCompileTestCase):
Packit 562c7a
    def setUp(self):
Packit 562c7a
        CythonCompileTestCase.setUp(self)
Packit 562c7a
        from Cython.Compiler import Options
Packit 562c7a
        Options.clear_to_none = False
Packit 562c7a
Packit 562c7a
    def shortDescription(self):
Packit 562c7a
        if self.cython_only:
Packit 562c7a
            return CythonCompileTestCase.shortDescription(self)
Packit 562c7a
        else:
Packit 562c7a
            return "compiling (%s%s) and running %s" % (self.language, "/pythran" if self.pythran_dir is not None else "", self.name)
Packit 562c7a
Packit 562c7a
    def run(self, result=None):
Packit 562c7a
        if result is None:
Packit 562c7a
            result = self.defaultTestResult()
Packit 562c7a
        result.startTest(self)
Packit 562c7a
        try:
Packit 562c7a
            self.setUp()
Packit 562c7a
            try:
Packit 562c7a
                self.success = False
Packit 562c7a
                ext_so_path = self.runCompileTest()
Packit 562c7a
                failures, errors = len(result.failures), len(result.errors)
Packit 562c7a
                if not self.cython_only and ext_so_path is not None:
Packit 562c7a
                    self.run_tests(result, ext_so_path)
Packit 562c7a
                if failures == len(result.failures) and errors == len(result.errors):
Packit 562c7a
                    # No new errors...
Packit 562c7a
                    self.success = True
Packit 562c7a
            finally:
Packit 562c7a
                check_thread_termination()
Packit 562c7a
        except Exception:
Packit 562c7a
            result.addError(self, sys.exc_info())
Packit 562c7a
            result.stopTest(self)
Packit 562c7a
        try:
Packit 562c7a
            self.tearDown()
Packit 562c7a
        except Exception:
Packit 562c7a
            pass
Packit 562c7a
Packit 562c7a
    def run_tests(self, result, ext_so_path):
Packit 562c7a
        self.run_doctests(self.module, result, ext_so_path)
Packit 562c7a
Packit 562c7a
    def run_doctests(self, module_or_name, result, ext_so_path):
Packit 562c7a
        def run_test(result):
Packit 562c7a
            if isinstance(module_or_name, basestring):
Packit 562c7a
                module = import_ext(module_or_name, ext_so_path)
Packit 562c7a
            else:
Packit 562c7a
                module = module_or_name
Packit 562c7a
            tests = doctest.DocTestSuite(module)
Packit 562c7a
            tests.run(result)
Packit 562c7a
        run_forked_test(result, run_test, self.shortDescription(), self.fork)
Packit 562c7a
Packit 562c7a
def run_forked_test(result, run_func, test_name, fork=True):
Packit 562c7a
    if not fork or sys.version_info[0] >= 3 or not hasattr(os, 'fork'):
Packit 562c7a
        run_func(result)
Packit 562c7a
        sys.stdout.flush()
Packit 562c7a
        sys.stderr.flush()
Packit 562c7a
        gc.collect()
Packit 562c7a
        return
Packit 562c7a
Packit 562c7a
    # fork to make sure we do not keep the tested module loaded
Packit 562c7a
    result_handle, result_file = tempfile.mkstemp()
Packit 562c7a
    os.close(result_handle)
Packit 562c7a
    child_id = os.fork()
Packit 562c7a
    if not child_id:
Packit 562c7a
        result_code = 0
Packit 562c7a
        output = None
Packit 562c7a
        try:
Packit 562c7a
            try:
Packit 562c7a
                tests = partial_result = None
Packit 562c7a
                try:
Packit 562c7a
                    partial_result = PartialTestResult(result)
Packit 562c7a
                    run_func(partial_result)
Packit 562c7a
                    sys.stdout.flush()
Packit 562c7a
                    sys.stderr.flush()
Packit 562c7a
                    gc.collect()
Packit 562c7a
                except Exception:
Packit 562c7a
                    result_code = 1
Packit 562c7a
                    if partial_result is not None:
Packit 562c7a
                        if tests is None:
Packit 562c7a
                            # importing failed, try to fake a test class
Packit 562c7a
                            tests = _FakeClass(
Packit 562c7a
                                failureException=sys.exc_info()[1],
Packit 562c7a
                                _shortDescription=test_name,
Packit 562c7a
                                module_name=None)
Packit 562c7a
                        partial_result.addError(tests, sys.exc_info())
Packit 562c7a
                output = open(result_file, 'wb')
Packit 562c7a
                pickle.dump(partial_result.data(), output)
Packit 562c7a
            except:
Packit 562c7a
                traceback.print_exc()
Packit 562c7a
        finally:
Packit 562c7a
            try: sys.stderr.flush()
Packit 562c7a
            except: pass
Packit 562c7a
            try: sys.stdout.flush()
Packit 562c7a
            except: pass
Packit 562c7a
            try:
Packit 562c7a
                if output is not None:
Packit 562c7a
                    output.close()
Packit 562c7a
            except:
Packit 562c7a
                pass
Packit 562c7a
            os._exit(result_code)
Packit 562c7a
Packit 562c7a
    try:
Packit 562c7a
        cid, result_code = os.waitpid(child_id, 0)
Packit 562c7a
        module_name = test_name.split()[-1]
Packit 562c7a
        # os.waitpid returns the child's result code in the
Packit 562c7a
        # upper byte of result_code, and the signal it was
Packit 562c7a
        # killed by in the lower byte
Packit 562c7a
        if result_code & 255:
Packit 562c7a
            raise Exception("Tests in module '%s' were unexpectedly killed by signal %d"%
Packit 562c7a
                            (module_name, result_code & 255))
Packit 562c7a
        result_code >>= 8
Packit 562c7a
        if result_code in (0,1):
Packit 562c7a
            input = open(result_file, 'rb')
Packit 562c7a
            try:
Packit 562c7a
                PartialTestResult.join_results(result, pickle.load(input))
Packit 562c7a
            finally:
Packit 562c7a
                input.close()
Packit 562c7a
        if result_code:
Packit 562c7a
            raise Exception("Tests in module '%s' exited with status %d" %
Packit 562c7a
                            (module_name, result_code))
Packit 562c7a
    finally:
Packit 562c7a
        try: os.unlink(result_file)
Packit 562c7a
        except: pass
Packit 562c7a
Packit 562c7a
class PureDoctestTestCase(unittest.TestCase):
Packit 562c7a
    def __init__(self, module_name, module_path):
Packit 562c7a
        self.module_name = module_name
Packit 562c7a
        self.module_path = module_path
Packit 562c7a
        unittest.TestCase.__init__(self, 'run')
Packit 562c7a
Packit 562c7a
    def shortDescription(self):
Packit 562c7a
        return "running pure doctests in %s" % self.module_name
Packit 562c7a
Packit 562c7a
    def run(self, result=None):
Packit 562c7a
        if result is None:
Packit 562c7a
            result = self.defaultTestResult()
Packit 562c7a
        loaded_module_name = 'pure_doctest__' + self.module_name
Packit 562c7a
        result.startTest(self)
Packit 562c7a
        try:
Packit 562c7a
            self.setUp()
Packit 562c7a
Packit 562c7a
            import imp
Packit 562c7a
            m = imp.load_source(loaded_module_name, self.module_path)
Packit 562c7a
            try:
Packit 562c7a
                doctest.DocTestSuite(m).run(result)
Packit 562c7a
            finally:
Packit 562c7a
                del m
Packit 562c7a
                if loaded_module_name in sys.modules:
Packit 562c7a
                    del sys.modules[loaded_module_name]
Packit 562c7a
                check_thread_termination()
Packit 562c7a
        except Exception:
Packit 562c7a
            result.addError(self, sys.exc_info())
Packit 562c7a
            result.stopTest(self)
Packit 562c7a
        try:
Packit 562c7a
            self.tearDown()
Packit 562c7a
        except Exception:
Packit 562c7a
            pass
Packit 562c7a
Packit 562c7a
is_private_field = re.compile('^_[^_]').match
Packit 562c7a
Packit 562c7a
class _FakeClass(object):
Packit 562c7a
    def __init__(self, **kwargs):
Packit 562c7a
        self._shortDescription = kwargs.get('module_name')
Packit 562c7a
        self.__dict__.update(kwargs)
Packit 562c7a
    def shortDescription(self):
Packit 562c7a
        return self._shortDescription
Packit 562c7a
Packit 562c7a
try: # Py2.7+ and Py3.2+
Packit 562c7a
    from unittest.runner import _TextTestResult
Packit 562c7a
except ImportError:
Packit 562c7a
    from unittest import _TextTestResult
Packit 562c7a
Packit 562c7a
class PartialTestResult(_TextTestResult):
Packit 562c7a
    def __init__(self, base_result):
Packit 562c7a
        _TextTestResult.__init__(
Packit 562c7a
            self, self._StringIO(), True,
Packit 562c7a
            base_result.dots + base_result.showAll*2)
Packit 562c7a
Packit 562c7a
    def strip_error_results(self, results):
Packit 562c7a
        for test_case, error in results:
Packit 562c7a
            for attr_name in filter(is_private_field, dir(test_case)):
Packit 562c7a
                if attr_name == '_dt_test':
Packit 562c7a
                    test_case._dt_test = _FakeClass(
Packit 562c7a
                        name=test_case._dt_test.name)
Packit 562c7a
                elif attr_name != '_shortDescription':
Packit 562c7a
                    setattr(test_case, attr_name, None)
Packit 562c7a
Packit 562c7a
    def data(self):
Packit 562c7a
        self.strip_error_results(self.failures)
Packit 562c7a
        self.strip_error_results(self.errors)
Packit 562c7a
        return (self.failures, self.errors, self.testsRun,
Packit 562c7a
                self.stream.getvalue())
Packit 562c7a
Packit 562c7a
    def join_results(result, data):
Packit 562c7a
        """Static method for merging the result back into the main
Packit 562c7a
        result object.
Packit 562c7a
        """
Packit 562c7a
        failures, errors, tests_run, output = data
Packit 562c7a
        if output:
Packit 562c7a
            result.stream.write(output)
Packit 562c7a
        result.errors.extend(errors)
Packit 562c7a
        result.failures.extend(failures)
Packit 562c7a
        result.testsRun += tests_run
Packit 562c7a
Packit 562c7a
    join_results = staticmethod(join_results)
Packit 562c7a
Packit 562c7a
    class _StringIO(StringIO):
Packit 562c7a
        def writeln(self, line):
Packit 562c7a
            self.write("%s\n" % line)
Packit 562c7a
Packit 562c7a
Packit 562c7a
class CythonUnitTestCase(CythonRunTestCase):
Packit 562c7a
    def shortDescription(self):
Packit 562c7a
        return "compiling (%s) tests in %s" % (self.language, self.name)
Packit 562c7a
Packit 562c7a
    def run_tests(self, result, ext_so_path):
Packit 562c7a
        module = import_ext(self.module, ext_so_path)
Packit 562c7a
        unittest.defaultTestLoader.loadTestsFromModule(module).run(result)
Packit 562c7a
Packit 562c7a
Packit 562c7a
class CythonPyregrTestCase(CythonRunTestCase):
Packit 562c7a
    def setUp(self):
Packit 562c7a
        CythonRunTestCase.setUp(self)
Packit 562c7a
        from Cython.Compiler import Options
Packit 562c7a
        Options.error_on_unknown_names = False
Packit 562c7a
        Options.error_on_uninitialized = False
Packit 562c7a
        Options._directive_defaults.update(dict(
Packit 562c7a
            binding=True, always_allow_keywords=True,
Packit 562c7a
            set_initial_path="SOURCEFILE"))
Packit 562c7a
        patch_inspect_isfunction()
Packit 562c7a
Packit 562c7a
    def related_files(self, test_directory, module_name):
Packit 562c7a
        return _list_pyregr_data_files(test_directory)
Packit 562c7a
Packit 562c7a
    def _run_unittest(self, result, *classes):
Packit 562c7a
        """Run tests from unittest.TestCase-derived classes."""
Packit 562c7a
        valid_types = (unittest.TestSuite, unittest.TestCase)
Packit 562c7a
        suite = unittest.TestSuite()
Packit 562c7a
        for cls in classes:
Packit 562c7a
            if isinstance(cls, str):
Packit 562c7a
                if cls in sys.modules:
Packit 562c7a
                    suite.addTest(unittest.findTestCases(sys.modules[cls]))
Packit 562c7a
                else:
Packit 562c7a
                    raise ValueError("str arguments must be keys in sys.modules")
Packit 562c7a
            elif isinstance(cls, valid_types):
Packit 562c7a
                suite.addTest(cls)
Packit 562c7a
            else:
Packit 562c7a
                suite.addTest(unittest.makeSuite(cls))
Packit 562c7a
        suite.run(result)
Packit 562c7a
Packit 562c7a
    def _run_doctest(self, result, module):
Packit 562c7a
        self.run_doctests(module, result, None)
Packit 562c7a
Packit 562c7a
    def run_tests(self, result, ext_so_path):
Packit 562c7a
        try:
Packit 562c7a
            from test import support
Packit 562c7a
        except ImportError: # Python2.x
Packit 562c7a
            from test import test_support as support
Packit 562c7a
Packit 562c7a
        def run_test(result):
Packit 562c7a
            def run_unittest(*classes):
Packit 562c7a
                return self._run_unittest(result, *classes)
Packit 562c7a
            def run_doctest(module, verbosity=None):
Packit 562c7a
                return self._run_doctest(result, module)
Packit 562c7a
Packit 562c7a
            backup = (support.run_unittest, support.run_doctest)
Packit 562c7a
            support.run_unittest = run_unittest
Packit 562c7a
            support.run_doctest = run_doctest
Packit 562c7a
Packit 562c7a
            try:
Packit 562c7a
                try:
Packit 562c7a
                    sys.stdout.flush() # helps in case of crashes
Packit 562c7a
                    module = import_ext(self.module, ext_so_path)
Packit 562c7a
                    sys.stdout.flush() # helps in case of crashes
Packit 562c7a
                    if hasattr(module, 'test_main'):
Packit 562c7a
                        # help 'doctest.DocFileTest' find the module path through frame inspection
Packit 562c7a
                        fake_caller_module_globals = {
Packit 562c7a
                            'module': module,
Packit 562c7a
                            '__name__': module.__name__,
Packit 562c7a
                        }
Packit 562c7a
                        call_tests = eval(
Packit 562c7a
                            'lambda: module.test_main()',
Packit 562c7a
                            fake_caller_module_globals, fake_caller_module_globals)
Packit 562c7a
                        call_tests()
Packit 562c7a
                        sys.stdout.flush() # helps in case of crashes
Packit 562c7a
                except (unittest.SkipTest, support.ResourceDenied):
Packit 562c7a
                    result.addSkip(self, 'ok')
Packit 562c7a
            finally:
Packit 562c7a
                support.run_unittest, support.run_doctest = backup
Packit 562c7a
Packit 562c7a
        run_forked_test(result, run_test, self.shortDescription(), self.fork)
Packit 562c7a
Packit 562c7a
Packit 562c7a
include_debugger = IS_CPYTHON
Packit 562c7a
Packit 562c7a
Packit 562c7a
def collect_unittests(path, module_prefix, suite, selectors, exclude_selectors):
Packit 562c7a
    def file_matches(filename):
Packit 562c7a
        return filename.startswith("Test") and filename.endswith(".py")
Packit 562c7a
Packit 562c7a
    def package_matches(dirname):
Packit 562c7a
        return dirname == "Tests"
Packit 562c7a
Packit 562c7a
    loader = unittest.TestLoader()
Packit 562c7a
Packit 562c7a
    if include_debugger:
Packit 562c7a
        skipped_dirs = []
Packit 562c7a
    else:
Packit 562c7a
        skipped_dirs = ['Cython' + os.path.sep + 'Debugger' + os.path.sep]
Packit 562c7a
Packit 562c7a
    for dirpath, dirnames, filenames in os.walk(path):
Packit 562c7a
        if dirpath != path and "__init__.py" not in filenames:
Packit 562c7a
            skipped_dirs.append(dirpath + os.path.sep)
Packit 562c7a
            continue
Packit 562c7a
        skip = False
Packit 562c7a
        for dir in skipped_dirs:
Packit 562c7a
            if dirpath.startswith(dir):
Packit 562c7a
                skip = True
Packit 562c7a
        if skip:
Packit 562c7a
            continue
Packit 562c7a
        parentname = os.path.split(dirpath)[-1]
Packit 562c7a
        if package_matches(parentname):
Packit 562c7a
            for f in filenames:
Packit 562c7a
                if file_matches(f):
Packit 562c7a
                    filepath = os.path.join(dirpath, f)[:-len(".py")]
Packit 562c7a
                    modulename = module_prefix + filepath[len(path)+1:].replace(os.path.sep, '.')
Packit 562c7a
                    if not any(1 for match in selectors if match(modulename)):
Packit 562c7a
                        continue
Packit 562c7a
                    if any(1 for match in exclude_selectors if match(modulename)):
Packit 562c7a
                        continue
Packit 562c7a
                    module = __import__(modulename)
Packit 562c7a
                    for x in modulename.split('.')[1:]:
Packit 562c7a
                        module = getattr(module, x)
Packit 562c7a
                    suite.addTests([loader.loadTestsFromModule(module)])
Packit 562c7a
Packit 562c7a
Packit 562c7a
def collect_doctests(path, module_prefix, suite, selectors, exclude_selectors):
Packit 562c7a
    def package_matches(dirname):
Packit 562c7a
        if dirname == 'Debugger' and not include_debugger:
Packit 562c7a
            return False
Packit 562c7a
        return dirname not in ("Mac", "Distutils", "Plex", "Tempita")
Packit 562c7a
    def file_matches(filename):
Packit 562c7a
        filename, ext = os.path.splitext(filename)
Packit 562c7a
        blacklist = ['libcython', 'libpython', 'test_libcython_in_gdb',
Packit 562c7a
                     'TestLibCython']
Packit 562c7a
        return (ext == '.py' and not
Packit 562c7a
                '~' in filename and not
Packit 562c7a
                '#' in filename and not
Packit 562c7a
                filename.startswith('.') and not
Packit 562c7a
                filename in blacklist)
Packit 562c7a
    import doctest
Packit 562c7a
    for dirpath, dirnames, filenames in os.walk(path):
Packit 562c7a
        for dir in list(dirnames):
Packit 562c7a
            if not package_matches(dir):
Packit 562c7a
                dirnames.remove(dir)
Packit 562c7a
        for f in filenames:
Packit 562c7a
            if file_matches(f):
Packit 562c7a
                if not f.endswith('.py'): continue
Packit 562c7a
                filepath = os.path.join(dirpath, f)
Packit 562c7a
                if os.path.getsize(filepath) == 0: continue
Packit 562c7a
                filepath = filepath[:-len(".py")]
Packit 562c7a
                modulename = module_prefix + filepath[len(path)+1:].replace(os.path.sep, '.')
Packit 562c7a
                if not [ 1 for match in selectors if match(modulename) ]:
Packit 562c7a
                    continue
Packit 562c7a
                if [ 1 for match in exclude_selectors if match(modulename) ]:
Packit 562c7a
                    continue
Packit 562c7a
                if 'in_gdb' in modulename:
Packit 562c7a
                    # These should only be imported from gdb.
Packit 562c7a
                    continue
Packit 562c7a
                module = __import__(modulename)
Packit 562c7a
                for x in modulename.split('.')[1:]:
Packit 562c7a
                    module = getattr(module, x)
Packit 562c7a
                if hasattr(module, "__doc__") or hasattr(module, "__test__"):
Packit 562c7a
                    try:
Packit 562c7a
                        suite.addTest(doctest.DocTestSuite(module))
Packit 562c7a
                    except ValueError: # no tests
Packit 562c7a
                        pass
Packit 562c7a
Packit 562c7a
Packit 562c7a
class EndToEndTest(unittest.TestCase):
Packit 562c7a
    """
Packit 562c7a
    This is a test of build/*.srctree files, where srctree defines a full
Packit 562c7a
    directory structure and its header gives a list of commands to run.
Packit 562c7a
    """
Packit 562c7a
    cython_root = os.path.dirname(os.path.abspath(__file__))
Packit 562c7a
Packit 562c7a
    def __init__(self, treefile, workdir, cleanup_workdir=True):
Packit 562c7a
        self.name = os.path.splitext(os.path.basename(treefile))[0]
Packit 562c7a
        self.treefile = treefile
Packit 562c7a
        self.workdir = os.path.join(workdir, self.name)
Packit 562c7a
        self.cleanup_workdir = cleanup_workdir
Packit 562c7a
        cython_syspath = [self.cython_root]
Packit 562c7a
        for path in sys.path:
Packit 562c7a
            if path.startswith(self.cython_root) and path not in cython_syspath:
Packit 562c7a
                # Py3 installation and refnanny build prepend their
Packit 562c7a
                # fixed paths to sys.path => prefer that over the
Packit 562c7a
                # generic one (cython_root itself goes last)
Packit 562c7a
                cython_syspath.append(path)
Packit 562c7a
        self.cython_syspath = os.pathsep.join(cython_syspath[::-1])
Packit 562c7a
        unittest.TestCase.__init__(self)
Packit 562c7a
Packit 562c7a
    def shortDescription(self):
Packit 562c7a
        return "End-to-end %s" % self.name
Packit 562c7a
Packit 562c7a
    def setUp(self):
Packit 562c7a
        from Cython.TestUtils import unpack_source_tree
Packit 562c7a
        _, self.commands = unpack_source_tree(self.treefile, self.workdir)
Packit 562c7a
        self.old_dir = os.getcwd()
Packit 562c7a
        os.chdir(self.workdir)
Packit 562c7a
        if self.workdir not in sys.path:
Packit 562c7a
            sys.path.insert(0, self.workdir)
Packit 562c7a
Packit 562c7a
    def tearDown(self):
Packit 562c7a
        if self.cleanup_workdir:
Packit 562c7a
            for trial in range(5):
Packit 562c7a
                try:
Packit 562c7a
                    shutil.rmtree(self.workdir)
Packit 562c7a
                except OSError:
Packit 562c7a
                    time.sleep(0.1)
Packit 562c7a
                else:
Packit 562c7a
                    break
Packit 562c7a
        os.chdir(self.old_dir)
Packit 562c7a
Packit 562c7a
    def _try_decode(self, content):
Packit 562c7a
        try:
Packit 562c7a
            return content.decode()
Packit 562c7a
        except UnicodeDecodeError:
Packit 562c7a
            return content.decode('iso-8859-1')
Packit 562c7a
Packit 562c7a
    def runTest(self):
Packit 562c7a
        self.success = False
Packit 562c7a
        commands = (self.commands
Packit 562c7a
            .replace("CYTHON", "PYTHON %s" % os.path.join(self.cython_root, 'cython.py'))
Packit 562c7a
            .replace("PYTHON", sys.executable))
Packit 562c7a
        old_path = os.environ.get('PYTHONPATH')
Packit 562c7a
        os.environ['PYTHONPATH'] = self.cython_syspath + os.pathsep + (old_path or '')
Packit 562c7a
        try:
Packit 562c7a
            for command in filter(None, commands.splitlines()):
Packit 562c7a
                p = subprocess.Popen(command,
Packit 562c7a
                                     stderr=subprocess.PIPE,
Packit 562c7a
                                     stdout=subprocess.PIPE,
Packit 562c7a
                                     shell=True)
Packit 562c7a
                out, err = p.communicate()
Packit 562c7a
                res = p.returncode
Packit 562c7a
                if res != 0:
Packit 562c7a
                    print(command)
Packit 562c7a
                    print(self._try_decode(out))
Packit 562c7a
                    print(self._try_decode(err))
Packit 562c7a
                self.assertEqual(0, res, "non-zero exit status")
Packit 562c7a
        finally:
Packit 562c7a
            if old_path:
Packit 562c7a
                os.environ['PYTHONPATH'] = old_path
Packit 562c7a
            else:
Packit 562c7a
                del os.environ['PYTHONPATH']
Packit 562c7a
        self.success = True
Packit 562c7a
Packit 562c7a
Packit 562c7a
# TODO: Support cython_freeze needed here as well.
Packit 562c7a
# TODO: Windows support.
Packit 562c7a
Packit 562c7a
class EmbedTest(unittest.TestCase):
Packit 562c7a
Packit 562c7a
    working_dir = "Demos/embed"
Packit 562c7a
Packit 562c7a
    def setUp(self):
Packit 562c7a
        self.old_dir = os.getcwd()
Packit 562c7a
        os.chdir(self.working_dir)
Packit 562c7a
        os.system(
Packit 562c7a
            "make PYTHON='%s' clean > /dev/null" % sys.executable)
Packit 562c7a
Packit 562c7a
    def tearDown(self):
Packit 562c7a
        try:
Packit 562c7a
            os.system(
Packit 562c7a
                "make PYTHON='%s' clean > /dev/null" % sys.executable)
Packit 562c7a
        except:
Packit 562c7a
            pass
Packit 562c7a
        os.chdir(self.old_dir)
Packit 562c7a
Packit 562c7a
    def test_embed(self):
Packit 562c7a
        libname = sysconfig.get_config_var('LIBRARY')
Packit 562c7a
        libdir = sysconfig.get_config_var('LIBDIR')
Packit 562c7a
        if not os.path.isdir(libdir) or libname not in os.listdir(libdir):
Packit 562c7a
            libdir = os.path.join(os.path.dirname(sys.executable), '..', 'lib')
Packit 562c7a
            if not os.path.isdir(libdir) or libname not in os.listdir(libdir):
Packit 562c7a
                libdir = os.path.join(libdir, 'python%d.%d' % sys.version_info[:2], 'config')
Packit 562c7a
                if not os.path.isdir(libdir) or libname not in os.listdir(libdir):
Packit 562c7a
                    # report the error for the original directory
Packit 562c7a
                    libdir = sysconfig.get_config_var('LIBDIR')
Packit 562c7a
        cython = 'cython.py'
Packit 562c7a
        if sys.version_info[0] >=3 and CY3_DIR:
Packit 562c7a
            cython = os.path.join(CY3_DIR, cython)
Packit 562c7a
        cython = os.path.abspath(os.path.join('..', '..', cython))
Packit 562c7a
        self.assert_(os.system(
Packit 562c7a
            "make PYTHON='%s' CYTHON='%s' LIBDIR1='%s' test > make.output" % (sys.executable, cython, libdir)) == 0)
Packit 562c7a
        try:
Packit 562c7a
            os.remove('make.output')
Packit 562c7a
        except OSError:
Packit 562c7a
            pass
Packit 562c7a
Packit 562c7a
Packit 562c7a
class MissingDependencyExcluder(object):
Packit 562c7a
    def __init__(self, deps):
Packit 562c7a
        # deps: { matcher func : module name }
Packit 562c7a
        self.exclude_matchers = []
Packit 562c7a
        for matcher, mod in deps.items():
Packit 562c7a
            try:
Packit 562c7a
                __import__(mod)
Packit 562c7a
            except ImportError:
Packit 562c7a
                self.exclude_matchers.append(string_selector(matcher))
Packit 562c7a
        self.tests_missing_deps = []
Packit 562c7a
    def __call__(self, testname, tags=None):
Packit 562c7a
        for matcher in self.exclude_matchers:
Packit 562c7a
            if matcher(testname, tags):
Packit 562c7a
                self.tests_missing_deps.append(testname)
Packit 562c7a
                return True
Packit 562c7a
        return False
Packit 562c7a
Packit 562c7a
Packit 562c7a
class VersionDependencyExcluder(object):
Packit 562c7a
    def __init__(self, deps):
Packit 562c7a
        # deps: { version : matcher func }
Packit 562c7a
        from sys import version_info
Packit 562c7a
        self.exclude_matchers = []
Packit 562c7a
        for ver, (compare, matcher) in deps.items():
Packit 562c7a
            if compare(version_info, ver):
Packit 562c7a
                self.exclude_matchers.append(matcher)
Packit 562c7a
        self.tests_missing_deps = []
Packit 562c7a
    def __call__(self, testname, tags=None):
Packit 562c7a
        for matcher in self.exclude_matchers:
Packit 562c7a
            if matcher(testname):
Packit 562c7a
                self.tests_missing_deps.append(testname)
Packit 562c7a
                return True
Packit 562c7a
        return False
Packit 562c7a
Packit 562c7a
Packit 562c7a
class FileListExcluder(object):
Packit 562c7a
    def __init__(self, list_file, verbose=False):
Packit 562c7a
        self.verbose = verbose
Packit 562c7a
        self.excludes = {}
Packit 562c7a
        self._list_file = os.path.relpath(list_file)
Packit 562c7a
        with open(list_file) as f:
Packit 562c7a
            for line in f:
Packit 562c7a
                line = line.strip()
Packit 562c7a
                if line and line[0] != '#':
Packit 562c7a
                    self.excludes[line.split()[0]] = True
Packit 562c7a
Packit 562c7a
    def __call__(self, testname, tags=None):
Packit 562c7a
        exclude = (testname in self.excludes
Packit 562c7a
                   or testname.split('.')[-1] in self.excludes)
Packit 562c7a
        if exclude and self.verbose:
Packit 562c7a
            print("Excluding %s because it's listed in %s"
Packit 562c7a
                  % (testname, self._list_file))
Packit 562c7a
        return exclude
Packit 562c7a
Packit 562c7a
Packit 562c7a
class TagsSelector(object):
Packit 562c7a
    def __init__(self, tag, value):
Packit 562c7a
        self.tag = tag
Packit 562c7a
        self.value = value
Packit 562c7a
Packit 562c7a
    def __call__(self, testname, tags=None):
Packit 562c7a
        if tags is None:
Packit 562c7a
            return False
Packit 562c7a
        else:
Packit 562c7a
            return self.value in tags[self.tag]
Packit 562c7a
Packit 562c7a
Packit 562c7a
class RegExSelector(object):
Packit 562c7a
    def __init__(self, pattern_string):
Packit 562c7a
        try:
Packit 562c7a
            self.regex_matches = re.compile(pattern_string, re.I|re.U).search
Packit 562c7a
        except re.error:
Packit 562c7a
            print('Invalid pattern: %r' % pattern_string)
Packit 562c7a
            raise
Packit 562c7a
Packit 562c7a
    def __call__(self, testname, tags=None):
Packit 562c7a
        return self.regex_matches(testname)
Packit 562c7a
Packit 562c7a
Packit 562c7a
def string_selector(s):
Packit 562c7a
    if ':' in s:
Packit 562c7a
        return TagsSelector(*s.split(':', 1))
Packit 562c7a
    else:
Packit 562c7a
        return RegExSelector(s)
Packit 562c7a
Packit 562c7a
Packit 562c7a
class ShardExcludeSelector(object):
Packit 562c7a
    # This is an exclude selector so it can override the (include) selectors.
Packit 562c7a
    # It may not provide uniform distribution (in time or count), but is a
Packit 562c7a
    # determanistic partition of the tests which is important.
Packit 562c7a
    def __init__(self, shard_num, shard_count):
Packit 562c7a
        self.shard_num = shard_num
Packit 562c7a
        self.shard_count = shard_count
Packit 562c7a
Packit 562c7a
    def __call__(self, testname, tags=None, _hash=zlib.crc32, _is_py2=sys.version_info[0] < 3):
Packit 562c7a
        # Cannot use simple hash() here as shard processes might use different hash seeds.
Packit 562c7a
        # CRC32 is fast and simple, but might return negative values in Py2.
Packit 562c7a
        hashval = _hash(testname) & 0x7fffffff if _is_py2 else _hash(testname.encode())
Packit 562c7a
        return hashval % self.shard_count != self.shard_num
Packit 562c7a
Packit 562c7a
Packit 562c7a
class PendingThreadsError(RuntimeError):
Packit 562c7a
    pass
Packit 562c7a
Packit 562c7a
threads_seen = []
Packit 562c7a
Packit 562c7a
def check_thread_termination(ignore_seen=True):
Packit 562c7a
    if threading is None: # no threading enabled in CPython
Packit 562c7a
        return
Packit 562c7a
    current = threading.currentThread()
Packit 562c7a
    blocking_threads = []
Packit 562c7a
    for t in threading.enumerate():
Packit 562c7a
        if not t.isAlive() or t == current:
Packit 562c7a
            continue
Packit 562c7a
        t.join(timeout=2)
Packit 562c7a
        if t.isAlive():
Packit 562c7a
            if not ignore_seen:
Packit 562c7a
                blocking_threads.append(t)
Packit 562c7a
                continue
Packit 562c7a
            for seen in threads_seen:
Packit 562c7a
                if t is seen:
Packit 562c7a
                    break
Packit 562c7a
            else:
Packit 562c7a
                threads_seen.append(t)
Packit 562c7a
                blocking_threads.append(t)
Packit 562c7a
    if not blocking_threads:
Packit 562c7a
        return
Packit 562c7a
    sys.stderr.write("warning: left-over threads found after running test:\n")
Packit 562c7a
    for t in blocking_threads:
Packit 562c7a
        sys.stderr.write('...%s\n'  % repr(t))
Packit 562c7a
    raise PendingThreadsError("left-over threads found after running test")
Packit 562c7a
Packit 562c7a
def subprocess_output(cmd):
Packit 562c7a
    try:
Packit 562c7a
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Packit 562c7a
        return p.communicate()[0].decode('UTF-8')
Packit 562c7a
    except OSError:
Packit 562c7a
        return ''
Packit 562c7a
Packit 562c7a
def get_version():
Packit 562c7a
    from Cython.Compiler.Version import version as cython_version
Packit 562c7a
    full_version = cython_version
Packit 562c7a
    top = os.path.dirname(os.path.abspath(__file__))
Packit 562c7a
    if os.path.exists(os.path.join(top, '.git')):
Packit 562c7a
        old_dir = os.getcwd()
Packit 562c7a
        try:
Packit 562c7a
            os.chdir(top)
Packit 562c7a
            head_commit = subprocess_output(['git', 'rev-parse', 'HEAD']).strip()
Packit 562c7a
            version_commit = subprocess_output(['git', 'rev-parse', cython_version]).strip()
Packit 562c7a
            diff = subprocess_output(['git', 'diff', '--stat']).strip()
Packit 562c7a
            if head_commit != version_commit:
Packit 562c7a
                full_version += " " + head_commit
Packit 562c7a
            if diff:
Packit 562c7a
                full_version += ' + uncommitted changes'
Packit 562c7a
        finally:
Packit 562c7a
            os.chdir(old_dir)
Packit 562c7a
    return full_version
Packit 562c7a
Packit 562c7a
_orig_stdout, _orig_stderr = sys.stdout, sys.stderr
Packit 562c7a
def flush_and_terminate(status):
Packit 562c7a
    try:
Packit 562c7a
        _orig_stdout.flush()
Packit 562c7a
        _orig_stderr.flush()
Packit 562c7a
    finally:
Packit 562c7a
        os._exit(status)
Packit 562c7a
Packit 562c7a
def main():
Packit 562c7a
Packit 562c7a
    global DISTDIR, WITH_CYTHON
Packit 562c7a
    DISTDIR = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]))
Packit 562c7a
Packit 562c7a
    from Cython.Compiler import DebugFlags
Packit 562c7a
    args = []
Packit 562c7a
    for arg in sys.argv[1:]:
Packit 562c7a
        if arg.startswith('--debug') and arg[2:].replace('-', '_') in dir(DebugFlags):
Packit 562c7a
            setattr(DebugFlags, arg[2:].replace('-', '_'), True)
Packit 562c7a
        else:
Packit 562c7a
            args.append(arg)
Packit 562c7a
Packit 562c7a
    from optparse import OptionParser
Packit 562c7a
    parser = OptionParser()
Packit 562c7a
    parser.add_option("--no-cleanup", dest="cleanup_workdir",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not delete the generated C files (allows passing --no-cython on next run)")
Packit 562c7a
    parser.add_option("--no-cleanup-sharedlibs", dest="cleanup_sharedlibs",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not delete the generated shared library files (allows manual module experimentation)")
Packit 562c7a
    parser.add_option("--no-cleanup-failures", dest="cleanup_failures",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="enable --no-cleanup and --no-cleanup-sharedlibs for failed tests only")
Packit 562c7a
    parser.add_option("--no-cython", dest="with_cython",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not run the Cython compiler, only the C compiler")
Packit 562c7a
    parser.add_option("--compiler", dest="compiler", default=None,
Packit 562c7a
                      help="C compiler type")
Packit 562c7a
    backend_list = ','.join(BACKENDS)
Packit 562c7a
    parser.add_option("--backends", dest="backends", default=backend_list,
Packit 562c7a
                      help="select backends to test (default: %s)" % backend_list)
Packit 562c7a
    parser.add_option("--no-c", dest="use_c",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not test C compilation backend")
Packit 562c7a
    parser.add_option("--no-cpp", dest="use_cpp",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not test C++ compilation backend")
Packit 562c7a
    parser.add_option("--no-unit", dest="unittests",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not run the unit tests")
Packit 562c7a
    parser.add_option("--no-doctest", dest="doctests",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not run the doctests")
Packit 562c7a
    parser.add_option("--no-file", dest="filetests",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not run the file based tests")
Packit 562c7a
    parser.add_option("--no-pyregr", dest="pyregr",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not run the regression tests of CPython in tests/pyregr/")
Packit 562c7a
    parser.add_option("--cython-only", dest="cython_only",
Packit 562c7a
                      action="store_true", default=False,
Packit 562c7a
                      help="only compile pyx to c, do not run C compiler or run the tests")
Packit 562c7a
    parser.add_option("--no-refnanny", dest="with_refnanny",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not regression test reference counting")
Packit 562c7a
    parser.add_option("--no-fork", dest="fork",
Packit 562c7a
                      action="store_false", default=True,
Packit 562c7a
                      help="do not fork to run tests")
Packit 562c7a
    parser.add_option("--sys-pyregr", dest="system_pyregr",
Packit 562c7a
                      action="store_true", default=False,
Packit 562c7a
                      help="run the regression tests of the CPython installation")
Packit 562c7a
    parser.add_option("-x", "--exclude", dest="exclude",
Packit 562c7a
                      action="append", metavar="PATTERN",
Packit 562c7a
                      help="exclude tests matching the PATTERN")
Packit 562c7a
    parser.add_option("-j", "--shard_count", dest="shard_count", metavar="N",
Packit 562c7a
                      type=int, default=1,
Packit 562c7a
                      help="shard this run into several parallel runs")
Packit 562c7a
    parser.add_option("--shard_num", dest="shard_num", metavar="K",
Packit 562c7a
                      type=int, default=-1,
Packit 562c7a
                      help="test only this single shard")
Packit 562c7a
    parser.add_option("-C", "--coverage", dest="coverage",
Packit 562c7a
                      action="store_true", default=False,
Packit 562c7a
                      help="collect source coverage data for the Compiler")
Packit 562c7a
    parser.add_option("--coverage-xml", dest="coverage_xml",
Packit 562c7a
                      action="store_true", default=False,
Packit 562c7a
                      help="collect source coverage data for the Compiler in XML format")
Packit 562c7a
    parser.add_option("--coverage-html", dest="coverage_html",
Packit 562c7a
                      action="store_true", default=False,
Packit 562c7a
                      help="collect source coverage data for the Compiler in HTML format")
Packit 562c7a
    parser.add_option("-A", "--annotate", dest="annotate_source",
Packit 562c7a
                      action="store_true", default=True,
Packit 562c7a
                      help="generate annotated HTML versions of the test source files")
Packit 562c7a
    parser.add_option("--no-annotate", dest="annotate_source",
Packit 562c7a
                      action="store_false",
Packit 562c7a
                      help="do not generate annotated HTML versions of the test source files")
Packit 562c7a
    parser.add_option("-v", "--verbose", dest="verbosity",
Packit 562c7a
                      action="count", default=0,
Packit 562c7a
                      help="display test progress, pass twice to print test names")
Packit 562c7a
    parser.add_option("-T", "--ticket", dest="tickets",
Packit 562c7a
                      action="append",
Packit 562c7a
                      help="a bug ticket number to run the respective test in 'tests/*'")
Packit 562c7a
    parser.add_option("-3", dest="language_level",
Packit 562c7a
                      action="store_const", const=3, default=2,
Packit 562c7a
                      help="set language level to Python 3 (useful for running the CPython regression tests)'")
Packit 562c7a
    parser.add_option("--xml-output", dest="xml_output_dir", metavar="DIR",
Packit 562c7a
                      help="write test results in XML to directory DIR")
Packit 562c7a
    parser.add_option("--exit-ok", dest="exit_ok", default=False,
Packit 562c7a
                      action="store_true",
Packit 562c7a
                      help="exit without error code even on test failures")
Packit 562c7a
    parser.add_option("--failfast", dest="failfast", default=False,
Packit 562c7a
                      action="store_true",
Packit 562c7a
                      help="stop on first failure or error")
Packit 562c7a
    parser.add_option("--root-dir", dest="root_dir", default=os.path.join(DISTDIR, 'tests'),
Packit 562c7a
                      help="working directory")
Packit 562c7a
    parser.add_option("--work-dir", dest="work_dir", default=os.path.join(os.getcwd(), 'TEST_TMP'),
Packit 562c7a
                      help="working directory")
Packit 562c7a
    parser.add_option("--cython-dir", dest="cython_dir", default=os.getcwd(),
Packit 562c7a
                      help="Cython installation directory (default: use local source version)")
Packit 562c7a
    parser.add_option("--debug", dest="for_debugging", default=False, action="store_true",
Packit 562c7a
                      help="configure for easier use with a debugger (e.g. gdb)")
Packit 562c7a
    parser.add_option("--pyximport-py", dest="pyximport_py", default=False, action="store_true",
Packit 562c7a
                      help="use pyximport to automatically compile imported .pyx and .py files")
Packit 562c7a
    parser.add_option("--watermark", dest="watermark", default=None,
Packit 562c7a
                      help="deterministic generated by string")
Packit 562c7a
    parser.add_option("--use_common_utility_dir", default=False, action="store_true")
Packit 562c7a
    parser.add_option("--use_formal_grammar", default=False, action="store_true")
Packit 562c7a
    parser.add_option("--test_determinism", default=False, action="store_true",
Packit 562c7a
                      help="test whether Cython's output is deterministic")
Packit 562c7a
    parser.add_option("--pythran-dir", dest="pythran_dir", default=None,
Packit 562c7a
                      help="specify Pythran include directory. This will run the C++ tests using Pythran backend for Numpy")
Packit 562c7a
Packit 562c7a
    options, cmd_args = parser.parse_args(args)
Packit 562c7a
Packit 562c7a
    WORKDIR = os.path.abspath(options.work_dir)
Packit 562c7a
Packit 562c7a
    if options.with_cython and sys.version_info[0] >= 3:
Packit 562c7a
        sys.path.insert(0, options.cython_dir)
Packit 562c7a
Packit 562c7a
    WITH_CYTHON = options.with_cython
Packit 562c7a
Packit 562c7a
    coverage = None
Packit 562c7a
    if options.coverage or options.coverage_xml or options.coverage_html:
Packit 562c7a
        if options.shard_count <= 1 and options.shard_num < 0:
Packit 562c7a
            if not WITH_CYTHON:
Packit 562c7a
                options.coverage = options.coverage_xml = options.coverage_html = False
Packit 562c7a
            else:
Packit 562c7a
                print("Enabling coverage analysis")
Packit 562c7a
                from coverage import coverage as _coverage
Packit 562c7a
                coverage = _coverage(branch=True, omit=['Test*'])
Packit 562c7a
                coverage.erase()
Packit 562c7a
                coverage.start()
Packit 562c7a
Packit 562c7a
    if options.xml_output_dir:
Packit 562c7a
        shutil.rmtree(options.xml_output_dir, ignore_errors=True)
Packit 562c7a
Packit 562c7a
    if options.shard_count > 1 and options.shard_num == -1:
Packit 562c7a
        import multiprocessing
Packit 562c7a
        pool = multiprocessing.Pool(options.shard_count)
Packit 562c7a
        tasks = [(options, cmd_args, shard_num) for shard_num in range(options.shard_count)]
Packit 562c7a
        errors = []
Packit 562c7a
        for shard_num, return_code in pool.imap_unordered(runtests_callback, tasks):
Packit 562c7a
            if return_code != 0:
Packit 562c7a
                errors.append(shard_num)
Packit 562c7a
                print("FAILED (%s/%s)" % (shard_num, options.shard_count))
Packit 562c7a
            print("ALL DONE (%s/%s)" % (shard_num, options.shard_count))
Packit 562c7a
        pool.close()
Packit 562c7a
        pool.join()
Packit 562c7a
        if errors:
Packit 562c7a
            print("Errors for shards %s" % ", ".join([str(e) for e in errors]))
Packit 562c7a
            return_code = 1
Packit 562c7a
        else:
Packit 562c7a
            return_code = 0
Packit 562c7a
    else:
Packit 562c7a
        _, return_code = runtests(options, cmd_args, coverage)
Packit 562c7a
    print("ALL DONE")
Packit 562c7a
Packit 562c7a
    try:
Packit 562c7a
        check_thread_termination(ignore_seen=False)
Packit 562c7a
    except PendingThreadsError:
Packit 562c7a
        # normal program exit won't kill the threads, do it the hard way here
Packit 562c7a
        flush_and_terminate(return_code)
Packit 562c7a
    else:
Packit 562c7a
        sys.exit(return_code)
Packit 562c7a
Packit 562c7a
Packit 562c7a
def configure_cython(options):
Packit 562c7a
    global CompilationOptions, pyrex_default_options, cython_compile
Packit 562c7a
    from Cython.Compiler.Main import \
Packit 562c7a
        CompilationOptions, \
Packit 562c7a
        default_options as pyrex_default_options, \
Packit 562c7a
        compile as cython_compile
Packit 562c7a
    from Cython.Compiler import Errors
Packit 562c7a
    Errors.LEVEL = 0  # show all warnings
Packit 562c7a
    from Cython.Compiler import Options
Packit 562c7a
    Options.generate_cleanup_code = 3  # complete cleanup code
Packit 562c7a
    from Cython.Compiler import DebugFlags
Packit 562c7a
    DebugFlags.debug_temp_code_comments = 1
Packit 562c7a
    pyrex_default_options['formal_grammar'] = options.use_formal_grammar
Packit 562c7a
    if options.watermark:
Packit 562c7a
        import Cython.Compiler.Version
Packit 562c7a
        Cython.Compiler.Version.watermark = options.watermark
Packit 562c7a
Packit 562c7a
Packit 562c7a
def runtests_callback(args):
Packit 562c7a
    options, cmd_args, shard_num = args
Packit 562c7a
    options.shard_num = shard_num
Packit 562c7a
    return runtests(options, cmd_args)
Packit 562c7a
Packit 562c7a
Packit 562c7a
def runtests(options, cmd_args, coverage=None):
Packit 562c7a
Packit 562c7a
    WITH_CYTHON = options.with_cython
Packit 562c7a
    ROOTDIR = os.path.abspath(options.root_dir)
Packit 562c7a
    WORKDIR = os.path.abspath(options.work_dir)
Packit 562c7a
Packit 562c7a
    if WITH_CYTHON:
Packit 562c7a
        configure_cython(options)
Packit 562c7a
Packit 562c7a
    xml_output_dir = options.xml_output_dir
Packit 562c7a
    if options.shard_num > -1:
Packit 562c7a
        WORKDIR = os.path.join(WORKDIR, str(options.shard_num))
Packit 562c7a
        if xml_output_dir:
Packit 562c7a
            xml_output_dir = os.path.join(xml_output_dir, 'shard-%03d' % options.shard_num)
Packit 562c7a
Packit 562c7a
    # RUN ALL TESTS!
Packit 562c7a
    UNITTEST_MODULE = "Cython"
Packit 562c7a
    UNITTEST_ROOT = os.path.join(os.path.dirname(__file__), UNITTEST_MODULE)
Packit 562c7a
    if WITH_CYTHON:
Packit 562c7a
        if os.path.exists(WORKDIR):
Packit 562c7a
            for path in os.listdir(WORKDIR):
Packit 562c7a
                if path in ("support", "Cy3"): continue
Packit 562c7a
                shutil.rmtree(os.path.join(WORKDIR, path), ignore_errors=True)
Packit 562c7a
    if not os.path.exists(WORKDIR):
Packit 562c7a
        os.makedirs(WORKDIR)
Packit 562c7a
Packit 562c7a
    if options.shard_num <= 0:
Packit 562c7a
        sys.stderr.write("Python %s\n" % sys.version)
Packit 562c7a
        sys.stderr.write("\n")
Packit 562c7a
        if WITH_CYTHON:
Packit 562c7a
            sys.stderr.write("Running tests against Cython %s\n" % get_version())
Packit 562c7a
        else:
Packit 562c7a
            sys.stderr.write("Running tests without Cython.\n")
Packit 562c7a
Packit 562c7a
    if options.for_debugging:
Packit 562c7a
        options.cleanup_workdir = False
Packit 562c7a
        options.cleanup_sharedlibs = False
Packit 562c7a
        options.fork = False
Packit 562c7a
        if WITH_CYTHON and include_debugger:
Packit 562c7a
            from Cython.Compiler.Main import default_options as compiler_default_options
Packit 562c7a
            compiler_default_options['gdb_debug'] = True
Packit 562c7a
            compiler_default_options['output_dir'] = os.getcwd()
Packit 562c7a
Packit 562c7a
    if IS_PYPY:
Packit 562c7a
        if options.with_refnanny:
Packit 562c7a
            sys.stderr.write("Disabling refnanny in PyPy\n")
Packit 562c7a
            options.with_refnanny = False
Packit 562c7a
Packit 562c7a
    if options.with_refnanny:
Packit 562c7a
        from pyximport.pyxbuild import pyx_to_dll
Packit 562c7a
        libpath = pyx_to_dll(os.path.join("Cython", "Runtime", "refnanny.pyx"),
Packit 562c7a
                             build_in_temp=True,
Packit 562c7a
                             pyxbuild_dir=os.path.join(WORKDIR, "support"))
Packit 562c7a
        sys.path.insert(0, os.path.split(libpath)[0])
Packit 562c7a
        CFLAGS.append("-DCYTHON_REFNANNY=1")
Packit 562c7a
Packit 562c7a
    if xml_output_dir and options.fork:
Packit 562c7a
        # doesn't currently work together
Packit 562c7a
        sys.stderr.write("Disabling forked testing to support XML test output\n")
Packit 562c7a
        options.fork = False
Packit 562c7a
Packit 562c7a
    if WITH_CYTHON and options.language_level == 3:
Packit 562c7a
        sys.stderr.write("Using Cython language level 3.\n")
Packit 562c7a
Packit 562c7a
    test_bugs = False
Packit 562c7a
    if options.tickets:
Packit 562c7a
        for ticket_number in options.tickets:
Packit 562c7a
            test_bugs = True
Packit 562c7a
            cmd_args.append('ticket:%s' % ticket_number)
Packit 562c7a
    if not test_bugs:
Packit 562c7a
        for selector in cmd_args:
Packit 562c7a
            if selector.startswith('bugs'):
Packit 562c7a
                test_bugs = True
Packit 562c7a
Packit 562c7a
    selectors = [ string_selector(r) for r in cmd_args ]
Packit 562c7a
    verbose_excludes = selectors or options.verbosity >= 2
Packit 562c7a
    if not selectors:
Packit 562c7a
        selectors = [ lambda x, tags=None: True ]
Packit 562c7a
Packit 562c7a
    # Check which external modules are not present and exclude tests
Packit 562c7a
    # which depends on them (by prefix)
Packit 562c7a
Packit 562c7a
    missing_dep_excluder = MissingDependencyExcluder(EXT_DEP_MODULES)
Packit 562c7a
    version_dep_excluder = VersionDependencyExcluder(VER_DEP_MODULES)
Packit 562c7a
    exclude_selectors = [missing_dep_excluder, version_dep_excluder] # want to print msg at exit
Packit 562c7a
Packit 562c7a
    try:
Packit 562c7a
        import IPython.core.release
Packit 562c7a
        if list(IPython.core.release._ver) < [1, 0, 0]:
Packit 562c7a
            raise ImportError
Packit 562c7a
    except (ImportError, AttributeError, TypeError):
Packit 562c7a
        exclude_selectors.append(RegExSelector('IPython'))
Packit 562c7a
Packit 562c7a
    try:
Packit 562c7a
        raise ImportError("Jedi typer is currently broken, see GH#1845")
Packit 562c7a
        import jedi
Packit 562c7a
        if not ([0, 9] <= list(map(int, re.findall('[0-9]+', jedi.__version__ or '0')))):
Packit 562c7a
            raise ImportError
Packit 562c7a
    except (ImportError, AttributeError, TypeError):
Packit 562c7a
        exclude_selectors.append(RegExSelector('Jedi'))
Packit 562c7a
Packit 562c7a
    if options.exclude:
Packit 562c7a
        exclude_selectors += [ string_selector(r) for r in options.exclude ]
Packit 562c7a
Packit 562c7a
    if not COMPILER_HAS_INT128 or not IS_CPYTHON:
Packit 562c7a
        exclude_selectors += [RegExSelector('int128')]
Packit 562c7a
Packit 562c7a
    if options.shard_num > -1:
Packit 562c7a
        exclude_selectors.append(ShardExcludeSelector(options.shard_num, options.shard_count))
Packit 562c7a
Packit 562c7a
    if not test_bugs:
Packit 562c7a
        bug_files = [
Packit 562c7a
            ('bugs.txt', True),
Packit 562c7a
            ('pypy_bugs.txt', IS_PYPY),
Packit 562c7a
            ('windows_bugs.txt', sys.platform == 'win32'),
Packit 562c7a
            ('cygwin_bugs.txt', sys.platform == 'cygwin')
Packit 562c7a
        ]
Packit 562c7a
Packit 562c7a
        exclude_selectors += [
Packit 562c7a
            FileListExcluder(os.path.join(ROOTDIR, bugs_file_name),
Packit 562c7a
                             verbose=verbose_excludes)
Packit 562c7a
            for bugs_file_name, condition in bug_files if condition
Packit 562c7a
        ]
Packit 562c7a
Packit 562c7a
    global COMPILER
Packit 562c7a
    if options.compiler:
Packit 562c7a
        COMPILER = options.compiler
Packit 562c7a
Packit 562c7a
    selected_backends = [ name.strip() for name in options.backends.split(',') if name.strip() ]
Packit 562c7a
    backends = []
Packit 562c7a
    for backend in selected_backends:
Packit 562c7a
        if backend == 'c' and not options.use_c:
Packit 562c7a
            continue
Packit 562c7a
        elif backend == 'cpp' and not options.use_cpp:
Packit 562c7a
            continue
Packit 562c7a
        elif backend not in BACKENDS:
Packit 562c7a
            sys.stderr.write("Unknown backend requested: '%s' not one of [%s]\n" % (
Packit 562c7a
                backend, ','.join(BACKENDS)))
Packit 562c7a
            sys.exit(1)
Packit 562c7a
        backends.append(backend)
Packit 562c7a
    if options.shard_num <= 0:
Packit 562c7a
        sys.stderr.write("Backends: %s\n" % ','.join(backends))
Packit 562c7a
    languages = backends
Packit 562c7a
Packit 562c7a
    if 'TRAVIS' in os.environ and sys.platform == 'darwin' and 'cpp' in languages:
Packit 562c7a
        bugs_file_name = 'travis_macos_cpp_bugs.txt'
Packit 562c7a
        exclude_selectors += [
Packit 562c7a
            FileListExcluder(os.path.join(ROOTDIR, bugs_file_name),
Packit 562c7a
                             verbose=verbose_excludes)
Packit 562c7a
        ]
Packit 562c7a
Packit 562c7a
    if options.use_common_utility_dir:
Packit 562c7a
        common_utility_dir = os.path.join(WORKDIR, 'utility_code')
Packit 562c7a
        if not os.path.exists(common_utility_dir):
Packit 562c7a
            os.makedirs(common_utility_dir)
Packit 562c7a
    else:
Packit 562c7a
        common_utility_dir = None
Packit 562c7a
Packit 562c7a
    sys.stderr.write("\n")
Packit 562c7a
Packit 562c7a
    test_suite = unittest.TestSuite()
Packit 562c7a
Packit 562c7a
    if options.unittests:
Packit 562c7a
        collect_unittests(UNITTEST_ROOT, UNITTEST_MODULE + ".", test_suite, selectors, exclude_selectors)
Packit 562c7a
Packit 562c7a
    if options.doctests:
Packit 562c7a
        collect_doctests(UNITTEST_ROOT, UNITTEST_MODULE + ".", test_suite, selectors, exclude_selectors)
Packit 562c7a
Packit 562c7a
    if options.filetests and languages:
Packit 562c7a
        filetests = TestBuilder(ROOTDIR, WORKDIR, selectors, exclude_selectors,
Packit 562c7a
                                options.annotate_source, options.cleanup_workdir,
Packit 562c7a
                                options.cleanup_sharedlibs, options.cleanup_failures,
Packit 562c7a
                                options.pyregr,
Packit 562c7a
                                options.cython_only, languages, test_bugs,
Packit 562c7a
                                options.fork, options.language_level,
Packit 562c7a
                                options.test_determinism,
Packit 562c7a
                                common_utility_dir, options.pythran_dir)
Packit 562c7a
        test_suite.addTest(filetests.build_suite())
Packit 562c7a
Packit 562c7a
    if options.system_pyregr and languages:
Packit 562c7a
        sys_pyregr_dir = os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test')
Packit 562c7a
        if not os.path.isdir(sys_pyregr_dir):
Packit 562c7a
            sys_pyregr_dir = os.path.join(os.path.dirname(sys.executable), 'Lib', 'test')  # source build
Packit 562c7a
        if os.path.isdir(sys_pyregr_dir):
Packit 562c7a
            filetests = TestBuilder(ROOTDIR, WORKDIR, selectors, exclude_selectors,
Packit 562c7a
                                    options.annotate_source, options.cleanup_workdir,
Packit 562c7a
                                    options.cleanup_sharedlibs, options.cleanup_failures,
Packit 562c7a
                                    True,
Packit 562c7a
                                    options.cython_only, languages, test_bugs,
Packit 562c7a
                                    options.fork, sys.version_info[0],
Packit 562c7a
                                    options.test_determinism,
Packit 562c7a
                                    common_utility_dir)
Packit 562c7a
            sys.stderr.write("Including CPython regression tests in %s\n" % sys_pyregr_dir)
Packit 562c7a
            test_suite.addTest(filetests.handle_directory(sys_pyregr_dir, 'pyregr'))
Packit 562c7a
Packit 562c7a
    if xml_output_dir:
Packit 562c7a
        from Cython.Tests.xmlrunner import XMLTestRunner
Packit 562c7a
        if not os.path.exists(xml_output_dir):
Packit 562c7a
            try: os.makedirs(xml_output_dir)
Packit 562c7a
            except OSError: pass  # concurrency issue?
Packit 562c7a
        test_runner = XMLTestRunner(output=xml_output_dir,
Packit 562c7a
                                    verbose=options.verbosity > 0)
Packit 562c7a
        if options.failfast:
Packit 562c7a
            sys.stderr.write("--failfast not supported with XML runner\n")
Packit 562c7a
    else:
Packit 562c7a
        text_runner_options = {}
Packit 562c7a
        if options.failfast:
Packit 562c7a
            if sys.version_info < (2, 7):
Packit 562c7a
                sys.stderr.write("--failfast not supported with Python < 2.7\n")
Packit 562c7a
            else:
Packit 562c7a
                text_runner_options['failfast'] = True
Packit 562c7a
        test_runner = unittest.TextTestRunner(verbosity=options.verbosity, **text_runner_options)
Packit 562c7a
Packit 562c7a
    if options.pyximport_py:
Packit 562c7a
        from pyximport import pyximport
Packit 562c7a
        pyximport.install(pyimport=True, build_dir=os.path.join(WORKDIR, '_pyximport'),
Packit 562c7a
                          load_py_module_on_import_failure=True, inplace=True)
Packit 562c7a
Packit 562c7a
    try:
Packit 562c7a
        gc.set_debug(gc.DEBUG_UNCOLLECTABLE)
Packit 562c7a
    except AttributeError:
Packit 562c7a
        pass  # not available on PyPy
Packit 562c7a
Packit 562c7a
    result = test_runner.run(test_suite)
Packit 562c7a
Packit 562c7a
    if common_utility_dir and options.shard_num < 0 and options.cleanup_workdir:
Packit 562c7a
        shutil.rmtree(common_utility_dir)
Packit 562c7a
Packit 562c7a
    if coverage is not None:
Packit 562c7a
        coverage.stop()
Packit 562c7a
        ignored_modules = set(
Packit 562c7a
            'Cython.Compiler.' + name
Packit 562c7a
            for name in ('Version', 'DebugFlags', 'CmdLine')) | set(
Packit 562c7a
            'Cython.' + name
Packit 562c7a
            for name in ('Debugging',))
Packit 562c7a
        ignored_packages = ['Cython.Runtime', 'Cython.Tempita']
Packit 562c7a
        modules = [
Packit 562c7a
            module for name, module in sys.modules.items()
Packit 562c7a
            if module is not None and
Packit 562c7a
            name.startswith('Cython.') and
Packit 562c7a
            '.Tests' not in name and
Packit 562c7a
            name not in ignored_modules and
Packit 562c7a
            not any(name.startswith(package) for package in ignored_packages)
Packit 562c7a
        ]
Packit 562c7a
        if options.coverage:
Packit 562c7a
            coverage.report(modules, show_missing=0)
Packit 562c7a
        if options.coverage_xml:
Packit 562c7a
            coverage.xml_report(modules, outfile="coverage-report.xml")
Packit 562c7a
        if options.coverage_html:
Packit 562c7a
            coverage.html_report(modules, directory="coverage-report-html")
Packit 562c7a
Packit 562c7a
    if missing_dep_excluder.tests_missing_deps:
Packit 562c7a
        sys.stderr.write("Following tests excluded because of missing dependencies on your system:\n")
Packit 562c7a
        for test in missing_dep_excluder.tests_missing_deps:
Packit 562c7a
            sys.stderr.write("   %s\n" % test)
Packit 562c7a
Packit 562c7a
    if options.with_refnanny:
Packit 562c7a
        import refnanny
Packit 562c7a
        sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog]))
Packit 562c7a
Packit 562c7a
    if options.exit_ok:
Packit 562c7a
        return options.shard_num, 0
Packit 562c7a
    else:
Packit 562c7a
        return options.shard_num, not result.wasSuccessful()
Packit 562c7a
Packit 562c7a
Packit 562c7a
if __name__ == '__main__':
Packit 562c7a
    try:
Packit 562c7a
        main()
Packit 562c7a
    except Exception:
Packit 562c7a
        traceback.print_exc()
Packit 562c7a
        try:
Packit 562c7a
            check_thread_termination(ignore_seen=False)
Packit 562c7a
        except PendingThreadsError:
Packit 562c7a
            # normal program exit won't kill the threads, do it the hard way here
Packit 562c7a
            flush_and_terminate(1)
Packit 562c7a
        sys.exit(1)