Skip to content

Commit

Permalink
Fix get_hashes logic for unhashable requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
jcushman committed May 10, 2019
1 parent e6bdfa7 commit d755c60
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 15 deletions.
2 changes: 2 additions & 0 deletions piptools/_compat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
get_installed_distributions,
install_req_from_editable,
install_req_from_line,
is_dir_url,
is_file_url,
is_vcs_url,
parse_requirements,
path_to_url,
stdlib_pkgs,
Expand Down
2 changes: 2 additions & 0 deletions piptools/_compat/pip_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def do_import(module_path, subimport=None, old_path=None):
user_cache_dir = do_import("utils.appdirs", "user_cache_dir")
FAVORITE_HASH = do_import("utils.hashes", "FAVORITE_HASH")
is_file_url = do_import("download", "is_file_url")
is_dir_url = do_import("download", "is_dir_url")
is_vcs_url = do_import("download", "is_vcs_url")
path_to_url = do_import("download", "path_to_url")
url_to_path = do_import("download", "url_to_path")
PackageFinder = do_import("index", "PackageFinder")
Expand Down
36 changes: 23 additions & 13 deletions piptools/repositories/pypi.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
TemporaryDirectory,
Wheel,
contextlib,
is_dir_url,
is_file_url,
is_vcs_url,
path_to_url,
url_to_path,
)
Expand Down Expand Up @@ -282,21 +284,29 @@ def get_dependencies(self, ireq):
def get_hashes(self, ireq):
"""
Given an InstallRequirement, return a set of hashes that represent all
of the files for a given requirement. Editable requirements return an
of the files for a given requirement. Unhashable requirements return an
empty set. Unpinned requirements raise a TypeError.
"""
if ireq.editable:
return set()

if is_url_requirement(ireq):
# url requirements may have been previously downloaded and cached
# locally by self.resolve_reqs()
cached_path = os.path.join(self._download_dir, ireq.link.filename)
if os.path.exists(cached_path):
cached_link = Link(path_to_url(cached_path))
else:
cached_link = ireq.link
return {self._get_file_hash(cached_link)}

if ireq.link:
link = ireq.link

if is_vcs_url(link) or (is_file_url(link) and is_dir_url(link)):
# Return empty set for unhashable requirements.
# Unhashable logic modeled on pip's
# RequirementPreparer.prepare_linked_requirement
return set()

if is_url_requirement(ireq):
# Directly hash URL requirements.
# URL requirements may have been previously downloaded and cached
# locally by self.resolve_reqs()
cached_path = os.path.join(self._download_dir, link.filename)
if os.path.exists(cached_path):
cached_link = Link(path_to_url(cached_path))
else:
cached_link = link
return {self._get_file_hash(cached_link)}

if not is_pinned_requirement(ireq):
raise TypeError("Expected pinned requirement, got {}".format(ireq))
Expand Down
7 changes: 5 additions & 2 deletions tests/test_cli_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,12 +335,15 @@ def test_locally_available_editable_package_is_not_archived_in_cache_dir(
),
],
)
def test_url_package(runner, line, dependency, rewritten_line):
@mark.parametrize(("generate_hashes",), [(True,), (False,)])
def test_url_package(runner, line, dependency, rewritten_line, generate_hashes):
if rewritten_line is None:
rewritten_line = line
with open("requirements.in", "w") as req_in:
req_in.write(line)
out = runner.invoke(cli, ["-n", "--rebuild"])
out = runner.invoke(
cli, ["-n", "--rebuild"] + (["--generate-hashes"] if generate_hashes else [])
)
assert out.exit_code == 0
assert rewritten_line in out.output
assert dependency in out.output
Expand Down

0 comments on commit d755c60

Please sign in to comment.