Skip to content

Commit

Permalink
Patch for setup.py egg_info issue (#5760)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
matteius committed Jul 1, 2023
1 parent 6a55712 commit ee20f40
Show file tree
Hide file tree
Showing 8 changed files with 26 additions and 56 deletions.
1 change: 1 addition & 0 deletions news/5760.bugfix.rst
Original file line number Diff line number Diff line change
@@ -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 changes: 7 additions & 0 deletions pipenv/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,13 @@ def which(self, search, as_path=True):
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:
Expand Down
4 changes: 0 additions & 4 deletions pipenv/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
14 changes: 3 additions & 11 deletions pipenv/utils/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
3 changes: 3 additions & 0 deletions pipenv/utils/project.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os

from pipenv import exceptions
from pipenv.utils.dependencies import python_version
from pipenv.utils.pipfile import ensure_pipfile
Expand Down Expand Up @@ -77,3 +79,4 @@ def ensure_project(
skip_requirements=skip_requirements,
system=system,
)
os.environ["PIP_PYTHON_PATH"] = project.python
7 changes: 2 additions & 5 deletions pipenv/utils/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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,
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion pipenv/utils/virtualenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -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=""):
Expand Down
44 changes: 9 additions & 35 deletions pipenv/vendor/requirementslib/models/setup_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,6 @@

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."""
Expand All @@ -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",
Expand Down Expand Up @@ -1123,46 +1119,24 @@ 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)
target_cwd = os.path.dirname(os.path.abspath(script_path))
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


Expand Down

0 comments on commit ee20f40

Please sign in to comment.