Skip to content

Commit dc217bb

Browse files
committed
Improve our setuptools shim
Modernise the shim, to account for the Python 3.2+ support matrix. This also presents clearer error messages on failures, the included comment helps inform users about why this shim exists and the traceback now explicitly mentions `<pip-setuptools-shim>` to make it clearer to users that this shim exists.
1 parent eb04d61 commit dc217bb

File tree

2 files changed

+44
-17
lines changed

2 files changed

+44
-17
lines changed

src/pip/_internal/utils/setuptools_build.py

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,45 @@
11
import sys
2+
import textwrap
23
from typing import List, Optional, Sequence
34

45
# Shim to wrap setup.py invocation with setuptools
5-
#
6-
# We set sys.argv[0] to the path to the underlying setup.py file so
7-
# setuptools / distutils don't take the path to the setup.py to be "-c" when
8-
# invoking via the shim. This avoids e.g. the following manifest_maker
9-
# warning: "warning: manifest_maker: standard file '-c' not found".
10-
_SETUPTOOLS_SHIM = (
11-
"import io, os, sys, setuptools, tokenize; sys.argv[0] = {0!r}; __file__={0!r};"
12-
"f = getattr(tokenize, 'open', open)(__file__) "
13-
"if os.path.exists(__file__) "
14-
"else io.StringIO('from setuptools import setup; setup()');"
15-
"code = f.read().replace('\\r\\n', '\\n');"
16-
"f.close();"
17-
"exec(compile(code, __file__, 'exec'))"
18-
)
6+
_SETUPTOOLS_SHIM = textwrap.dedent(
7+
"""
8+
exec(compile('''
9+
# This is <pip-setuptools-shim> -- a shim that pip uses to run setup.py
10+
#
11+
# - It imports setuptools before invoking setup.py, to enable projects that directly
12+
# import from `distutils.core` to work with newer packaging standards.
13+
# - Provides a clearer error message when setuptools is not installed.
14+
# - It sets `sys.argv[0]` to the underlying `setup.py`, when invoking `setup.py` so
15+
# setuptools doesn't think the script is `-c`. This avoids the following warning:
16+
# manifest_maker: standard file '-c' not found".
17+
# - It generates a shim setup.py, for handling setup.cfg-only projects.
18+
import os, sys, tokenize
19+
20+
try:
21+
import setuptools
22+
except ImportError as error:
23+
raise RuntimeError(
24+
"setuptools is not available in the build environment, but is required "
25+
"to use setup.py-based projects with pip."
26+
) from error
27+
28+
__file__ = {!r}
29+
sys.argv[0] = __file__
30+
31+
if os.path.exists(__file__):
32+
filename = __file__
33+
with tokenize.open(__file__) as f:
34+
setup_py_code = f.read()
35+
else:
36+
filename = "<auto-generated setuptools caller>"
37+
setup_py_code = "from setuptools import setup; setup()"
38+
39+
exec(compile(setup_py_code, filename, "exec"))
40+
''', "<pip-setuptools-shim>", "exec"))
41+
"""
42+
).rstrip()
1943

2044

2145
def make_setuptools_shim_args(

tests/unit/test_utils.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -943,11 +943,14 @@ def test_make_setuptools_shim_args() -> None:
943943
)
944944

945945
assert args[1:3] == ["-u", "-c"]
946-
# Spot-check key aspects of the command string.
947-
assert "sys.argv[0] = '/dir/path/setup.py'" in args[3]
948-
assert "__file__='/dir/path/setup.py'" in args[3]
949946
assert args[4:] == ["--some", "--option", "--no-user-cfg"]
950947

948+
shim = args[3]
949+
# Spot-check key aspects of the command string.
950+
assert "import setuptools" in shim
951+
assert "__file__ = '/dir/path/setup.py'" in args[3]
952+
assert "sys.argv[0] = __file__" in args[3]
953+
951954

952955
@pytest.mark.parametrize("global_options", [None, [], ["--some", "--option"]])
953956
def test_make_setuptools_shim_args__global_options(

0 commit comments

Comments
 (0)