Skip to content

Commit

Permalink
Improve our setuptools shim
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
pradyunsg committed Dec 10, 2021
1 parent eb04d61 commit dc217bb
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 17 deletions.
52 changes: 38 additions & 14 deletions src/pip/_internal/utils/setuptools_build.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,45 @@
import sys
import textwrap
from typing import List, Optional, Sequence

# Shim to wrap setup.py invocation with setuptools
#
# We set sys.argv[0] to the path to the underlying setup.py file so
# setuptools / distutils don't take the path to the setup.py to be "-c" when
# invoking via the shim. This avoids e.g. the following manifest_maker
# warning: "warning: manifest_maker: standard file '-c' not found".
_SETUPTOOLS_SHIM = (
"import io, os, sys, setuptools, tokenize; sys.argv[0] = {0!r}; __file__={0!r};"
"f = getattr(tokenize, 'open', open)(__file__) "
"if os.path.exists(__file__) "
"else io.StringIO('from setuptools import setup; setup()');"
"code = f.read().replace('\\r\\n', '\\n');"
"f.close();"
"exec(compile(code, __file__, 'exec'))"
)
_SETUPTOOLS_SHIM = textwrap.dedent(
"""
exec(compile('''
# This is <pip-setuptools-shim> -- a shim that pip uses to run setup.py
#
# - It imports setuptools before invoking setup.py, to enable projects that directly
# import from `distutils.core` to work with newer packaging standards.
# - Provides a clearer error message when setuptools is not installed.
# - It sets `sys.argv[0]` to the underlying `setup.py`, when invoking `setup.py` so
# setuptools doesn't think the script is `-c`. This avoids the following warning:
# manifest_maker: standard file '-c' not found".
# - It generates a shim setup.py, for handling setup.cfg-only projects.
import os, sys, tokenize
try:
import setuptools
except ImportError as error:
raise RuntimeError(
"setuptools is not available in the build environment, but is required "
"to use setup.py-based projects with pip."
) from error
__file__ = {!r}
sys.argv[0] = __file__
if os.path.exists(__file__):
filename = __file__
with tokenize.open(__file__) as f:
setup_py_code = f.read()
else:
filename = "<auto-generated setuptools caller>"
setup_py_code = "from setuptools import setup; setup()"
exec(compile(setup_py_code, filename, "exec"))
''', "<pip-setuptools-shim>", "exec"))
"""
).rstrip()


def make_setuptools_shim_args(
Expand Down
9 changes: 6 additions & 3 deletions tests/unit/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -943,11 +943,14 @@ def test_make_setuptools_shim_args() -> None:
)

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

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


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

0 comments on commit dc217bb

Please sign in to comment.