From f623e8edae09343d4ed9018a8c97610031b2790b Mon Sep 17 00:00:00 2001 From: chopeen Date: Sun, 5 Feb 2023 12:44:25 +0000 Subject: [PATCH 01/12] refactor: extract function _get_archive_info --- src/poetry/installation/executor.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index dd72729a66d..33f296d2e10 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -799,20 +799,14 @@ def _create_git_url_reference(self, package: Package) -> dict[str, Any]: return reference def _create_url_url_reference(self, package: Package) -> dict[str, Any]: - archive_info = {} - - if package.name in self._hashes: - archive_info["hash"] = self._hashes[package.name] + archive_info = self._get_archive_info(package) reference = {"url": package.source_url, "archive_info": archive_info} return reference def _create_file_url_reference(self, package: Package) -> dict[str, Any]: - archive_info = {} - - if package.name in self._hashes: - archive_info["hash"] = self._hashes[package.name] + archive_info = self._get_archive_info(package) assert package.source_url is not None return { @@ -831,3 +825,11 @@ def _create_directory_url_reference(self, package: Package) -> dict[str, Any]: "url": Path(package.source_url).as_uri(), "dir_info": dir_info, } + + def _get_archive_info(self, package: Package) -> dict[str, Any]: + archive_info = {} + + if package.name in self._hashes: + archive_info["hash"] = self._hashes[package.name] + + return archive_info From 539c09624603719e008deaf40172f0605d2cab92 Mon Sep 17 00:00:00 2001 From: chopeen Date: Sun, 5 Feb 2023 12:46:36 +0000 Subject: [PATCH 02/12] refactor: construct dictionary in return stmt --- src/poetry/installation/executor.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index 33f296d2e10..4afd812fe89 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -801,9 +801,10 @@ def _create_git_url_reference(self, package: Package) -> dict[str, Any]: def _create_url_url_reference(self, package: Package) -> dict[str, Any]: archive_info = self._get_archive_info(package) - reference = {"url": package.source_url, "archive_info": archive_info} - - return reference + return { + "url": package.source_url, + "archive_info": archive_info + } def _create_file_url_reference(self, package: Package) -> dict[str, Any]: archive_info = self._get_archive_info(package) From 528c7703a9dd99ed79f55c214591c7cb183c2e05 Mon Sep 17 00:00:00 2001 From: chopeen Date: Sun, 5 Feb 2023 12:56:11 +0000 Subject: [PATCH 03/12] feat: populate `hashes` key in `archive_info` - https://packaging.python.org/en/latest/specifications/direct-url/ --- src/poetry/installation/executor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index 4afd812fe89..021a7755cf1 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -831,6 +831,7 @@ def _get_archive_info(self, package: Package) -> dict[str, Any]: archive_info = {} if package.name in self._hashes: - archive_info["hash"] = self._hashes[package.name] + algorithm, value = self._hashes[package.name].split(":") + archive_info["hashes"] = {algorithm: value} return archive_info From 8ea8b7557874512ac00f015fefcf2d6d8c67e433 Mon Sep 17 00:00:00 2001 From: chopeen Date: Sun, 5 Feb 2023 12:57:45 +0000 Subject: [PATCH 04/12] feat: keep `hash` in `archive_info` for backwards compatibility, use `=` as separator - https://packaging.python.org/en/latest/specifications/direct-url/ --- src/poetry/installation/executor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index 021a7755cf1..3d9aa512be9 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -833,5 +833,6 @@ def _get_archive_info(self, package: Package) -> dict[str, Any]: if package.name in self._hashes: algorithm, value = self._hashes[package.name].split(":") archive_info["hashes"] = {algorithm: value} + archive_info["hash"] = f"{algorithm}={value}" return archive_info From 2bdd7dcde4a8df13f544d28e41e649789a2b373c Mon Sep 17 00:00:00 2001 From: chopeen Date: Sun, 5 Feb 2023 15:37:49 +0000 Subject: [PATCH 05/12] tests: verify `archive_info` contains hashes --- tests/installation/test_executor.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/installation/test_executor.py b/tests/installation/test_executor.py index 6b8de09546b..4bdd53d211a 100644 --- a/tests/installation/test_executor.py +++ b/tests/installation/test_executor.py @@ -585,11 +585,25 @@ def test_executor_should_write_pep610_url_references_for_urls( source_type="url", source_url="https://files.pythonhosted.org/demo-0.1.0-py2.py3-none-any.whl", ) + # Set package.files so the executor will attempt to hash the package + package.files = [ + { + "file": "demo-0.1.0-py2.py3-none-any.whl", + "hash": "sha256:70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a", # noqa: E501 + } + ] executor = Executor(tmp_venv, pool, config, io) executor.execute([Install(package)]) + expected_url_reference = { + "archive_info": { + "hashes": {"sha256": "70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a"}, + "hash": "sha256=70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a", + }, + "url": package.source_url + } verify_installed_distribution( - tmp_venv, package, {"archive_info": {}, "url": package.source_url} + tmp_venv, package, expected_url_reference ) From 928380b83782ace1b04315773593fdcd4689e1dd Mon Sep 17 00:00:00 2001 From: chopeen Date: Sun, 5 Feb 2023 15:50:03 +0000 Subject: [PATCH 06/12] chore: remove deprecated key `hash` --- src/poetry/installation/executor.py | 1 - tests/installation/test_executor.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index 3d9aa512be9..021a7755cf1 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -833,6 +833,5 @@ def _get_archive_info(self, package: Package) -> dict[str, Any]: if package.name in self._hashes: algorithm, value = self._hashes[package.name].split(":") archive_info["hashes"] = {algorithm: value} - archive_info["hash"] = f"{algorithm}={value}" return archive_info diff --git a/tests/installation/test_executor.py b/tests/installation/test_executor.py index 4bdd53d211a..20dc6cc791b 100644 --- a/tests/installation/test_executor.py +++ b/tests/installation/test_executor.py @@ -598,7 +598,6 @@ def test_executor_should_write_pep610_url_references_for_urls( expected_url_reference = { "archive_info": { "hashes": {"sha256": "70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a"}, - "hash": "sha256=70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a", }, "url": package.source_url } From 9b0628ce32e0b0094f03b10d117d3fcb40e73fbd Mon Sep 17 00:00:00 2001 From: chopeen Date: Sun, 5 Feb 2023 15:56:39 +0000 Subject: [PATCH 07/12] chore: apply pre-commit fixes --- src/poetry/installation/executor.py | 7 ++----- tests/installation/test_executor.py | 12 +++++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index 021a7755cf1..39ef4611e44 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -801,10 +801,7 @@ def _create_git_url_reference(self, package: Package) -> dict[str, Any]: def _create_url_url_reference(self, package: Package) -> dict[str, Any]: archive_info = self._get_archive_info(package) - return { - "url": package.source_url, - "archive_info": archive_info - } + return {"url": package.source_url, "archive_info": archive_info} def _create_file_url_reference(self, package: Package) -> dict[str, Any]: archive_info = self._get_archive_info(package) @@ -826,7 +823,7 @@ def _create_directory_url_reference(self, package: Package) -> dict[str, Any]: "url": Path(package.source_url).as_uri(), "dir_info": dir_info, } - + def _get_archive_info(self, package: Package) -> dict[str, Any]: archive_info = {} diff --git a/tests/installation/test_executor.py b/tests/installation/test_executor.py index 20dc6cc791b..7356a60a4d3 100644 --- a/tests/installation/test_executor.py +++ b/tests/installation/test_executor.py @@ -597,13 +597,15 @@ def test_executor_should_write_pep610_url_references_for_urls( executor.execute([Install(package)]) expected_url_reference = { "archive_info": { - "hashes": {"sha256": "70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a"}, + "hashes": { + "sha256": ( + "70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a" + ) + }, }, - "url": package.source_url + "url": package.source_url, } - verify_installed_distribution( - tmp_venv, package, expected_url_reference - ) + verify_installed_distribution(tmp_venv, package, expected_url_reference) def test_executor_should_write_pep610_url_references_for_git( From 69e2f639c9e3e16d7800175db305629034222451 Mon Sep 17 00:00:00 2001 From: chopeen Date: Mon, 6 Feb 2023 09:21:09 +0100 Subject: [PATCH 08/12] docs: add a docstring for _get_archive_info --- src/poetry/installation/executor.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index 463285332e9..8dfc6ace8d1 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -900,6 +900,13 @@ def _create_directory_url_reference(self, package: Package) -> dict[str, Any]: } def _get_archive_info(self, package: Package) -> dict[str, Any]: + """ + Create dictionary `archive_info` for file `direct_url.json`. + + Specification: https://packaging.python.org/en/latest/specifications/direct-url/ (it supersedes PEP 610) + + :param package: This must be a poetry package instance. + """ archive_info = {} if package.name in self._hashes: From 81639525569f6904a39f90ab3d651c9f638db053 Mon Sep 17 00:00:00 2001 From: chopeen Date: Mon, 6 Feb 2023 10:24:21 +0100 Subject: [PATCH 09/12] chore: apply pre-commit fixes --- src/poetry/installation/executor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index 8dfc6ace8d1..556fcb33d31 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -903,7 +903,8 @@ def _get_archive_info(self, package: Package) -> dict[str, Any]: """ Create dictionary `archive_info` for file `direct_url.json`. - Specification: https://packaging.python.org/en/latest/specifications/direct-url/ (it supersedes PEP 610) + Specification: https://packaging.python.org/en/latest/specifications/direct-url + (it supersedes PEP 610) :param package: This must be a poetry package instance. """ From 9c15c55eaf378d6f9f86f6e645726426929bc6b4 Mon Sep 17 00:00:00 2001 From: chopeen Date: Mon, 6 Feb 2023 10:59:41 +0100 Subject: [PATCH 10/12] feat: populate _hashes when installing package of type "file" --- src/poetry/installation/executor.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index 556fcb33d31..5aff69b77c2 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -572,6 +572,10 @@ def _prepare_archive(self, operation: Install | Update) -> Path: if not Path(package.source_url).is_absolute() and package.root_dir: archive = package.root_dir / archive + if package.files and archive.name in {f["file"] for f in package.files}: + archive_hash = self._validate_archive_hash(archive, package) + self._hashes[package.name] = archive_hash + return self._chef.prepare(archive, editable=package.develop) def _prepare_directory_archive(self, operation: Install | Update) -> Path: From a9c18449091ff102b83cc2ff7a5da7a8940ed71b Mon Sep 17 00:00:00 2001 From: chopeen Date: Mon, 6 Feb 2023 11:00:34 +0100 Subject: [PATCH 11/12] tests: verify `archive_info` contains hashes for source_type="file" --- tests/installation/test_executor.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tests/installation/test_executor.py b/tests/installation/test_executor.py index c1efe11ac83..9ede4a63c5f 100644 --- a/tests/installation/test_executor.py +++ b/tests/installation/test_executor.py @@ -622,12 +622,27 @@ def test_executor_should_write_pep610_url_references_for_files( .resolve() ) package = Package("demo", "0.1.0", source_type="file", source_url=url.as_posix()) + # Set package.files so the executor will attempt to hash the package + package.files = [ + { + "file": "demo-0.1.0-py2.py3-none-any.whl", + "hash": "sha256:70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a", # noqa: E501 + } + ] executor = Executor(tmp_venv, pool, config, io) executor.execute([Install(package)]) - verify_installed_distribution( - tmp_venv, package, {"archive_info": {}, "url": url.as_uri()} - ) + expected_url_reference = { + "archive_info": { + "hashes": { + "sha256": ( + "70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a" + ) + }, + }, + "url": url.as_uri(), + } + verify_installed_distribution(tmp_venv, package, expected_url_reference) def test_executor_should_write_pep610_url_references_for_directories( From beb936f91ce5804e3a37c790fc2959bfdc9caa11 Mon Sep 17 00:00:00 2001 From: chopeen Date: Mon, 6 Feb 2023 11:29:44 +0100 Subject: [PATCH 12/12] refactor: extract function _populate_hashes_dict --- src/poetry/installation/executor.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index 5aff69b77c2..a4ca1238cee 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -572,9 +572,7 @@ def _prepare_archive(self, operation: Install | Update) -> Path: if not Path(package.source_url).is_absolute() and package.root_dir: archive = package.root_dir / archive - if package.files and archive.name in {f["file"] for f in package.files}: - archive_hash = self._validate_archive_hash(archive, package) - self._hashes[package.name] = archive_hash + self._populate_hashes_dict(archive, package) return self._chef.prepare(archive, editable=package.develop) @@ -738,13 +736,15 @@ def _download_link(self, operation: Install | Update, link: Link) -> Path: archive = self._chef.prepare(archive, output_dir=output_dir) + self._populate_hashes_dict(archive, package) + + return archive + + def _populate_hashes_dict(self, archive: Path, package: Package) -> None: if package.files and archive.name in {f["file"] for f in package.files}: archive_hash = self._validate_archive_hash(archive, package) - self._hashes[package.name] = archive_hash - return archive - @staticmethod def _validate_archive_hash(archive: Path, package: Package) -> str: archive_hash: str = "sha256:" + get_file_hash(archive)