From 08c14e9a908a821040434c6dcbf8147f13840646 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Sat, 26 Aug 2023 19:21:24 -0400 Subject: [PATCH] Fix for sys platform markers from Pipfile + fix for vcs subdirectory fragments (#5871) * Fix not considering sys platform markers from Pipfile * Fix for handling vcs subdirectory fragments * Add news fragments --- news/5870.bugfix.rst | 1 + news/5871.bugfix.rst | 1 + pipenv/project.py | 4 ++++ pipenv/utils/dependencies.py | 11 +++++++++-- pipenv/utils/locking.py | 2 ++ pipenv/utils/markers.py | 17 ++--------------- pipenv/utils/requirements.py | 29 +++++++++++++++++++---------- 7 files changed, 38 insertions(+), 27 deletions(-) create mode 100644 news/5870.bugfix.rst create mode 100644 news/5871.bugfix.rst diff --git a/news/5870.bugfix.rst b/news/5870.bugfix.rst new file mode 100644 index 0000000000..d6872c8de0 --- /dev/null +++ b/news/5870.bugfix.rst @@ -0,0 +1 @@ +Fix recent regressions with local/editable file installs. diff --git a/news/5871.bugfix.rst b/news/5871.bugfix.rst new file mode 100644 index 0000000000..ab0d0ea245 --- /dev/null +++ b/news/5871.bugfix.rst @@ -0,0 +1 @@ +Fixes the vcs subdirectory fragments regression; fixes sys_platform markers regression. diff --git a/pipenv/project.py b/pipenv/project.py index 15cc231ce0..3beee4c177 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -1146,6 +1146,10 @@ def generate_package_pipfile_entry(self, package, pip_line, category=None): vcs_parts = vcs_part.rsplit("@", 1) entry["ref"] = vcs_parts[1].split("#", 1)[0].strip() entry[vcs] = vcs_parts[0].strip() + + # Check and extract subdirectory fragment + if package.link.subdirectory_fragment: + entry["subdirectory"] = package.link.subdirectory_fragment break else: entry["version"] = specifier diff --git a/pipenv/utils/dependencies.py b/pipenv/utils/dependencies.py index cf311d25c1..2fff657513 100644 --- a/pipenv/utils/dependencies.py +++ b/pipenv/utils/dependencies.py @@ -246,6 +246,8 @@ def clean_resolved_dep(project, dep, is_top_level=False, current_entry=None): else: lockfile[vcs_type] = dep[vcs_type] lockfile["ref"] = dep.get("ref") + if "subdirectory" in dep: + lockfile["subdirectory"] = dep["subdirectory"] is_vcs_or_file = True if "editable" in dep: @@ -965,6 +967,9 @@ def install_req_from_pipfile(name, pipfile): if vcs: vcs_url = _pipfile[vcs] + subdirectory = _pipfile.get("subdirectory", "") + if subdirectory: + subdirectory = f"#subdirectory={subdirectory}" fallback_ref = "" if ("ssh://" in vcs_url and vcs_url.count("@") >= 2) or ( "ssh://" not in vcs_url and "@" in vcs_url @@ -977,9 +982,11 @@ def install_req_from_pipfile(name, pipfile): if not req_str.startswith(f"{vcs}+"): req_str = f"{vcs}+{req_str}" if f"{vcs}+file://" in req_str: - req_str = f"-e {req_str}#egg={name}{extras_str}" + req_str = ( + f"-e {req_str}#egg={name}{extras_str}{subdirectory.replace('#', '&')}" + ) else: - req_str = f"{name}{extras_str}@ {req_str}" + req_str = f"{name}{extras_str}@ {req_str}{subdirectory}" elif "path" in _pipfile: req_str = str(Path(_pipfile["path"]).as_posix()) elif "file" in _pipfile: diff --git a/pipenv/utils/locking.py b/pipenv/utils/locking.py index edad0ea400..a4c3ce53da 100644 --- a/pipenv/utils/locking.py +++ b/pipenv/utils/locking.py @@ -65,6 +65,8 @@ def format_requirement_for_lockfile( entry[vcs] = original_deps[name] else: entry[vcs] = req.link.url + if pipfile_entry.get("subdirectory"): + entry["subdirectory"] = pipfile_entry["subdirectory"] if req.req: entry["version"] = str(req.specifier) elif version: diff --git a/pipenv/utils/markers.py b/pipenv/utils/markers.py index 520360069b..d1e177b971 100644 --- a/pipenv/utils/markers.py +++ b/pipenv/utils/markers.py @@ -35,14 +35,6 @@ class PipenvMarkers(BaseModel): implementation_name: Optional[str] = None implementation_version: Optional[str] = None - @property - def line_part(self): - return " and ".join([f"{k} {v}" for k, v in self.dict().items() if v is not None]) - - @property - def pipfile_part(self): - return {"markers": self.as_line} - @classmethod def make_marker(cls, marker_string): try: @@ -53,13 +45,6 @@ def make_marker(cls, marker_string): ) return marker - @classmethod - def from_line(cls, line): - if ";" in line: - line = line.rsplit(";", 1)[1].strip() - marker = cls.make_marker(line) - return marker - @classmethod def from_pipfile(cls, name, pipfile): attr_fields = list(cls.__fields__) @@ -67,6 +52,8 @@ def from_pipfile(cls, name, pipfile): marker_strings = [f"{k} {pipfile[k]}" for k in found_keys] if pipfile.get("markers"): marker_strings.append(pipfile.get("markers")) + if pipfile.get("sys_platform"): + marker_strings.append(f"sys_platform '{pipfile['sys_platform']}'") markers = set() for marker in marker_strings: markers.add(marker) diff --git a/pipenv/utils/requirements.py b/pipenv/utils/requirements.py index 316f9714b3..3d82095862 100644 --- a/pipenv/utils/requirements.py +++ b/pipenv/utils/requirements.py @@ -151,6 +151,18 @@ def requirement_from_lockfile( return f"{package_name}=={package_info}" else: return package_name + + markers = ( + "; {}".format(package_info["markers"]) + if include_markers and "markers" in package_info and package_info["markers"] + else "" + ) + os_markers = ( + "; {}".format(package_info["os_markers"]) + if include_markers and "os_markers" in package_info and package_info["os_markers"] + else "" + ) + # Handling vcs repositories for vcs in VCS_LIST: if vcs in package_info: @@ -171,13 +183,16 @@ def requirement_from_lockfile( if "extras" in package_info else "" ) + subdirectory = package_info.get("subdirectory", "") include_vcs = "" if f"{vcs}+" in url else f"{vcs}+" egg_fragment = "" if "#egg=" in url else f"#egg={package_name}" ref_str = "" if not ref or f"@{ref}" in url else f"@{ref}" if is_editable_path(url) or "file://" in url: pip_line = f"-e {include_vcs}{url}{ref_str}{egg_fragment}{extras}" + pip_line += f"&subdirectory={subdirectory}" if subdirectory else "" else: pip_line = f"{package_name}{extras}@ {include_vcs}{url}{ref_str}" + pip_line += f"#subdirectory={subdirectory}" if subdirectory else "" return pip_line # Handling file-sourced packages for k in ["file", "path"]: @@ -187,6 +202,10 @@ def requirement_from_lockfile( if is_editable_path(path): line.append("-e") line.append(f"{package_info[k]}") + if os_markers: + line.append(os_markers) + if markers: + line.append(markers) pip_line = " ".join(line) return pip_line @@ -197,16 +216,6 @@ def requirement_from_lockfile( if include_hashes and "hashes" in package_info else "" ) - markers = ( - "; {}".format(package_info["markers"]) - if include_markers and "markers" in package_info and package_info["markers"] - else "" - ) - os_markers = ( - "; {}".format(package_info["os_markers"]) - if include_markers and "os_markers" in package_info and package_info["os_markers"] - else "" - ) extras = ( "[{}]".format(",".join(package_info.get("extras", []))) if "extras" in package_info