File: __init__.py

package info (click to toggle)
extension-helpers 1.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 280 kB
  • sloc: python: 1,082; ansic: 69; makefile: 16
file content (141 lines) | stat: -rw-r--r-- 4,414 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import os
import subprocess as sp
import sys

import pytest

from ..conftest import HAS_COVERAGE, SUBPROCESS_COVERAGE, CoverageData

PACKAGE_DIR = os.path.dirname(__file__)


def run_cmd(cmd, args, path=None, raise_error=True):
    """
    Runs a shell command with the given argument list.  Changes directory to
    ``path`` if given, otherwise runs the command in the current directory.

    Returns a 3-tuple of (stdout, stderr, exit code)

    If ``raise_error=True`` raise an exception on non-zero exit codes.
    """

    if path is not None:
        # Transparently support py.path objects
        path = str(path)

    p = sp.Popen([cmd] + list(args), stdout=sp.PIPE, stderr=sp.PIPE, cwd=path)
    streams = tuple(s.decode("latin1").strip() for s in p.communicate())
    return_code = p.returncode

    if raise_error and return_code != 0:
        raise RuntimeError(
            f"The command `{cmd}` with args {list(args)!r} exited with code {return_code}.\n"
            f"Stdout:\n\n{streams[0]}\n\nStderr:\n\n{streams[1]}"
        )

    return streams + (return_code,)


def run_setup(setup_script, args):
    # This used to call setuptools.sandbox's run_setup, but due to issues with
    # this and Cython (which caused segmentation faults), we now use subprocess.

    setup_script = os.path.abspath(setup_script)

    path = os.path.dirname(setup_script)
    setup_script = os.path.basename(setup_script)

    if HAS_COVERAGE:
        # In this case, we run the command using the coverage command and we
        # then collect the coverage data into a SUBPROCESS_COVERAGE list which
        # is set up at the start of the testing process and is then combined
        # into a single .coverage file at the end of the testing process.

        p = sp.Popen(
            ["coverage", "run", setup_script] + list(args), cwd=path, stdout=sp.PIPE, stderr=sp.PIPE
        )
        stdout, stderr = p.communicate()

        cdata = CoverageData()
        if HAS_COVERAGE >= 5:
            # Support coverage<5 and >=5; see
            # https://github.com/astropy/extension-helpers/issues/24
            cdata.read()
        else:
            cdata.read_file(os.path.join(path, ".coverage"))

        SUBPROCESS_COVERAGE.append(cdata)

    else:
        # Otherwise we just run the tests with Python

        p = sp.Popen(
            [sys.executable, setup_script] + list(args), cwd=path, stdout=sp.PIPE, stderr=sp.PIPE
        )
        stdout, stderr = p.communicate()

    sys.stdout.write(stdout.decode("utf-8"))
    sys.stderr.write(stderr.decode("utf-8"))

    if p.returncode != 0:
        raise SystemExit(p.returncode)


TEST_PACKAGE_SETUP_PY = """\
#!/usr/bin/env python

from setuptools import setup

NAME = 'extension-helpers-test'
VERSION = {version!r}

setup(name=NAME, version=VERSION,
      packages=['_extension_helpers_test_'],
      zip_safe=False)
"""


def create_testpackage(tmp_path, version="0.1"):
    source = tmp_path / "testpkg"
    os.mkdir(source)

    with source.as_cwd():
        source.mkdir("_extension_helpers_test_")
        init = source.join("_extension_helpers_test_", "__init__.py")
        init.write(f"__version__ = {version!r}")
        setup_py = TEST_PACKAGE_SETUP_PY.format(version=version)
        source.join("setup.py").write(setup_py)

        # Make the new test package into a git repo
        run_cmd("git", ["init"])
        run_cmd("git", ["add", "--all"])
        run_cmd("git", ["commit", "-m", "test package"])

    return source


@pytest.fixture
def testpackage(tmp_path, version="0.1"):
    """
    This fixture creates a simplified package called _extension_helpers_test_
    used primarily for testing ah_boostrap, but without using the
    extension_helpers package directly and getting it confused with the
    extension_helpers package already under test.
    """

    return create_testpackage(tmp_path, version=version)


def cleanup_import(package_name):
    """Remove all references to package_name from sys.modules"""

    for k in list(sys.modules):
        if not isinstance(k, str):
            # Some things will actually do this =_=
            continue
        elif k.startswith("extension_helpers.tests"):
            # Don't delete imported test modules or else the tests will break,
            # badly
            continue
        if k == package_name or k.startswith(package_name + "."):
            del sys.modules[k]