Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a912b13
Add optional param from_dir to format_requirement
AndydeCleyre Jun 30, 2022
c90d969
Reuse fragment_string to simplify _build_direct_reference_best_efforts
AndydeCleyre Jun 30, 2022
11ffba6
Add working_dir context manager and corresponding test
AndydeCleyre Jun 30, 2022
65c489c
Add abs_ireq for normalizing ireqs, and related tests
AndydeCleyre Jun 30, 2022
987d90b
Update test to expect and accept more Windows file URIs
AndydeCleyre Jun 30, 2022
6713b60
Add writer test for annotation accuracy regarding source ireqs
AndydeCleyre Jun 30, 2022
0f2cf1d
Add optional param from_dir to _comes_from_as_string
AndydeCleyre Jun 30, 2022
f2350e1
Add optional from_dir param to parse_requirements
AndydeCleyre Jun 30, 2022
8edf988
Add flag for compile: --write-relative-to-output
AndydeCleyre Jun 30, 2022
bc00d62
Add test_local_editable_vcs_package
AndydeCleyre Jun 30, 2022
a9784a1
Add flag to sync: --read-relative-to-input
AndydeCleyre Jun 30, 2022
996f21c
Absolute-ize src_file paths and more safely determine output file paths
AndydeCleyre Jun 30, 2022
a92729f
Exit earlier when no output file is specified for multiple input files
AndydeCleyre Jun 30, 2022
f46a2d5
Add flag for compile: --read-relative-to-input
AndydeCleyre Jun 30, 2022
7e55700
Make annotation req file paths relative to the output file
AndydeCleyre Jun 30, 2022
4004f96
Add test_annotation_relative_paths for #1107
AndydeCleyre Jun 30, 2022
7ef7b98
Add test_format_requirement_annotation_impossible_relative_path
AndydeCleyre Jun 30, 2022
48d05fd
Reinject any lost url fragments during parse_requirements
AndydeCleyre Jun 30, 2022
6084450
Include extras syntax in direct references we construct
AndydeCleyre Jun 30, 2022
8117c1d
Avoid choking on a relative path without scheme prefix, with fragment
AndydeCleyre Jun 30, 2022
ece9e14
When copying ireqs, copy extras from a newly provided link
AndydeCleyre Jun 30, 2022
3345abc
Improve consistency of output regarding fragments and extras
AndydeCleyre Jun 30, 2022
eee3e8a
Add test_url_package_with_extras and fix it for backtracking
AndydeCleyre Jun 30, 2022
4ed481d
Remove fragment_string parameter omit_extras
AndydeCleyre Jun 30, 2022
2d27659
Add test_local_file_uri_with_extras
AndydeCleyre Jun 30, 2022
88eb70d
Add test_local_file_path_package for non-URI paths
AndydeCleyre Jun 30, 2022
6468e37
Use consistently canonicalized ireq name when writing direct reference
AndydeCleyre Jun 30, 2022
aa3ee0f
Construct relative req lines to match what pip install understands
AndydeCleyre Jun 30, 2022
f853ba9
Merge branch 'master' into feature/relpaths-post-6.8.0
ssbarnea Oct 5, 2022
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
Prev Previous commit
Next Next commit
Add abs_ireq for normalizing ireqs, and related tests
Tests:

- abs_ireq_preserves_source_ireqs
- format_requirement_impossible_relative_path_becomes_absolute (Windows-only)

Also, ensure copy_install_requirement preserves our custom attributes.
  • Loading branch information
AndydeCleyre committed Oct 3, 2022
commit 65c489c6fd2344ccb80bb89bbce6bc03cec53858
54 changes: 53 additions & 1 deletion piptools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import itertools
import json
import os
import platform
import re
import shlex
from contextlib import contextmanager
Expand All @@ -23,10 +24,11 @@

