Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attempt to fix the local/editable file installs #5870

Merged
merged 4 commits into from
Aug 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions pipenv/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,8 @@ def get_hashes_from_remote_index_urls(self, ireq, source):
)
return None

def get_file_hash(self, session, link):
@staticmethod
def get_file_hash(session, link):
h = hashlib.new(FAVORITE_HASH)
err.print(f"Downloading file {link.filename} to obtain hash...")
with open_file(link.url, session) as fp:
Expand Down Expand Up @@ -1126,7 +1127,7 @@ def generate_package_pipfile_entry(self, package, pip_line, category=None):
if extras:
entry["extras"] = list(extras)
if path_specifier:
entry["file"] = unquote(path_specifier)
entry["file"] = unquote(str(path_specifier))
elif vcs_specifier:
for vcs in VCS_LIST:
if vcs in package.link.scheme:
Expand Down
27 changes: 8 additions & 19 deletions pipenv/utils/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from pathlib import Path
from tempfile import NamedTemporaryFile, TemporaryDirectory
from typing import Any, AnyStr, Dict, List, Mapping, Optional, Sequence, Union
from urllib.parse import urljoin, urlparse, urlsplit, urlunsplit
from urllib.parse import urlparse, urlsplit, urlunsplit

from pipenv.patched.pip._internal.models.link import Link
from pipenv.patched.pip._internal.network.download import Downloader
Expand Down Expand Up @@ -639,15 +639,12 @@ def find_package_name_from_directory(directory):
def determine_path_specifier(package: InstallRequirement):
if package.link:
if package.link.scheme in ["http", "https"]:
path_specifier = package.link.url_without_fragment
return path_specifier
return package.link.url_without_fragment
if package.link.scheme == "file":
try:
path_specifier = os.path.relpath(package.link.file_path)
return Path(package.link.file_path).relative_to(Path.cwd()).as_posix()
except ValueError:
# If os.path.relpath() fails, use the absolute path instead
path_specifier = os.path.abspath(package.link.file_path)
return path_specifier
return Path(package.link.file_path).as_posix()


def determine_vcs_specifier(package: InstallRequirement):
Expand Down Expand Up @@ -900,13 +897,7 @@ def expansive_install_req_from_line(
if expand_env:
name = expand_env_variables(name)

if os.path.isfile(name) or os.path.isdir(name):
if not name.startswith("file:"):
# Make sure the path is absolute and properly formatted as a file: URL
absolute_path = os.path.abspath(name)
name = urljoin("file:", absolute_path)
name = "file:" + name

if editable or os.path.isdir(name):
return install_req_from_editable(name, line_source)

vcs_part = name
Expand All @@ -926,9 +917,7 @@ def expansive_install_req_from_line(
constraint=constraint,
user_supplied=user_supplied,
)
if editable:
return install_req_from_editable(name, line_source)
if urlparse(name).scheme in ("http", "https", "file"):
if urlparse(name).scheme in ("http", "https", "file") or os.path.isfile(name):
parts = parse_req_from_line(name, line_source)
else:
# It's a requirement
Expand Down Expand Up @@ -992,9 +981,9 @@ def install_req_from_pipfile(name, pipfile):
else:
req_str = f"{name}{extras_str}@ {req_str}"
elif "path" in _pipfile:
req_str = f"{_pipfile['path']}{extras_str}"
req_str = str(Path(_pipfile["path"]).as_posix())
elif "file" in _pipfile:
req_str = f"{_pipfile['file']}{extras_str}"
req_str = str(Path(_pipfile["file"]).as_posix())
else:
# We ensure version contains an operator. Default to equals (==)
_pipfile["version"] = version = get_version(pipfile)
Expand Down
15 changes: 5 additions & 10 deletions pipenv/utils/funktools.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import time
import warnings
from functools import partial
from itertools import count, islice, tee
from itertools import count, islice
from typing import Any, Iterable

DIRECTORY_CLEANUP_TIMEOUT = 1.0
Expand Down Expand Up @@ -62,18 +62,13 @@ def unnest(elem: Iterable) -> Any:
"""

if isinstance(elem, Iterable) and not isinstance(elem, str):
elem, target = tee(elem, 2)
else:
target = elem
if not target or not _is_iterable(target):
yield target
else:
for el in target:
for el in elem:
if isinstance(el, Iterable) and not isinstance(el, str):
el, el_copy = tee(el, 2)
yield from unnest(el_copy)
yield from unnest(el)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes total sense to use recursion here. I wonder how it was not done before.

else:
yield el
else:
yield elem


def dedup(iterable: Iterable) -> Iterable:
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test_install_uri.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def test_install_local_vcs_not_in_lockfile(pipenv_instance_pypi):
def test_get_vcs_refs(pipenv_instance_private_pypi):
with pipenv_instance_private_pypi() as p:
c = p.pipenv(
"install -e git+https://github.com/benjaminp/six.git@1.9.0"
"install -e git+https://github.com/benjaminp/six.git@1.9.0#egg=six"
)
assert c.returncode == 0
assert "six" in p.pipfile["packages"]
Expand Down