70c5794c471bfebc6c57db29a24938299a4e74b9
[platform/upstream/python3-setuptools.git] / setuptools / tests / test_develop.py
1 """develop tests
2 """
3
4 import os
5 import sys
6 import subprocess
7 import platform
8 import pathlib
9 import textwrap
10
11 from setuptools.command import test
12
13 import pytest
14
15 from setuptools.command.develop import develop
16 from setuptools.dist import Distribution
17 from . import contexts
18 from . import namespaces
19
20 SETUP_PY = """\
21 from setuptools import setup
22
23 setup(name='foo',
24     packages=['foo'],
25 )
26 """
27
28 INIT_PY = """print "foo"
29 """
30
31
32 @pytest.fixture
33 def temp_user(monkeypatch):
34     with contexts.tempdir() as user_base:
35         with contexts.tempdir() as user_site:
36             monkeypatch.setattr('site.USER_BASE', user_base)
37             monkeypatch.setattr('site.USER_SITE', user_site)
38             yield
39
40
41 @pytest.fixture
42 def test_env(tmpdir, temp_user):
43     target = tmpdir
44     foo = target.mkdir('foo')
45     setup = target / 'setup.py'
46     if setup.isfile():
47         raise ValueError(dir(target))
48     with setup.open('w') as f:
49         f.write(SETUP_PY)
50     init = foo / '__init__.py'
51     with init.open('w') as f:
52         f.write(INIT_PY)
53     with target.as_cwd():
54         yield target
55
56
57 class TestDevelop:
58     in_virtualenv = hasattr(sys, 'real_prefix')
59     in_venv = hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix
60
61     def test_console_scripts(self, tmpdir):
62         """
63         Test that console scripts are installed and that they reference
64         only the project by name and not the current version.
65         """
66         pytest.skip(
67             "TODO: needs a fixture to cause 'develop' "
68             "to be invoked without mutating environment."
69         )
70         settings = dict(
71             name='foo',
72             packages=['foo'],
73             version='0.0',
74             entry_points={
75                 'console_scripts': [
76                     'foocmd = foo:foo',
77                 ],
78             },
79         )
80         dist = Distribution(settings)
81         dist.script_name = 'setup.py'
82         cmd = develop(dist)
83         cmd.ensure_finalized()
84         cmd.install_dir = tmpdir
85         cmd.run()
86         # assert '0.0' not in foocmd_text
87
88
89 class TestResolver:
90     """
91     TODO: These tests were written with a minimal understanding
92     of what _resolve_setup_path is intending to do. Come up with
93     more meaningful cases that look like real-world scenarios.
94     """
95
96     def test_resolve_setup_path_cwd(self):
97         assert develop._resolve_setup_path('.', '.', '.') == '.'
98
99     def test_resolve_setup_path_one_dir(self):
100         assert develop._resolve_setup_path('pkgs', '.', 'pkgs') == '../'
101
102     def test_resolve_setup_path_one_dir_trailing_slash(self):
103         assert develop._resolve_setup_path('pkgs/', '.', 'pkgs') == '../'
104
105
106 class TestNamespaces:
107     @staticmethod
108     def install_develop(src_dir, target):
109
110         develop_cmd = [
111             sys.executable,
112             'setup.py',
113             'develop',
114             '--install-dir',
115             str(target),
116         ]
117         with src_dir.as_cwd():
118             with test.test.paths_on_pythonpath([str(target)]):
119                 subprocess.check_call(develop_cmd)
120
121     @pytest.mark.skipif(
122         bool(os.environ.get("APPVEYOR")),
123         reason="https://github.com/pypa/setuptools/issues/851",
124     )
125     @pytest.mark.skipif(
126         platform.python_implementation() == 'PyPy',
127         reason="https://github.com/pypa/setuptools/issues/1202",
128     )
129     def test_namespace_package_importable(self, tmpdir):
130         """
131         Installing two packages sharing the same namespace, one installed
132         naturally using pip or `--single-version-externally-managed`
133         and the other installed using `develop` should leave the namespace
134         in tact and both packages reachable by import.
135         """
136         pkg_A = namespaces.build_namespace_package(tmpdir, 'myns.pkgA')
137         pkg_B = namespaces.build_namespace_package(tmpdir, 'myns.pkgB')
138         target = tmpdir / 'packages'
139         # use pip to install to the target directory
140         install_cmd = [
141             sys.executable,
142             '-m',
143             'pip',
144             'install',
145             str(pkg_A),
146             '-t',
147             str(target),
148         ]
149         subprocess.check_call(install_cmd)
150         self.install_develop(pkg_B, target)
151         namespaces.make_site_dir(target)
152         try_import = [
153             sys.executable,
154             '-c',
155             'import myns.pkgA; import myns.pkgB',
156         ]
157         with test.test.paths_on_pythonpath([str(target)]):
158             subprocess.check_call(try_import)
159
160         # additionally ensure that pkg_resources import works
161         pkg_resources_imp = [
162             sys.executable,
163             '-c',
164             'import pkg_resources',
165         ]
166         with test.test.paths_on_pythonpath([str(target)]):
167             subprocess.check_call(pkg_resources_imp)
168
169     @staticmethod
170     def install_workaround(site_packages):
171         site_packages.mkdir(parents=True)
172         sc = site_packages / 'sitecustomize.py'
173         sc.write_text(
174             textwrap.dedent(
175                 """
176             import site
177             import pathlib
178             here = pathlib.Path(__file__).parent
179             site.addsitedir(str(here))
180             """
181             ).lstrip()
182         )
183
184     @pytest.mark.xfail(
185         platform.python_implementation() == 'PyPy',
186         reason="Workaround fails on PyPy (why?)",
187     )
188     def test_editable_prefix(self, tmp_path, sample_project):
189         """
190         Editable install to a prefix should be discoverable.
191         """
192         prefix = tmp_path / 'prefix'
193         prefix.mkdir()
194
195         # figure out where pip will likely install the package
196         site_packages = prefix / next(
197             pathlib.Path(path).relative_to(sys.prefix)
198             for path in sys.path
199             if 'site-packages' in path and path.startswith(sys.prefix)
200         )
201
202         # install the workaround
203         self.install_workaround(site_packages)
204
205         env = dict(os.environ, PYTHONPATH=str(site_packages))
206         cmd = [
207             sys.executable,
208             '-m',
209             'pip',
210             'install',
211             '--editable',
212             str(sample_project),
213             '--prefix',
214             str(prefix),
215             '--no-build-isolation',
216         ]
217         subprocess.check_call(cmd, env=env)
218
219         # now run 'sample' with the prefix on the PYTHONPATH
220         bin = 'Scripts' if platform.system() == 'Windows' else 'bin'
221         exe = prefix / bin / 'sample'
222         if sys.version_info < (3, 7) and platform.system() == 'Windows':
223             exe = str(exe)
224         subprocess.check_call([exe], env=env)