Skip to content

Commit ee20f40

Browse files
authored
Patch for setup.py egg_info issue (#5760)
* Set the PIP_PYTHON_PATH to be the environment python to patch issue where requirementslib is using system python (until better patch can be made). * Use the correct python for the environment * PR feedback * add news fragment.
1 parent 6a55712 commit ee20f40

File tree

8 files changed

+26
-56
lines changed

8 files changed

+26
-56
lines changed

news/5760.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix ``error: invalid command 'egg_info'`` edge case with requirementslib 3.0.0. It exposed pipenv resolver sometimes was using a different python than expected.

pipenv/project.py

+7
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,13 @@ def which(self, search, as_path=True):
11551155
result = str(result.path)
11561156
return result
11571157

1158+
@property
1159+
def python(self) -> str:
1160+
"""Path to the project python"""
1161+
from pipenv.utils.shell import project_python
1162+
1163+
return project_python(self)
1164+
11581165
def _which(self, command, location=None, allow_global=False):
11591166
if not allow_global and location is None:
11601167
if self.virtualenv_exists:

pipenv/resolver.py

-4
Original file line numberDiff line numberDiff line change
@@ -795,10 +795,6 @@ def _main(
795795
parse_only=False,
796796
category=None,
797797
):
798-
os.environ["PIPENV_REQUESTED_PYTHON_VERSION"] = ".".join(
799-
[str(s) for s in sys.version_info[:3]]
800-
)
801-
os.environ["PIP_PYTHON_PATH"] = str(sys.executable)
802798
if parse_only:
803799
parse_packages(
804800
packages,

pipenv/utils/dependencies.py

+3-11
Original file line numberDiff line numberDiff line change
@@ -53,25 +53,17 @@ def get_pipfile_category_using_lockfile_section(category):
5353

5454

5555
class HackedPythonVersion:
56-
"""A Beautiful hack, which allows us to tell pip which version of Python we're using."""
56+
"""A hack, which allows us to tell resolver which version of Python we're using."""
5757

58-
def __init__(self, python_version, python_path):
59-
self.python_version = python_version
58+
def __init__(self, python_path):
6059
self.python_path = python_path
6160

6261
def __enter__(self):
63-
# Only inject when the value is valid
64-
if self.python_version:
65-
os.environ["PIPENV_REQUESTED_PYTHON_VERSION"] = str(self.python_version)
6662
if self.python_path:
6763
os.environ["PIP_PYTHON_PATH"] = str(self.python_path)
6864

6965
def __exit__(self, *args):
70-
# Restore original Python version information.
71-
try:
72-
del os.environ["PIPENV_REQUESTED_PYTHON_VERSION"]
73-
except KeyError:
74-
pass
66+
pass
7567

7668

7769
def get_canonical_names(packages):

pipenv/utils/project.py

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
from pipenv import exceptions
24
from pipenv.utils.dependencies import python_version
35
from pipenv.utils.pipfile import ensure_pipfile
@@ -77,3 +79,4 @@ def ensure_project(
7779
skip_requirements=skip_requirements,
7880
system=system,
7981
)
82+
os.environ["PIP_PYTHON_PATH"] = project.python

pipenv/utils/resolver.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -1156,10 +1156,8 @@ def resolve_deps(
11561156
"""
11571157
index_lookup = {}
11581158
markers_lookup = {}
1159-
python_path = which("python", allow_global=allow_global)
11601159
if not os.environ.get("PIP_SRC"):
11611160
os.environ["PIP_SRC"] = project.virtualenv_src_location
1162-
backup_python_path = sys.executable
11631161
results = []
11641162
resolver = None
11651163
if not deps:
@@ -1168,7 +1166,7 @@ def resolve_deps(
11681166
req_dir = req_dir if req_dir else os.environ.get("req_dir", None)
11691167
if not req_dir:
11701168
req_dir = create_tracked_tempdir(prefix="pipenv-", suffix="-requirements")
1171-
with HackedPythonVersion(python_version=python, python_path=python_path):
1169+
with HackedPythonVersion(python_path=project.python):
11721170
try:
11731171
results, hashes, markers_lookup, resolver, skipped = actually_resolve_deps(
11741172
deps,
@@ -1187,8 +1185,7 @@ def resolve_deps(
11871185
# Second (last-resort) attempt:
11881186
if results is None:
11891187
with HackedPythonVersion(
1190-
python_version=".".join([str(s) for s in sys.version_info[:3]]),
1191-
python_path=backup_python_path,
1188+
python_path=project.python,
11921189
):
11931190
try:
11941191
# Attempt to resolve again, with different Python version information,

pipenv/utils/virtualenv.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def cleanup_virtualenv(project, bare=True):
217217

218218
def ensure_python(project, python=None):
219219
# Runtime import is necessary due to the possibility that the environments module may have been reloaded.
220-
if project.s.PIPENV_PYTHON and python is False:
220+
if project.s.PIPENV_PYTHON and not python:
221221
python = project.s.PIPENV_PYTHON
222222

223223
def abort(msg=""):

pipenv/vendor/requirementslib/models/setup_info.py

+9-35
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,6 @@
5858

5959
CACHE_DIR = os.environ.get("PIPENV_CACHE_DIR", user_cache_dir("pipenv"))
6060

61-
# The following are necessary for people who like to use "if __name__" conditionals
62-
# in their setup.py scripts
63-
_setup_stop_after = None
64-
_setup_distribution = None
65-
6661

6762
def pep517_subprocess_runner(cmd, cwd=None, extra_environ=None) -> None:
6863
"""The default method of calling the wrapper subprocess."""
@@ -75,8 +70,9 @@ def pep517_subprocess_runner(cmd, cwd=None, extra_environ=None) -> None:
7570

7671
class BuildEnv(envbuild.BuildEnvironment):
7772
def pip_install(self, reqs):
73+
python = os.environ.get("PIP_PYTHON_PATH", sys.executable)
7874
cmd = [
79-
sys.executable,
75+
python,
8076
"-m",
8177
"pip",
8278
"install",
@@ -1123,46 +1119,24 @@ def run_setup(script_path, egg_base=None):
11231119
:return: The metadata dictionary
11241120
:rtype: Dict[Any, Any]
11251121
"""
1122+
from pathlib import Path
11261123

11271124
if not os.path.exists(script_path):
11281125
raise FileNotFoundError(script_path)
11291126
target_cwd = os.path.dirname(os.path.abspath(script_path))
11301127
if egg_base is None:
11311128
egg_base = os.path.join(target_cwd, "reqlib-metadata")
11321129
with temp_path(), cd(target_cwd):
1133-
# This is for you, Hynek
1134-
# see https://github.com/hynek/environ_config/blob/69b1c8a/setup.py
11351130
args = ["egg_info"]
11361131
if egg_base:
11371132
args += ["--egg-base", egg_base]
1138-
script_name = os.path.basename(script_path)
1139-
g = {"__file__": script_name, "__name__": "__main__"}
1140-
sys.path.insert(0, target_cwd)
1141-
1142-
save_argv = sys.argv.copy()
1143-
try:
1144-
global _setup_distribution, _setup_stop_after
1145-
_setup_stop_after = "run"
1146-
sys.argv[0] = script_name
1147-
sys.argv[1:] = args
1148-
with open(script_name, "rb") as f:
1149-
contents = f.read().replace(rb"\r\n", rb"\n")
1150-
exec(contents, g)
1151-
# We couldn't import everything needed to run setup
1152-
except Exception:
1153-
python = os.environ.get("PIP_PYTHON_PATH", sys.executable)
11541133

1155-
sp.run(
1156-
[python, "setup.py"] + args,
1157-
cwd=target_cwd,
1158-
stdout=sp.PIPE,
1159-
stderr=sp.PIPE,
1160-
)
1161-
finally:
1162-
_setup_stop_after = None
1163-
sys.argv = save_argv
1164-
_setup_distribution = get_metadata(egg_base, metadata_type="egg")
1165-
dist = _setup_distribution
1134+
python = os.environ.get("PIP_PYTHON_PATH", sys.executable)
1135+
sp.run(
1136+
[python, "setup.py"] + args,
1137+
capture_output=True,
1138+
)
1139+
dist = get_metadata(egg_base, metadata_type="egg")
11661140
return dist
11671141

11681142

0 commit comments

Comments
 (0)