1import subprocess
2from textwrap import dedent
3
4import pytest
5import jaraco.envs
6import path
7
8
9@pytest.fixture
10def venv(tmp_path, setuptools_wheel):
11    env = jaraco.envs.VirtualEnv()
12    vars(env).update(
13        root=path.Path(tmp_path),  # workaround for error on windows
14        name=".venv",
15        create_opts=["--no-setuptools"],
16        req=str(setuptools_wheel),
17    )
18    return env.create()
19
20
21EXAMPLE = {
22    'pyproject.toml': dedent("""\
23        [build-system]
24        requires = ["setuptools", "wheel"]
25        build-backend = "setuptools.build_meta"
26
27        [project]
28        name = "mypkg"
29        version = "3.14159"
30        license = {text = "MIT"}
31        description = "This is a Python package"
32        dynamic = ["readme"]
33        classifiers = [
34            "Development Status :: 5 - Production/Stable",
35            "Intended Audience :: Developers"
36        ]
37        urls = {Homepage = "http://github.com"}
38        dependencies = ['importlib-metadata; python_version<"3.8"']
39
40        [tool.setuptools]
41        package-dir = {"" = "src"}
42        packages = {find = {where = ["src"]}}
43        license-files = ["LICENSE*"]
44
45        [tool.setuptools.dynamic]
46        readme = {file = "README.rst"}
47
48        [tool.distutils.egg_info]
49        tag-build = ".post0"
50        """),
51    "MANIFEST.in": dedent("""\
52        global-include *.py *.txt
53        global-exclude *.py[cod]
54        """).strip(),
55    "README.rst": "This is a ``README``",
56    "LICENSE.txt": "---- placeholder MIT license ----",
57    "src": {
58        "mypkg": {
59            "__init__.py": dedent("""\
60                import sys
61
62                if sys.version_info[:2] >= (3, 8):
63                    from importlib.metadata import PackageNotFoundError, version
64                else:
65                    from importlib_metadata import PackageNotFoundError, version
66
67                try:
68                    __version__ = version(__name__)
69                except PackageNotFoundError:
70                    __version__ = "unknown"
71                """),
72            "__main__.py": dedent("""\
73                from importlib.resources import read_text
74                from . import __version__, __name__ as parent
75                from .mod import x
76
77                data = read_text(parent, "data.txt")
78                print(__version__, data, x)
79                """),
80            "mod.py": "x = ''",
81            "data.txt": "Hello World",
82        }
83    }
84}
85
86
87SETUP_SCRIPT_STUB = "__import__('setuptools').setup()"
88MISSING_SETUP_SCRIPT = pytest.param(
89    None,
90    marks=pytest.mark.xfail(
91        reason="Editable install is currently only supported with `setup.py`"
92    )
93)
94
95
96@pytest.mark.parametrize("setup_script", [SETUP_SCRIPT_STUB, MISSING_SETUP_SCRIPT])
97def test_editable_with_pyproject(tmp_path, venv, setup_script):
98    project = tmp_path / "mypkg"
99    files = {**EXAMPLE, "setup.py": setup_script}
100    project.mkdir()
101    jaraco.path.build(files, prefix=project)
102
103    cmd = [venv.exe(), "-m", "pip", "install",
104           "--no-build-isolation",  # required to force current version of setuptools
105           "-e", str(project)]
106    print(str(subprocess.check_output(cmd), "utf-8"))
107
108    cmd = [venv.exe(), "-m", "mypkg"]
109    assert subprocess.check_output(cmd).strip() == b"3.14159.post0 Hello World"
110
111    (project / "src/mypkg/data.txt").write_text("foobar")
112    (project / "src/mypkg/mod.py").write_text("x = 42")
113    assert subprocess.check_output(cmd).strip() == b"3.14159.post0 foobar 42"
114