Skip to content

Commit 516adb4

Browse files
authored
Merge pull request #5190 from benoit-pierre/fix_pep518_support
fix PEP 518 support
2 parents 8e07440 + 6da1d9e commit 516adb4

File tree

7 files changed

+63
-119
lines changed

7 files changed

+63
-119
lines changed

news/5188.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix PEP 518 support.

src/pip/_internal/build_env.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"""
33

44
import os
5+
from distutils.sysconfig import get_python_lib
56
from sysconfig import get_paths
67

78
from pip._internal.utils.temp_dir import TempDirectory
@@ -38,11 +39,14 @@ def __enter__(self):
3839
else:
3940
os.environ['PATH'] = scripts + os.pathsep + os.defpath
4041

41-
if install_dirs['purelib'] == install_dirs['platlib']:
42-
lib_dirs = install_dirs['purelib']
42+
# Note: prefer distutils' sysconfig to get the
43+
# library paths so PyPy is correctly supported.
44+
purelib = get_python_lib(plat_specific=0, prefix=self.path)
45+
platlib = get_python_lib(plat_specific=1, prefix=self.path)
46+
if purelib == platlib:
47+
lib_dirs = purelib
4348
else:
44-
lib_dirs = install_dirs['purelib'] + os.pathsep + \
45-
install_dirs['platlib']
49+
lib_dirs = purelib + os.pathsep + platlib
4650
if self.save_pythonpath:
4751
os.environ['PYTHONPATH'] = lib_dirs + os.pathsep + \
4852
self.save_pythonpath

src/pip/_internal/commands/wheel.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from pip._internal.operations.prepare import RequirementPreparer
1212
from pip._internal.req import RequirementSet
1313
from pip._internal.resolve import Resolver
14-
from pip._internal.utils.misc import import_or_raise
1514
from pip._internal.utils.temp_dir import TempDirectory
1615
from pip._internal.wheel import WheelBuilder
1716

@@ -102,28 +101,7 @@ def __init__(self, *args, **kw):
102101
self.parser.insert_option_group(0, index_opts)
103102
self.parser.insert_option_group(0, cmd_opts)
104103

105-
def check_required_packages(self):
106-
import_or_raise(
107-
'wheel.bdist_wheel',
108-
CommandError,
109-
"'pip wheel' requires the 'wheel' package. To fix this, run: "
110-
"pip install wheel"
111-
)
112-
113-
need_setuptools_message = (
114-
"'pip wheel' requires setuptools >= 0.8 for dist-info support. "
115-
"To fix this, run: pip install --upgrade setuptools>=0.8"
116-
)
117-
pkg_resources = import_or_raise(
118-
'pkg_resources',
119-
CommandError,
120-
need_setuptools_message
121-
)
122-
if not hasattr(pkg_resources, 'DistInfoDistribution'):
123-
raise CommandError(need_setuptools_message)
124-
125104
def run(self, options, args):
126-
self.check_required_packages()
127105
cmdoptions.check_install_build_global(options)
128106

129107
index_urls = [options.index_url] + options.extra_index_urls

src/pip/_internal/operations/prepare.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,25 +126,31 @@ def prep_for_dist(self, finder, build_isolation):
126126
build_requirements, isolate = self.req.get_pep_518_info()
127127
should_isolate = build_isolation and isolate
128128

129-
if 'setuptools' not in build_requirements:
129+
minimum_requirements = ('setuptools', 'wheel')
130+
missing_requirements = set(minimum_requirements) - set(
131+
pkg_resources.Requirement(r).key
132+
for r in build_requirements
133+
)
134+
if missing_requirements:
135+
def format_reqs(rs):
136+
return ' and '.join(map(repr, sorted(rs)))
130137
logger.warning(
131-
"%s does not include 'setuptools' as a buildtime requirement "
132-
"in its pyproject.toml.", self.req.name,
138+
"Missing build time requirements in pyproject.toml for %s: "
139+
"%s.", self.req, format_reqs(missing_requirements)
133140
)
134141
logger.warning(
135142
"This version of pip does not implement PEP 517 so it cannot "
136-
"build a wheel without setuptools."
143+
"build a wheel without %s.", format_reqs(minimum_requirements)
137144
)
138145

139-
if not should_isolate:
140-
self.req.build_env = NoOpBuildEnvironment(no_clean=False)
141-
142-
with self.req.build_env as prefix:
143-
if should_isolate:
146+
if should_isolate:
147+
with self.req.build_env as prefix:
144148
_install_build_reqs(finder, prefix, build_requirements)
149+
else:
150+
self.req.build_env = NoOpBuildEnvironment(no_clean=False)
145151

146-
self.req.run_egg_info()
147-
self.req.assert_source_matches_version()
152+
self.req.run_egg_info()
153+
self.req.assert_source_matches_version()
148154

149155

150156
class Installed(DistAbstraction):

src/pip/_internal/req/req_install.py

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -413,24 +413,6 @@ def setup_py_dir(self):
413413
@property
414414
def setup_py(self):
415415
assert self.source_dir, "No source dir for %s" % self
416-
cmd = [sys.executable, '-c', 'import setuptools']
417-
output = call_subprocess(
418-
cmd,
419-
show_stdout=False,
420-
command_desc='python -c "import setuptools"',
421-
on_returncode='ignore',
422-
)
423-
424-
if output:
425-
if get_installed_version('setuptools') is None:
426-
add_msg = "Please install setuptools."
427-
else:
428-
add_msg = output
429-
# Setuptools is not available
430-
raise InstallationError(
431-
"Could not import setuptools which is required to "
432-
"install from a source distribution.\n%s" % add_msg
433-
)
434416

435417
setup_py = os.path.join(self.setup_py_dir, 'setup.py')
436418

@@ -496,11 +478,12 @@ def run_egg_info(self):
496478
egg_info_dir = os.path.join(self.setup_py_dir, 'pip-egg-info')
497479
ensure_dir(egg_info_dir)
498480
egg_base_option = ['--egg-base', 'pip-egg-info']
499-
call_subprocess(
500-
egg_info_cmd + egg_base_option,
501-
cwd=self.setup_py_dir,
502-
show_stdout=False,
503-
command_desc='python setup.py egg_info')
481+
with self.build_env:
482+
call_subprocess(
483+
egg_info_cmd + egg_base_option,
484+
cwd=self.setup_py_dir,
485+
show_stdout=False,
486+
command_desc='python setup.py egg_info')
504487

505488
if not self.req:
506489
if isinstance(parse_version(self.pkg_info()["Version"]), Version):
@@ -788,12 +771,13 @@ def install(self, install_options, global_options=None, root=None,
788771
msg = 'Running setup.py install for %s' % (self.name,)
789772
with open_spinner(msg) as spinner:
790773
with indent_log():
791-
call_subprocess(
792-
install_args + install_options,
793-
cwd=self.setup_py_dir,
794-
show_stdout=False,
795-
spinner=spinner,
796-
)
774+
with self.build_env:
775+
call_subprocess(
776+
install_args + install_options,
777+
cwd=self.setup_py_dir,
778+
show_stdout=False,
779+
spinner=spinner,
780+
)
797781

798782
if not os.path.exists(record_filename):
799783
logger.debug('Record file %s not found', record_filename)

tests/functional/test_install.py

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,48 +19,30 @@
1919
from tests.lib.path import Path
2020

2121

22-
def test_without_setuptools(script, data):
23-
script.pip("uninstall", "setuptools", "-y")
24-
result = script.run(
25-
"python", "-c",
26-
"import pip._internal; pip._internal.main(["
27-
"'install', "
28-
"'INITools==0.2', "
29-
"'-f', '%s', "
30-
"'--no-binary=:all:'])" % data.packages,
31-
expect_error=True,
32-
)
33-
assert (
34-
"Could not import setuptools which is required to install from a "
35-
"source distribution."
36-
in result.stderr
37-
)
38-
assert "Please install setuptools" in result.stderr
39-
40-
41-
def test_with_setuptools_and_import_error(script, data):
42-
# Make sure we get an ImportError while importing setuptools
43-
setuptools_init_path = script.site_packages_path.join(
44-
"setuptools", "__init__.py")
45-
with open(setuptools_init_path, 'a') as f:
46-
f.write('\nraise ImportError("toto")')
47-
48-
result = script.run(
49-
"python", "-c",
50-
"import pip._internal; pip._internal.main(["
51-
"'install', "
52-
"'INITools==0.2', "
53-
"'-f', '%s', "
54-
"'--no-binary=:all:'])" % data.packages,
55-
expect_error=True,
56-
)
57-
assert (
58-
"Could not import setuptools which is required to install from a "
59-
"source distribution."
60-
in result.stderr
61-
)
62-
assert "Traceback " in result.stderr
63-
assert "ImportError: toto" in result.stderr
22+
@pytest.mark.parametrize('original_setuptools', ('missing', 'bad'))
23+
def test_pep518_uses_build_env(script, data, original_setuptools):
24+
if original_setuptools == 'missing':
25+
script.pip("uninstall", "-y", "setuptools")
26+
elif original_setuptools == 'bad':
27+
setuptools_init_path = script.site_packages_path.join(
28+
"setuptools", "__init__.py")
29+
with open(setuptools_init_path, 'a') as f:
30+
f.write('\nraise ImportError("toto")')
31+
else:
32+
raise ValueError(original_setuptools)
33+
to_install = data.src.join("pep518-3.0")
34+
for command in ('install', 'wheel'):
35+
kwargs = {}
36+
if sys.version_info[:2] == (3, 3):
37+
# Ignore Python 3.3 deprecation warning...
38+
kwargs['expect_stderr'] = True
39+
script.run(
40+
"python", "-c",
41+
"import pip._internal; pip._internal.main(["
42+
"%r, " "'-f', %r, " "%r, "
43+
"])" % (command, str(data.packages), str(to_install)),
44+
**kwargs
45+
)
6446

6547

6648
@pytest.mark.network

tests/functional/test_wheel.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,6 @@
99
from tests.lib import pyversion
1010

1111

12-
def test_basic_pip_wheel_fails_without_wheel(script, data):
13-
"""
14-
Test 'pip wheel' fails without wheel
15-
"""
16-
result = script.pip(
17-
'wheel', '--no-index', '-f', data.find_links, 'simple==3.0',
18-
expect_error=True,
19-
)
20-
assert "'pip wheel' requires the 'wheel' package" in result.stderr
21-
22-
2312
def test_wheel_exit_status_code_when_no_requirements(script, common_wheels):
2413
"""
2514
Test wheel exit status code when no requirements specified

0 commit comments

Comments
 (0)