import click
from click.utils import LazyFile
from pip._internal.models.link import Link
from pip._internal.req import InstallRequirement
from pip._internal.req.constructors import install_req_from_line
from pip._internal.utils.misc import redact_auth_from_url
from pip._internal.utils.urls import path_to_url
from pip._internal.utils.urls import path_to_url, url_to_path
from pip._internal.vcs import is_url
from pip._vendor.packaging.markers import Marker
from pip._vendor.packaging.specifiers import SpecifierSet
Expand Down Expand Up @@ -367,6 +369,52 @@ def working_dir(folder: Optional[str]) -> Iterator[None]:
os.chdir(original_dir)


def abs_ireq(
ireq: InstallRequirement, from_dir: Optional[str] = None
) -> InstallRequirement:
"""
Return the given InstallRequirement if its source isn't a relative path;
Otherwise, return a new one with the relative path rewritten as absolute.

In this case, an extra attribute is added: _was_relative,
which is always True when present at all.
"""
# We check ireq.link.scheme rather than ireq.link.is_file,
# to also match <vcs>+file schemes
if ireq.link is None or not ireq.link.scheme.endswith("file"):
return ireq

naive_path = ireq.local_file_path or ireq.link.path
if platform.system() == "Windows":
naive_path = naive_path.lstrip("/")

with working_dir(from_dir):
url = path_to_url(naive_path).replace("%40", "@")

if (
os.path.normpath(naive_path).lower()
== os.path.normpath(url_to_path(url)).lower()
):
return ireq

abs_url = f"{url}{fragment_string(ireq)}"
if "+" in ireq.link.scheme:
abs_url = f"{ireq.link.scheme.split('+')[0]}+{abs_url}"

abs_link = Link(
url=abs_url,
comes_from=ireq.link.comes_from,
requires_python=ireq.link.requires_python,
yanked_reason=ireq.link.yanked_reason,
cache_link_parsing=ireq.link.cache_link_parsing,
)

a_ireq = copy_install_requirement(ireq, link=abs_link)
a_ireq._was_relative = True

return a_ireq


def get_compile_command(click_ctx: click.Context) -> str:
"""
Returns a normalized compile command depending on cli context.
Expand Down Expand Up @@ -540,4 +588,8 @@ def copy_install_requirement(
template.original_link if original_link is None else original_link
)

for custom_attr in ("_source_ireqs", "_was_relative"):
if hasattr(template, custom_attr):
setattr(ireq, custom_attr, getattr(template, custom_attr))

return ireq
25 changes: 25 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import operator
import os
import platform
import shlex
import sys

Expand All @@ -10,6 +11,7 @@

from piptools.scripts.compile import cli as compile_cli
from piptools.utils import (
abs_ireq,
as_tuple,
dedup,
drop_extras,
Expand Down Expand Up @@ -145,6 +147,15 @@ def test_format_requirement_editable_local_path(from_editable):
assert format_requirement(ireq) == "-e file:///home/user/package"


@pytest.mark.skipif(
platform.system() != "Windows",
reason="Relative paths can only be impossible on Windows",
)
def test_format_requirement_impossible_relative_path_becomes_absolute(from_line):
ireq = abs_ireq(from_line("file:./vendor/package.zip"), ".")
assert format_requirement(ireq, from_dir="z:") == ireq.link.url


def test_format_requirement_ireq_with_hashes(from_line):
ireq = from_line("pytz==2017.2")
ireq_hashes = [
Expand Down Expand Up @@ -560,3 +571,17 @@ def test_working_dir(tmpdir_cwd, folder_name, use_abspath):
assert os.getcwd() == expected_within

assert os.getcwd() == tmpdir_cwd


def test_local_abs_ireq_preserves_source_ireqs(from_line):
ireq1 = from_line("testone==1.2")
ireq1.comes_from = "xyz"

ireq2 = from_line("testtwo==2.4")
ireq2.comes_from = "lmno"

ireq3 = from_line("file:testwithsrcs")
ireq3._source_ireqs = [ireq1, ireq2]
ireq3 = abs_ireq(ireq3, os.getcwd())

assert ireq3._source_ireqs == [ireq1, ireq2]