From 453cd3aa4ae986bccc1c6a59b84f6f94f63b56f4 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Sun, 12 Feb 2023 17:31:10 +0000 Subject: [PATCH 1/3] fix for duplicate lines in wheel RECORD, prefer pathlib --- src/poetry/core/json/__init__.py | 10 ++-- src/poetry/core/masonry/builders/wheel.py | 36 +++++++------- src/poetry/core/version/markers.py | 2 + tests/masonry/builders/test_complete.py | 57 ++++++++++++++++------- 4 files changed, 64 insertions(+), 41 deletions(-) diff --git a/src/poetry/core/json/__init__.py b/src/poetry/core/json/__init__.py index c46a8d264..f620de198 100644 --- a/src/poetry/core/json/__init__.py +++ b/src/poetry/core/json/__init__.py @@ -1,12 +1,12 @@ from __future__ import annotations import json -import os +from pathlib import Path from typing import Any -SCHEMA_DIR = os.path.join(os.path.dirname(__file__), "schemas") +SCHEMA_DIR = Path(__file__).parent / "schemas" class ValidationError(ValueError): @@ -14,12 +14,12 @@ class ValidationError(ValueError): def validate_object(obj: dict[str, Any], schema_name: str) -> list[str]: - schema_file = os.path.join(SCHEMA_DIR, f"{schema_name}.json") + schema_file = SCHEMA_DIR / f"{schema_name}.json" - if not os.path.exists(schema_file): + if not schema_file.exists(): raise ValueError(f"Schema {schema_name} does not exist.") - with open(schema_file, encoding="utf-8") as f: + with schema_file.open(encoding="utf-8") as f: schema = json.loads(f.read()) from jsonschema import Draft7Validator diff --git a/src/poetry/core/masonry/builders/wheel.py b/src/poetry/core/masonry/builders/wheel.py index 8d704cbdc..5e649fb63 100644 --- a/src/poetry/core/masonry/builders/wheel.py +++ b/src/poetry/core/masonry/builders/wheel.py @@ -163,9 +163,9 @@ def _build(self, wheel: zipfile.ZipFile) -> None: # we assume that the build script will build and copy the files # directly. # That way they will be picked up when adding files to the wheel. - current_path = os.getcwd() + current_path = Path.cwd() try: - os.chdir(str(self._path)) + os.chdir(self._path) self._run_build_script(self._package.build_script) finally: os.chdir(current_path) @@ -173,9 +173,9 @@ def _build(self, wheel: zipfile.ZipFile) -> None: with SdistBuilder(poetry=self._poetry).setup_py() as setup: # We need to place ourselves in the temporary # directory in order to build the package - current_path = os.getcwd() + current_path = Path.cwd() try: - os.chdir(str(self._path)) + os.chdir(self._path) self._run_build_command(setup) finally: os.chdir(current_path) @@ -194,9 +194,9 @@ def _build(self, wheel: zipfile.ZipFile) -> None: if pkg.is_dir() or self.is_excluded(pkg): continue - rel_path = str(pkg.relative_to(lib)) + rel_path = pkg.relative_to(lib) - if rel_path in wheel.namelist(): + if rel_path.as_posix() in wheel.namelist(): continue logger.debug(f"Adding: {rel_path}") @@ -210,7 +210,7 @@ def _copy_file_scripts(self, wheel: zipfile.ZipFile) -> None: self._add_file( wheel, abs_path, - Path.joinpath(Path(self.wheel_data_folder), "scripts", abs_path.name), + Path(self.wheel_data_folder) / "scripts" / abs_path.name, ) def _run_build_command(self, setup: Path) -> None: @@ -268,7 +268,7 @@ def prepare_metadata(self, metadata_directory: Path) -> Path: continue dest = dist_info / license_file.relative_to(self._path) - os.makedirs(dest.parent, exist_ok=True) + dest.parent.mkdir(parents=True, exist_ok=True) shutil.copy(license_file, dest) return dist_info @@ -345,19 +345,15 @@ def tag(self) -> str: def _add_file( self, wheel: zipfile.ZipFile, - full_path: Path | str, - rel_path: Path | str, + full_path: Path, + rel_path: Path, ) -> None: - full_path, rel_path = str(full_path), str(rel_path) - if os.sep != "/": - # We always want to have /-separated paths in the zip file and in - # RECORD - rel_path = rel_path.replace(os.sep, "/") - - zinfo = zipfile.ZipInfo(rel_path) + # We always want to have /-separated paths in the zip file and in RECORD + rel_path_name = rel_path.as_posix() + zinfo = zipfile.ZipInfo(rel_path_name) # Normalize permission bits to either 755 (executable) or 644 - st_mode = os.stat(full_path).st_mode + st_mode = full_path.stat().st_mode new_mode = normalize_file_permissions(st_mode) zinfo.external_attr = (new_mode & 0xFFFF) << 16 # Unix attributes @@ -375,10 +371,10 @@ def _add_file( src.seek(0) wheel.writestr(zinfo, src.read(), compress_type=zipfile.ZIP_DEFLATED) - size = os.stat(full_path).st_size + size = full_path.stat().st_size hash_digest = urlsafe_b64encode(hashsum.digest()).decode("ascii").rstrip("=") - self._records.append((rel_path, hash_digest, size)) + self._records.append((rel_path_name, hash_digest, size)) @contextlib.contextmanager def _write_to_zip( diff --git a/src/poetry/core/version/markers.py b/src/poetry/core/version/markers.py index a9f67d87a..f4485fa57 100644 --- a/src/poetry/core/version/markers.py +++ b/src/poetry/core/version/markers.py @@ -830,8 +830,10 @@ def dnf(marker: BaseMarker) -> BaseMarker: return MarkerUnion.of( *[MultiMarker.of(*c) for c in itertools.product(*sub_marker_lists)] ) + if isinstance(marker, MarkerUnion): return MarkerUnion.of(*[dnf(m) for m in marker.markers]) + return marker diff --git a/tests/masonry/builders/test_complete.py b/tests/masonry/builders/test_complete.py index 7a5aebdea..5827e6758 100644 --- a/tests/masonry/builders/test_complete.py +++ b/tests/masonry/builders/test_complete.py @@ -1,5 +1,6 @@ from __future__ import annotations +import csv import os import platform import re @@ -47,7 +48,7 @@ def clear_samples_dist() -> None: or platform.python_implementation().lower() == "pypy", reason="Disable test on Windows for Python <=3.6 and for PyPy", ) -def test_wheel_c_extension() -> None: +def test_wheel_c_extension() -> None: # NOSONAR module_path = fixtures_dir / "extended" builder = Builder(Factory().create_poetry(module_path)) builder.build(fmt="all") @@ -89,12 +90,19 @@ def test_wheel_c_extension() -> None: is not None ) - records = zip.read("extended-0.1.dist-info/RECORD").decode() + record = zip.read("extended-0.1.dist-info/RECORD").decode() + records = csv.reader(record.splitlines()) + record_files = [row[0] for row in records] - assert re.search(r"\s+extended/extended.*\.(so|pyd)", records) is not None + assert re.search(r"\s+extended/extended.*\.(so|pyd)", record) is not None finally: zip.close() + # Files in RECORD should match files in wheel. + zip_files = sorted(zip.namelist()) + assert zip_files == sorted(record_files) + assert len(set(record_files)) == len(record_files) + @pytest.mark.skipif( sys.platform == "win32" @@ -102,7 +110,7 @@ def test_wheel_c_extension() -> None: or platform.python_implementation().lower() == "pypy", reason="Disable test on Windows for Python <=3.6 and for PyPy", ) -def test_wheel_c_extension_with_no_setup() -> None: +def test_wheel_c_extension_with_no_setup() -> None: # NOSONAR module_path = fixtures_dir / "extended_with_no_setup" builder = Builder(Factory().create_poetry(module_path)) builder.build(fmt="all") @@ -144,12 +152,19 @@ def test_wheel_c_extension_with_no_setup() -> None: is not None ) - records = zip.read("extended-0.1.dist-info/RECORD").decode() + record = zip.read("extended-0.1.dist-info/RECORD").decode() + records = csv.reader(record.splitlines()) + record_files = [row[0] for row in records] - assert re.search(r"\s+extended/extended.*\.(so|pyd)", records) is not None + assert re.search(r"\s+extended/extended.*\.(so|pyd)", record) is not None finally: zip.close() + # Files in RECORD should match files in wheel. + zip_files = sorted(zip.namelist()) + assert zip_files == sorted(record_files) + assert len(set(record_files)) == len(record_files) + @pytest.mark.skipif( sys.platform == "win32" @@ -157,7 +172,7 @@ def test_wheel_c_extension_with_no_setup() -> None: or platform.python_implementation().lower() == "pypy", reason="Disable test on Windows for Python <=3.6 and for PyPy", ) -def test_wheel_c_extension_src_layout() -> None: +def test_wheel_c_extension_src_layout() -> None: # NOSONAR module_path = fixtures_dir / "src_extended" builder = Builder(Factory().create_poetry(module_path)) builder.build(fmt="all") @@ -199,12 +214,19 @@ def test_wheel_c_extension_src_layout() -> None: is not None ) - records = zip.read("extended-0.1.dist-info/RECORD").decode() + record = zip.read("extended-0.1.dist-info/RECORD").decode() + records = csv.reader(record.splitlines()) + record_files = [row[0] for row in records] - assert re.search(r"\s+extended/extended.*\.(so|pyd)", records) is not None + assert re.search(r"\s+extended/extended.*\.(so|pyd)", record) is not None finally: zip.close() + # Files in RECORD should match files in wheel. + zip_files = sorted(zip.namelist()) + assert zip_files == sorted(record_files) + assert len(set(record_files)) == len(record_files) + def test_complete() -> None: module_path = fixtures_dir / "complete" @@ -297,20 +319,23 @@ def test_complete() -> None: # vary per operating systems and Python versions. # So instead of 1:1 assertion, let's do a bit clunkier one: - expected_records = [ + actual_files = [row[0] for row in csv.reader(actual_records.splitlines())] + expected_files = [ + "my_package-1.2.3.data/scripts/script.sh", + "my_package-1.2.3.dist-info/LICENSE", + "my_package-1.2.3.dist-info/METADATA", + "my_package-1.2.3.dist-info/RECORD", + "my_package-1.2.3.dist-info/WHEEL", + "my_package-1.2.3.dist-info/entry_points.txt", "my_package/__init__.py", "my_package/data1/test.json", "my_package/sub_pkg1/__init__.py", "my_package/sub_pkg2/__init__.py", "my_package/sub_pkg2/data2/data.json", - "my_package-1.2.3.dist-info/entry_points.txt", - "my_package-1.2.3.dist-info/LICENSE", - "my_package-1.2.3.dist-info/WHEEL", - "my_package-1.2.3.dist-info/METADATA", + "my_package/sub_pkg3/foo.py", ] - for expected_record in expected_records: - assert expected_record in actual_records + assert sorted(expected_files) == sorted(actual_files) finally: zip.close() From 7976f68ecc11c0f9e136425395c63a8495b208c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 11 Mar 2023 10:06:58 +0100 Subject: [PATCH 2/3] refactor(tests): parametrization instead of duplication, remove skip for Python 3.6 --- tests/masonry/builders/test_complete.py | 361 ++++-------------------- 1 file changed, 60 insertions(+), 301 deletions(-) diff --git a/tests/masonry/builders/test_complete.py b/tests/masonry/builders/test_complete.py index 5827e6758..0d2b656e5 100644 --- a/tests/masonry/builders/test_complete.py +++ b/tests/masonry/builders/test_complete.py @@ -43,102 +43,39 @@ def clear_samples_dist() -> None: @pytest.mark.skipif( - sys.platform == "win32" - and sys.version_info <= (3, 6) - or platform.python_implementation().lower() == "pypy", - reason="Disable test on Windows for Python <=3.6 and for PyPy", + platform.python_implementation().lower() == "pypy", reason="Disable test for PyPy" ) -def test_wheel_c_extension() -> None: # NOSONAR - module_path = fixtures_dir / "extended" - builder = Builder(Factory().create_poetry(module_path)) - builder.build(fmt="all") - - sdist = fixtures_dir / "extended" / "dist" / "extended-0.1.tar.gz" - - assert sdist.exists() - - with tarfile.open(str(sdist), "r") as tar: - assert "extended-0.1/build.py" in tar.getnames() - assert "extended-0.1/extended/extended.c" in tar.getnames() - - whl = list((module_path / "dist").glob("extended-0.1-cp*-cp*-*.whl"))[0] - - assert whl.exists() - - zip = zipfile.ZipFile(str(whl)) - - has_compiled_extension = False - for name in zip.namelist(): - if name.startswith("extended/extended") and name.endswith((".so", ".pyd")): - has_compiled_extension = True - - assert has_compiled_extension - - try: - wheel_data = zip.read("extended-0.1.dist-info/WHEEL").decode() - - assert ( - re.match( - f"""(?m)^\ -Wheel-Version: 1.0 -Generator: poetry-core {__version__} -Root-Is-Purelib: false -Tag: cp[23]_?\\d+-cp[23]_?\\d+m?u?-.+ -$""", - wheel_data, - ) - is not None - ) - - record = zip.read("extended-0.1.dist-info/RECORD").decode() - records = csv.reader(record.splitlines()) - record_files = [row[0] for row in records] - - assert re.search(r"\s+extended/extended.*\.(so|pyd)", record) is not None - finally: - zip.close() - - # Files in RECORD should match files in wheel. - zip_files = sorted(zip.namelist()) - assert zip_files == sorted(record_files) - assert len(set(record_files)) == len(record_files) - - -@pytest.mark.skipif( - sys.platform == "win32" - and sys.version_info <= (3, 6) - or platform.python_implementation().lower() == "pypy", - reason="Disable test on Windows for Python <=3.6 and for PyPy", +@pytest.mark.parametrize( + ["project", "exptected_c_dir"], + [ + ("extended", "extended"), + ("extended_with_no_setup", "extended"), + ("src_extended", "src/extended"), + ], ) -def test_wheel_c_extension_with_no_setup() -> None: # NOSONAR - module_path = fixtures_dir / "extended_with_no_setup" +def test_wheel_c_extension(project: str, exptected_c_dir: str) -> None: + module_path = fixtures_dir / project builder = Builder(Factory().create_poetry(module_path)) builder.build(fmt="all") - sdist = fixtures_dir / "extended_with_no_setup" / "dist" / "extended-0.1.tar.gz" - + sdist = fixtures_dir / project / "dist" / "extended-0.1.tar.gz" assert sdist.exists() - with tarfile.open(str(sdist), "r") as tar: + with tarfile.open(sdist, "r") as tar: assert "extended-0.1/build.py" in tar.getnames() - assert "extended-0.1/extended/extended.c" in tar.getnames() + assert f"extended-0.1/{exptected_c_dir}/extended.c" in tar.getnames() whl = list((module_path / "dist").glob("extended-0.1-cp*-cp*-*.whl"))[0] - assert whl.exists() - zip = zipfile.ZipFile(str(whl)) - - has_compiled_extension = False - for name in zip.namelist(): - if name.startswith("extended/extended") and name.endswith((".so", ".pyd")): - has_compiled_extension = True - - assert has_compiled_extension - - try: - wheel_data = zip.read("extended-0.1.dist-info/WHEEL").decode() + with zipfile.ZipFile(whl) as zipf: + has_compiled_extension = False + for name in zipf.namelist(): + if name.startswith("extended/extended") and name.endswith((".so", ".pyd")): + has_compiled_extension = True + assert has_compiled_extension + wheel_data = zipf.read("extended-0.1.dist-info/WHEEL").decode() assert ( re.match( f"""(?m)^\ @@ -152,84 +89,27 @@ def test_wheel_c_extension_with_no_setup() -> None: # NOSONAR is not None ) - record = zip.read("extended-0.1.dist-info/RECORD").decode() + record = zipf.read("extended-0.1.dist-info/RECORD").decode() records = csv.reader(record.splitlines()) record_files = [row[0] for row in records] - assert re.search(r"\s+extended/extended.*\.(so|pyd)", record) is not None - finally: - zip.close() - - # Files in RECORD should match files in wheel. - zip_files = sorted(zip.namelist()) - assert zip_files == sorted(record_files) - assert len(set(record_files)) == len(record_files) - - -@pytest.mark.skipif( - sys.platform == "win32" - and sys.version_info <= (3, 6) - or platform.python_implementation().lower() == "pypy", - reason="Disable test on Windows for Python <=3.6 and for PyPy", -) -def test_wheel_c_extension_src_layout() -> None: # NOSONAR - module_path = fixtures_dir / "src_extended" - builder = Builder(Factory().create_poetry(module_path)) - builder.build(fmt="all") - - sdist = fixtures_dir / "src_extended" / "dist" / "extended-0.1.tar.gz" - - assert sdist.exists() - - with tarfile.open(str(sdist), "r") as tar: - assert "extended-0.1/build.py" in tar.getnames() - assert "extended-0.1/src/extended/extended.c" in tar.getnames() - - whl = list((module_path / "dist").glob("extended-0.1-cp*-cp*-*.whl"))[0] - - assert whl.exists() - - zip = zipfile.ZipFile(str(whl)) - - has_compiled_extension = False - for name in zip.namelist(): - if name.startswith("extended/extended") and name.endswith((".so", ".pyd")): - has_compiled_extension = True - - assert has_compiled_extension - - try: - wheel_data = zip.read("extended-0.1.dist-info/WHEEL").decode() - assert ( - re.match( - f"""(?m)^\ -Wheel-Version: 1.0 -Generator: poetry-core {__version__} -Root-Is-Purelib: false -Tag: cp[23]_?\\d+-cp[23]_?\\d+m?u?-.+ -$""", - wheel_data, - ) - is not None - ) - - record = zip.read("extended-0.1.dist-info/RECORD").decode() - records = csv.reader(record.splitlines()) - record_files = [row[0] for row in records] + # Files in RECORD should match files in wheel. + zip_files = sorted(zipf.namelist()) + assert zip_files == sorted(record_files) + assert len(set(record_files)) == len(record_files) - assert re.search(r"\s+extended/extended.*\.(so|pyd)", record) is not None - finally: - zip.close() - # Files in RECORD should match files in wheel. - zip_files = sorted(zip.namelist()) - assert zip_files == sorted(record_files) - assert len(set(record_files)) == len(record_files) +@pytest.mark.parametrize("no_vcs", [False, True]) +def test_complete(no_vcs: bool) -> None: + module_path = fixtures_dir / "complete" + if no_vcs: + # Copy the complete fixtures dir to a temporary directory + temporary_dir = Path(tempfile.mkdtemp()) / "complete" + shutil.copytree(module_path.as_posix(), temporary_dir.as_posix()) + module_path = temporary_dir -def test_complete() -> None: - module_path = fixtures_dir / "complete" builder = Builder(Factory().create_poetry(module_path)) builder.build(fmt="all") @@ -239,126 +119,6 @@ def test_complete() -> None: if sys.platform != "win32": assert (os.stat(str(whl)).st_mode & 0o777) == 0o644 - zip = zipfile.ZipFile(str(whl)) - - try: - assert "my_package/sub_pgk1/extra_file.xml" not in zip.namelist() - assert "my_package-1.2.3.data/scripts/script.sh" in zip.namelist() - assert ( - "Hello World" - in zip.read("my_package-1.2.3.data/scripts/script.sh").decode() - ) - - entry_points = zip.read("my_package-1.2.3.dist-info/entry_points.txt") - - assert ( - entry_points.decode() - == """\ -[console_scripts] -extra-script=my_package.extra:main[time] -my-2nd-script=my_package:main2 -my-script=my_package:main - -""" - ) - wheel_data = zip.read("my_package-1.2.3.dist-info/WHEEL").decode() - - assert ( - wheel_data - == f"""\ -Wheel-Version: 1.0 -Generator: poetry-core {__version__} -Root-Is-Purelib: true -Tag: py3-none-any -""" - ) - wheel_data = zip.read("my_package-1.2.3.dist-info/METADATA").decode() - - assert ( - wheel_data - == """\ -Metadata-Version: 2.1 -Name: my-package -Version: 1.2.3 -Summary: Some description. -Home-page: https://python-poetry.org/ -License: MIT -Keywords: packaging,dependency,poetry -Author: Sébastien Eustace -Author-email: sebastien@eustace.io -Maintainer: People Everywhere -Maintainer-email: people@everywhere.com -Requires-Python: >=3.6,<4.0 -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Topic :: Software Development :: Build Tools -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Provides-Extra: time -Requires-Dist: cachy[msgpack] (>=0.2.0,<0.3.0) -Requires-Dist: cleo (>=0.6,<0.7) -Requires-Dist: pendulum (>=1.4,<2.0) ; (python_version ~= "2.7" and sys_platform == "win32" or python_version in "3.4 3.5") and (extra == "time") -Project-URL: Documentation, https://python-poetry.org/docs -Project-URL: Issue Tracker, https://github.com/python-poetry/poetry/issues -Project-URL: Repository, https://github.com/python-poetry/poetry -Description-Content-Type: text/x-rst - -My Package -========== - -""" - ) - actual_records = zip.read("my_package-1.2.3.dist-info/RECORD").decode() - - # For some reason, the ordering of the files and the SHA hashes - # vary per operating systems and Python versions. - # So instead of 1:1 assertion, let's do a bit clunkier one: - - actual_files = [row[0] for row in csv.reader(actual_records.splitlines())] - expected_files = [ - "my_package-1.2.3.data/scripts/script.sh", - "my_package-1.2.3.dist-info/LICENSE", - "my_package-1.2.3.dist-info/METADATA", - "my_package-1.2.3.dist-info/RECORD", - "my_package-1.2.3.dist-info/WHEEL", - "my_package-1.2.3.dist-info/entry_points.txt", - "my_package/__init__.py", - "my_package/data1/test.json", - "my_package/sub_pkg1/__init__.py", - "my_package/sub_pkg2/__init__.py", - "my_package/sub_pkg2/data2/data.json", - "my_package/sub_pkg3/foo.py", - ] - - assert sorted(expected_files) == sorted(actual_files) - - finally: - zip.close() - - -def test_complete_no_vcs() -> None: - # Copy the complete fixtures dir to a temporary directory - module_path = fixtures_dir / "complete" - temporary_dir = Path(tempfile.mkdtemp()) / "complete" - - shutil.copytree(module_path.as_posix(), temporary_dir.as_posix()) - - builder = Builder(Factory().create_poetry(temporary_dir)) - builder.build(fmt="all") - - whl = temporary_dir / "dist" / "my_package-1.2.3-py3-none-any.whl" - - assert whl.exists() - - zip = zipfile.ZipFile(str(whl)) - - # Check the zipped file to be sure that included and excluded files are - # correctly taken account of without vcs expected_name_list = [ "my_package/__init__.py", "my_package/data1/test.json", @@ -374,10 +134,14 @@ def test_complete_no_vcs() -> None: "my_package-1.2.3.dist-info/RECORD", ] - assert sorted(zip.namelist()) == sorted(expected_name_list) + with zipfile.ZipFile(str(whl)) as zipf: + assert sorted(zipf.namelist()) == sorted(expected_name_list) + assert ( + "Hello World" + in zipf.read("my_package-1.2.3.data/scripts/script.sh").decode() + ) - try: - entry_points = zip.read("my_package-1.2.3.dist-info/entry_points.txt") + entry_points = zipf.read("my_package-1.2.3.dist-info/entry_points.txt") assert ( entry_points.decode() @@ -389,7 +153,7 @@ def test_complete_no_vcs() -> None: """ ) - wheel_data = zip.read("my_package-1.2.3.dist-info/WHEEL").decode() + wheel_data = zipf.read("my_package-1.2.3.dist-info/WHEEL").decode() assert ( wheel_data @@ -400,7 +164,7 @@ def test_complete_no_vcs() -> None: Tag: py3-none-any """ ) - wheel_data = zip.read("my_package-1.2.3.dist-info/METADATA").decode() + wheel_data = zipf.read("my_package-1.2.3.dist-info/METADATA").decode() assert ( wheel_data @@ -430,7 +194,8 @@ def test_complete_no_vcs() -> None: Provides-Extra: time Requires-Dist: cachy[msgpack] (>=0.2.0,<0.3.0) Requires-Dist: cleo (>=0.6,<0.7) -Requires-Dist: pendulum (>=1.4,<2.0) ; (python_version ~= "2.7" and sys_platform == "win32" or python_version in "3.4 3.5") and (extra == "time") +Requires-Dist: pendulum (>=1.4,<2.0) ; (python_version ~= "2.7"\ + and sys_platform == "win32" or python_version in "3.4 3.5") and (extra == "time") Project-URL: Documentation, https://python-poetry.org/docs Project-URL: Issue Tracker, https://github.com/python-poetry/poetry/issues Project-URL: Repository, https://github.com/python-poetry/poetry @@ -441,8 +206,14 @@ def test_complete_no_vcs() -> None: """ ) - finally: - zip.close() + actual_records = zipf.read("my_package-1.2.3.dist-info/RECORD").decode() + + # For some reason, the ordering of the files and the SHA hashes + # vary per operating systems and Python versions. + # So instead of 1:1 assertion, let's do a bit clunkier one: + actual_files = [row[0] for row in csv.reader(actual_records.splitlines())] + + assert sorted(actual_files) == sorted(expected_name_list) def test_module_src() -> None: @@ -461,12 +232,8 @@ def test_module_src() -> None: assert whl.exists() - zip = zipfile.ZipFile(str(whl)) - - try: - assert "module_src.py" in zip.namelist() - finally: - zip.close() + with zipfile.ZipFile(str(whl)) as zipf: + assert "module_src.py" in zipf.namelist() def test_package_src() -> None: @@ -485,13 +252,9 @@ def test_package_src() -> None: assert whl.exists() - zip = zipfile.ZipFile(str(whl)) - - try: - assert "package_src/__init__.py" in zip.namelist() - assert "package_src/module.py" in zip.namelist() - finally: - zip.close() + with zipfile.ZipFile(str(whl)) as zipf: + assert "package_src/__init__.py" in zipf.namelist() + assert "package_src/module.py" in zipf.namelist() def test_split_source() -> None: @@ -511,13 +274,9 @@ def test_split_source() -> None: assert whl.exists() - zip = zipfile.ZipFile(str(whl)) - - try: - assert "module_a/__init__.py" in zip.namelist() - assert "module_b/__init__.py" in zip.namelist() - finally: - zip.close() + with zipfile.ZipFile(str(whl)) as zipf: + assert "module_a/__init__.py" in zipf.namelist() + assert "module_b/__init__.py" in zipf.namelist() def test_package_with_include(mocker: MockerFixture) -> None: From accd3fc3bebe0f1cbe4a40aa489dd85c3461727d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 11 Mar 2023 10:48:23 +0100 Subject: [PATCH 3/3] test(build): order in RECORD files and archives should be deterministic due to #545 --- tests/masonry/builders/test_complete.py | 45 ++++++++++++++----------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/tests/masonry/builders/test_complete.py b/tests/masonry/builders/test_complete.py index 0d2b656e5..f379f2fe9 100644 --- a/tests/masonry/builders/test_complete.py +++ b/tests/masonry/builders/test_complete.py @@ -95,8 +95,7 @@ def test_wheel_c_extension(project: str, exptected_c_dir: str) -> None: assert re.search(r"\s+extended/extended.*\.(so|pyd)", record) is not None # Files in RECORD should match files in wheel. - zip_files = sorted(zipf.namelist()) - assert zip_files == sorted(record_files) + assert zipf.namelist() == record_files assert len(set(record_files)) == len(record_files) @@ -119,23 +118,30 @@ def test_complete(no_vcs: bool) -> None: if sys.platform != "win32": assert (os.stat(str(whl)).st_mode & 0o777) == 0o644 - expected_name_list = [ - "my_package/__init__.py", - "my_package/data1/test.json", - "my_package/sub_pkg1/__init__.py", - "my_package/sub_pkg2/__init__.py", - "my_package/sub_pkg2/data2/data.json", - "my_package-1.2.3.data/scripts/script.sh", - "my_package/sub_pkg3/foo.py", - "my_package-1.2.3.dist-info/entry_points.txt", - "my_package-1.2.3.dist-info/LICENSE", - "my_package-1.2.3.dist-info/WHEEL", - "my_package-1.2.3.dist-info/METADATA", - "my_package-1.2.3.dist-info/RECORD", - ] + expected_name_list = ( + [ + "my_package/__init__.py", + "my_package/data1/test.json", + "my_package/sub_pkg1/__init__.py", + "my_package/sub_pkg2/__init__.py", + "my_package/sub_pkg2/data2/data.json", + "my_package/sub_pkg3/foo.py", + "my_package-1.2.3.data/scripts/script.sh", + ] + + sorted( + [ + "my_package-1.2.3.dist-info/entry_points.txt", + "my_package-1.2.3.dist-info/LICENSE", + "my_package-1.2.3.dist-info/METADATA", + "my_package-1.2.3.dist-info/WHEEL", + ], + key=lambda x: Path(x), + ) + + ["my_package-1.2.3.dist-info/RECORD"] + ) with zipfile.ZipFile(str(whl)) as zipf: - assert sorted(zipf.namelist()) == sorted(expected_name_list) + assert zipf.namelist() == expected_name_list assert ( "Hello World" in zipf.read("my_package-1.2.3.data/scripts/script.sh").decode() @@ -208,12 +214,11 @@ def test_complete(no_vcs: bool) -> None: ) actual_records = zipf.read("my_package-1.2.3.dist-info/RECORD").decode() - # For some reason, the ordering of the files and the SHA hashes - # vary per operating systems and Python versions. + # The SHA hashes vary per operating systems. # So instead of 1:1 assertion, let's do a bit clunkier one: actual_files = [row[0] for row in csv.reader(actual_records.splitlines())] - assert sorted(actual_files) == sorted(expected_name_list) + assert actual_files == expected_name_list def test_module_src() -> None: