From 2968e5ffc4f45ac3213e23f88df26db96a29d994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Wed, 13 Oct 2021 19:10:58 +0100 Subject: [PATCH] Include schemes with records, when calling `finalise_installation` (#75) --- src/installer/_core.py | 11 ++- src/installer/destinations.py | 6 +- src/installer/utils.py | 4 +- tests/test_core.py | 122 +++++++++++++++++++++++----------- tests/test_destinations.py | 44 +++++++++--- tests/test_records.py | 27 ++++++-- tests/test_utils.py | 3 +- 7 files changed, 149 insertions(+), 68 deletions(-) diff --git a/src/installer/_core.py b/src/installer/_core.py index 6e7ced41..b73587c4 100644 --- a/src/installer/_core.py +++ b/src/installer/_core.py @@ -8,13 +8,12 @@ from installer.exceptions import InvalidWheelSource from installer.records import RecordEntry from installer.sources import WheelSource -from installer.utils import SCHEME_NAMES, parse_entrypoints, parse_metadata_file +from installer.utils import SCHEME_NAMES, Scheme, parse_entrypoints, parse_metadata_file if TYPE_CHECKING: from typing import Dict, Tuple from installer._compat.typing import Binary, FSPath - from installer.utils import Scheme __all__ = ["install"] @@ -94,7 +93,7 @@ def install(source, destination, additional_metadata): attr=attr, section=section, ) - written_records.append(record) + written_records.append((Scheme("scripts"), record)) # Write all the files from the wheel. for record_elements, stream in source.get_contents(): @@ -115,7 +114,7 @@ def install(source, destination, additional_metadata): path=destination_path, stream=stream, ) - written_records.append(record) + written_records.append((scheme, record)) # Write all the installation-specific metadata for filename, contents in additional_metadata.items(): @@ -127,9 +126,9 @@ def install(source, destination, additional_metadata): path=path, stream=other_stream, ) - written_records.append(record) + written_records.append((root_scheme, record)) - written_records.append(RecordEntry(record_file_path, None, None)) + written_records.append((root_scheme, RecordEntry(record_file_path, None, None))) destination.finalize_installation( scheme=root_scheme, record_file_path=record_file_path, diff --git a/src/installer/destinations.py b/src/installer/destinations.py index e00bb261..6d726b53 100644 --- a/src/installer/destinations.py +++ b/src/installer/destinations.py @@ -15,7 +15,7 @@ ) if TYPE_CHECKING: - from typing import BinaryIO, Dict, Iterable + from typing import BinaryIO, Dict, Iterable, Tuple from installer._compat.typing import FSPath, Text from installer.scripts import LauncherKind, ScriptSection @@ -65,7 +65,7 @@ def write_file(self, scheme, path, stream): raise NotImplementedError def finalize_installation(self, scheme, record_file_path, records): - # type: (Scheme, FSPath, Iterable[RecordEntry]) -> None + # type: (Scheme, FSPath, Iterable[Tuple[Scheme, RecordEntry]]) -> None """Finalize installation, after all the files are written. Handles (re)writing of the ``RECORD`` file. @@ -180,7 +180,7 @@ def write_script(self, name, module, attr, section): return entry def finalize_installation(self, scheme, record_file_path, records): - # type: (Scheme, FSPath, Iterable[RecordEntry]) -> None + # type: (Scheme, FSPath, Iterable[Tuple[Scheme, RecordEntry]]) -> None """Finalize installation, by writing the ``RECORD`` file. :param scheme: scheme to write the ``RECORD`` file in diff --git a/src/installer/utils.py b/src/installer/utils.py index 2fd64ee4..4b76bd8d 100644 --- a/src/installer/utils.py +++ b/src/installer/utils.py @@ -169,13 +169,13 @@ def fix_shebang(stream, interpreter): def construct_record_file(records): - # type: (Iterable[RecordEntry]) -> BinaryIO + # type: (Iterable[Tuple[Scheme, RecordEntry]]) -> BinaryIO """Construct a RECORD file given some records. The original stream should be closed by the caller. """ stream = io.BytesIO() - for record in records: + for scheme, record in records: stream.write(str(record).encode("utf-8") + b"\n") stream.seek(0) return stream diff --git a/tests/test_core.py b/tests/test_core.py index c53788f9..5ac58ce4 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -205,16 +205,28 @@ def main(): scheme="purelib", record_file_path="fancy-1.0.0.dist-info/RECORD", records=[ - ("fancy", "fancy", "main", "console"), - ("fancy-gui", "fancy", "main", "gui"), - ("fancy/__init__.py", "purelib", 0), - ("fancy/__main__.py", "purelib", 0), - ("fancy-1.0.0.dist-info/METADATA", "purelib", 0), - ("fancy-1.0.0.dist-info/WHEEL", "purelib", 0), - ("fancy-1.0.0.dist-info/entry_points.txt", "purelib", 0), - ("fancy-1.0.0.dist-info/top_level.txt", "purelib", 0), - ("fancy-1.0.0.dist-info/fun_file.txt", "purelib", 0), - RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None), + ("scripts", ("fancy", "fancy", "main", "console")), + ("scripts", ("fancy-gui", "fancy", "main", "gui")), + ("purelib", ("fancy/__init__.py", "purelib", 0)), + ("purelib", ("fancy/__main__.py", "purelib", 0)), + ("purelib", ("fancy-1.0.0.dist-info/METADATA", "purelib", 0)), + ("purelib", ("fancy-1.0.0.dist-info/WHEEL", "purelib", 0)), + ( + "purelib", + ("fancy-1.0.0.dist-info/entry_points.txt", "purelib", 0), + ), + ( + "purelib", + ("fancy-1.0.0.dist-info/top_level.txt", "purelib", 0), + ), + ( + "purelib", + ("fancy-1.0.0.dist-info/fun_file.txt", "purelib", 0), + ), + ( + "purelib", + RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None), + ), ], ), ] @@ -305,13 +317,22 @@ def main(): scheme="purelib", record_file_path="fancy-1.0.0.dist-info/RECORD", records=[ - ("fancy/__init__.py", "purelib", 0), - ("fancy/__main__.py", "purelib", 0), - ("fancy-1.0.0.dist-info/METADATA", "purelib", 0), - ("fancy-1.0.0.dist-info/WHEEL", "purelib", 0), - ("fancy-1.0.0.dist-info/top_level.txt", "purelib", 0), - ("fancy-1.0.0.dist-info/fun_file.txt", "purelib", 0), - RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None), + ("purelib", ("fancy/__init__.py", "purelib", 0)), + ("purelib", ("fancy/__main__.py", "purelib", 0)), + ("purelib", ("fancy-1.0.0.dist-info/METADATA", "purelib", 0)), + ("purelib", ("fancy-1.0.0.dist-info/WHEEL", "purelib", 0)), + ( + "purelib", + ("fancy-1.0.0.dist-info/top_level.txt", "purelib", 0), + ), + ( + "purelib", + ("fancy-1.0.0.dist-info/fun_file.txt", "purelib", 0), + ), + ( + "purelib", + RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None), + ), ], ), ] @@ -426,16 +447,28 @@ def main(): scheme="platlib", record_file_path="fancy-1.0.0.dist-info/RECORD", records=[ - ("fancy", "fancy", "main", "console"), - ("fancy-gui", "fancy", "main", "gui"), - ("fancy/__init__.py", "platlib", 0), - ("fancy/__main__.py", "platlib", 0), - ("fancy-1.0.0.dist-info/METADATA", "platlib", 0), - ("fancy-1.0.0.dist-info/WHEEL", "platlib", 0), - ("fancy-1.0.0.dist-info/entry_points.txt", "platlib", 0), - ("fancy-1.0.0.dist-info/top_level.txt", "platlib", 0), - ("fancy-1.0.0.dist-info/fun_file.txt", "platlib", 0), - RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None), + ("scripts", ("fancy", "fancy", "main", "console")), + ("scripts", ("fancy-gui", "fancy", "main", "gui")), + ("platlib", ("fancy/__init__.py", "platlib", 0)), + ("platlib", ("fancy/__main__.py", "platlib", 0)), + ("platlib", ("fancy-1.0.0.dist-info/METADATA", "platlib", 0)), + ("platlib", ("fancy-1.0.0.dist-info/WHEEL", "platlib", 0)), + ( + "platlib", + ("fancy-1.0.0.dist-info/entry_points.txt", "platlib", 0), + ), + ( + "platlib", + ("fancy-1.0.0.dist-info/top_level.txt", "platlib", 0), + ), + ( + "platlib", + ("fancy-1.0.0.dist-info/fun_file.txt", "platlib", 0), + ), + ( + "platlib", + RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None), + ), ], ), ] @@ -691,19 +724,28 @@ def test_handles_data_properly(self, mock_destination): scheme="purelib", record_file_path="fancy-1.0.0.dist-info/RECORD", records=[ - ("fancy", "fancy", "main", "console"), - ("fancy-gui", "fancy", "main", "gui"), - ("fancy/data.py", "data", 0), - ("fancy/headers.py", "headers", 0), - ("fancy/platlib.py", "platlib", 0), - ("fancy/purelib.py", "purelib", 0), - ("fancy/scripts.py", "scripts", 0), - ("fancy/__init__.py", "purelib", 0), - ("fancy-1.0.0.dist-info/METADATA", "purelib", 0), - ("fancy-1.0.0.dist-info/WHEEL", "purelib", 0), - ("fancy-1.0.0.dist-info/entry_points.txt", "purelib", 0), - ("fancy-1.0.0.dist-info/top_level.txt", "purelib", 0), - RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None), + ("scripts", ("fancy", "fancy", "main", "console")), + ("scripts", ("fancy-gui", "fancy", "main", "gui")), + ("data", ("fancy/data.py", "data", 0)), + ("headers", ("fancy/headers.py", "headers", 0)), + ("platlib", ("fancy/platlib.py", "platlib", 0)), + ("purelib", ("fancy/purelib.py", "purelib", 0)), + ("scripts", ("fancy/scripts.py", "scripts", 0)), + ("purelib", ("fancy/__init__.py", "purelib", 0)), + ("purelib", ("fancy-1.0.0.dist-info/METADATA", "purelib", 0)), + ("purelib", ("fancy-1.0.0.dist-info/WHEEL", "purelib", 0)), + ( + "purelib", + ("fancy-1.0.0.dist-info/entry_points.txt", "purelib", 0), + ), + ( + "purelib", + ("fancy-1.0.0.dist-info/top_level.txt", "purelib", 0), + ), + ( + "purelib", + RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None), + ), ], ), ] diff --git a/tests/test_destinations.py b/tests/test_destinations.py index d9d9fc03..fde2df34 100644 --- a/tests/test_destinations.py +++ b/tests/test_destinations.py @@ -95,17 +95,43 @@ def test_write_script(self, destination): def test_finalize_write_record(self, destination): records = [ - destination.write_file("data", "my_data1.bin", io.BytesIO(b"my data 1")), - destination.write_file("data", "my_data2.bin", io.BytesIO(b"my data 2")), - destination.write_file("data", "my_data3.bin", io.BytesIO(b"my data 3")), - destination.write_file("scripts", "my_script", io.BytesIO(b"my script")), - destination.write_file( - "scripts", "my_script2", io.BytesIO(b"#!python\nmy script") + ( + "data", + destination.write_file( + "data", "my_data1.bin", io.BytesIO(b"my data 1") + ), + ), + ( + "data", + destination.write_file( + "data", "my_data2.bin", io.BytesIO(b"my data 2") + ), ), - destination.write_script( - "my_entrypoint", "my_module", "my_function", "console" + ( + "data", + destination.write_file( + "data", "my_data3.bin", io.BytesIO(b"my data 3") + ), + ), + ( + "scripts", + destination.write_file( + "scripts", "my_script", io.BytesIO(b"my script") + ), + ), + ( + "scripts", + destination.write_file( + "scripts", "my_script2", io.BytesIO(b"#!python\nmy script") + ), + ), + ( + "scripts", + destination.write_script( + "my_entrypoint", "my_module", "my_function", "console" + ), ), - RecordEntry("RECORD", None, None), + ("purelib", RecordEntry("RECORD", None, None)), ] destination.finalize_installation("purelib", "RECORD", records) diff --git a/tests/test_records.py b/tests/test_records.py index 4ec4da7d..0c88ae6f 100644 --- a/tests/test_records.py +++ b/tests/test_records.py @@ -34,26 +34,31 @@ def record_input(request): SAMPLE_RECORDS = [ ( + "purelib", ("test1.py", "sha256=Y0sCextp4SQtQNU-MSs7SsdxD1W-gfKJtUlEbvZ3i-4", 6), b"test1\n", True, ), ( + "purelib", ("test2.py", "sha256=fW_Xd08Nh2JNptzxbQ09EEwxkedx--LznIau1LK_Gg8", 6), b"test2\n", True, ), ( + "purelib", ("test3.py", "sha256=qwPDTx7OCCEf4qgDn9ZCQZmz9de1X_E7ETSzZHdsRcU", 6), b"test3\n", True, ), ( + "purelib", ("test4.py", "sha256=Y0sCextp4SQtQNU-MSs7SsdxD1W-gfKJtUlEbvZ3i-4", 7), b"test1\n", False, ), ( + "purelib", ( "test5.py", "sha256=Y0sCextp4SQtQNU-MSs7SsdxD1W-gfKJtUlEbvZ3i-4", @@ -62,7 +67,7 @@ def record_input(request): b"test1\n", True, ), - (("test6.py", None, None), b"test1\n", True), + ("purelib", ("test6.py", None, None), b"test1\n", True), ] @@ -100,8 +105,12 @@ def test_invalid_elements(self, path, hash_, size, caused_by): def test_valid_elements(self, path, hash_, size): RecordEntry.from_elements(path, hash_, size) - @pytest.mark.parametrize(("elements", "data", "passes_validation"), SAMPLE_RECORDS) - def test_populates_attributes_correctly(self, elements, data, passes_validation): + @pytest.mark.parametrize( + ("scheme", "elements", "data", "passes_validation"), SAMPLE_RECORDS + ) + def test_populates_attributes_correctly( + self, scheme, elements, data, passes_validation + ): path, hash_string, size = elements record = RecordEntry.from_elements(path, hash_string, size) @@ -114,13 +123,17 @@ def test_populates_attributes_correctly(self, elements, data, passes_validation) assert record.hash_.name == "sha256" assert record.hash_.value == hash_string[len("sha256=") :] - @pytest.mark.parametrize(("elements", "data", "passes_validation"), SAMPLE_RECORDS) - def test_validation(self, elements, data, passes_validation): + @pytest.mark.parametrize( + ("scheme", "elements", "data", "passes_validation"), SAMPLE_RECORDS + ) + def test_validation(self, scheme, elements, data, passes_validation): record = RecordEntry.from_elements(*elements) assert record.validate(data) == passes_validation - @pytest.mark.parametrize(("elements", "data", "passes_validation"), SAMPLE_RECORDS) - def test_string_representation(self, elements, data, passes_validation): + @pytest.mark.parametrize( + ("scheme", "elements", "data", "passes_validation"), SAMPLE_RECORDS + ) + def test_string_representation(self, scheme, elements, data, passes_validation): record = RecordEntry.from_elements(*elements) expected_string_value = ",".join( diff --git a/tests/test_utils.py b/tests/test_utils.py index 21d0b9b3..c3ff67bd 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -156,7 +156,8 @@ def test_keep_data(self, data): class TestConstructRecord: def test_construct(self): records = [ - RecordEntry.from_elements(*elements) for elements, _, _ in SAMPLE_RECORDS + (scheme, RecordEntry.from_elements(*elements)) + for scheme, elements, _, _ in SAMPLE_RECORDS ] assert construct_record_file(records).read() == ( b"test1.py,sha256=Y0sCextp4SQtQNU-MSs7SsdxD1W-gfKJtUlEbvZ3i-4,6\n"