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.
This commit is contained in:
Matt Davis
2023-07-01 01:42:00 -04:00
committed by GitHub
parent 6a55712651
commit ee20f405cd
8 changed files with 26 additions and 56 deletions
+1
View File
@@ -0,0 +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.
+7
View File
@@ -1155,6 +1155,13 @@ class Project:
result = str(result.path)
return result
@property
def python(self) -> str:
"""Path to the project python"""
from pipenv.utils.shell import project_python
return project_python(self)
def _which(self, command, location=None, allow_global=False):
if not allow_global and location is None:
if self.virtualenv_exists:
-4
View File
@@ -795,10 +795,6 @@ def _main(
parse_only=False,
category=None,
):
os.environ["PIPENV_REQUESTED_PYTHON_VERSION"] = ".".join(
[str(s) for s in sys.version_info[:3]]
)
os.environ["PIP_PYTHON_PATH"] = str(sys.executable)
if parse_only:
parse_packages(
packages,
+3 -11
View File
@@ -53,25 +53,17 @@ def get_pipfile_category_using_lockfile_section(category):
class HackedPythonVersion:
"""A Beautiful hack, which allows us to tell pip which version of Python we're using."""
"""A hack, which allows us to tell resolver which version of Python we're using."""
def __init__(self, python_version, python_path):
self.python_version = python_version
def __init__(self, python_path):
self.python_path = python_path
def __enter__(self):
# Only inject when the value is valid
if self.python_version:
os.environ["PIPENV_REQUESTED_PYTHON_VERSION"] = str(self.python_version)
if self.python_path:
os.environ["PIP_PYTHON_PATH"] = str(self.python_path)
def __exit__(self, *args):
# Restore original Python version information.
try:
del os.environ["PIPENV_REQUESTED_PYTHON_VERSION"]
except KeyError:
pass
pass
def get_canonical_names(packages):
+3
View File
@@ -1,3 +1,5 @@
import os
from pipenv import exceptions
from pipenv.utils.dependencies import python_version
from pipenv.utils.pipfile import ensure_pipfile
@@ -77,3 +79,4 @@ def ensure_project(
skip_requirements=skip_requirements,
system=system,
)
os.environ["PIP_PYTHON_PATH"] = project.python
+2 -5
View File
@@ -1156,10 +1156,8 @@ def resolve_deps(
"""
index_lookup = {}
markers_lookup = {}
python_path = which("python", allow_global=allow_global)
if not os.environ.get("PIP_SRC"):
os.environ["PIP_SRC"] = project.virtualenv_src_location
backup_python_path = sys.executable
results = []
resolver = None
if not deps:
@@ -1168,7 +1166,7 @@ def resolve_deps(
req_dir = req_dir if req_dir else os.environ.get("req_dir", None)
if not req_dir:
req_dir = create_tracked_tempdir(prefix="pipenv-", suffix="-requirements")
with HackedPythonVersion(python_version=python, python_path=python_path):
with HackedPythonVersion(python_path=project.python):
try:
results, hashes, markers_lookup, resolver, skipped = actually_resolve_deps(
deps,
@@ -1187,8 +1185,7 @@ def resolve_deps(
# Second (last-resort) attempt:
if results is None:
with HackedPythonVersion(
python_version=".".join([str(s) for s in sys.version_info[:3]]),
python_path=backup_python_path,
python_path=project.python,
):
try:
# Attempt to resolve again, with different Python version information,
+1 -1
View File
@@ -217,7 +217,7 @@ def cleanup_virtualenv(project, bare=True):
def ensure_python(project, python=None):
# Runtime import is necessary due to the possibility that the environments module may have been reloaded.
if project.s.PIPENV_PYTHON and python is False:
if project.s.PIPENV_PYTHON and not python:
python = project.s.PIPENV_PYTHON
def abort(msg=""):
+9 -35
View File
@@ -58,11 +58,6 @@ from .utils import (
CACHE_DIR = os.environ.get("PIPENV_CACHE_DIR", user_cache_dir("pipenv"))
# The following are necessary for people who like to use "if __name__" conditionals
# in their setup.py scripts
_setup_stop_after = None
_setup_distribution = None
def pep517_subprocess_runner(cmd, cwd=None, extra_environ=None) -> None:
"""The default method of calling the wrapper subprocess."""
@@ -75,8 +70,9 @@ def pep517_subprocess_runner(cmd, cwd=None, extra_environ=None) -> None:
class BuildEnv(envbuild.BuildEnvironment):
def pip_install(self, reqs):
python = os.environ.get("PIP_PYTHON_PATH", sys.executable)
cmd = [
sys.executable,
python,
"-m",
"pip",
"install",
@@ -1123,6 +1119,7 @@ def run_setup(script_path, egg_base=None):
:return: The metadata dictionary
:rtype: Dict[Any, Any]
"""
from pathlib import Path
if not os.path.exists(script_path):
raise FileNotFoundError(script_path)
@@ -1130,39 +1127,16 @@ def run_setup(script_path, egg_base=None):
if egg_base is None:
egg_base = os.path.join(target_cwd, "reqlib-metadata")
with temp_path(), cd(target_cwd):
# This is for you, Hynek
# see https://github.com/hynek/environ_config/blob/69b1c8a/setup.py
args = ["egg_info"]
if egg_base:
args += ["--egg-base", egg_base]
script_name = os.path.basename(script_path)
g = {"__file__": script_name, "__name__": "__main__"}
sys.path.insert(0, target_cwd)
save_argv = sys.argv.copy()
try:
global _setup_distribution, _setup_stop_after
_setup_stop_after = "run"
sys.argv[0] = script_name
sys.argv[1:] = args
with open(script_name, "rb") as f:
contents = f.read().replace(rb"\r\n", rb"\n")
exec(contents, g)
# We couldn't import everything needed to run setup
except Exception:
python = os.environ.get("PIP_PYTHON_PATH", sys.executable)
sp.run(
[python, "setup.py"] + args,
cwd=target_cwd,
stdout=sp.PIPE,
stderr=sp.PIPE,
)
finally:
_setup_stop_after = None
sys.argv = save_argv
_setup_distribution = get_metadata(egg_base, metadata_type="egg")
dist = _setup_distribution
python = os.environ.get("PIP_PYTHON_PATH", sys.executable)
sp.run(
[python, "setup.py"] + args,
capture_output=True,
)
dist = get_metadata(egg_base, metadata_type="egg")
return dist