From 57df729ba46fd5bc18072f573d8565fc069de86e Mon Sep 17 00:00:00 2001 From: Blazej Michalik Date: Tue, 3 Aug 2021 00:10:53 +0200 Subject: [PATCH] WheelFile: finish from_wheelfile --- CHANGELOG.md | 3 +++ tests/test_wheelfile_cloning.py | 14 ++++++++++++- wheelfile.py | 36 +++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fea36a..38caaae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ Versioning](https://semver.org/spec/v2.0.0.html). wheel name (`.build_tag`). ### Added +- `WheelFile.from_wheelfile` - a constructor class-method that makes it + possible to recreate a wheel and: rename it (change distname, version, + buildnumber and/or tags), append files to it, change its metadata, etc. - `WheelFile.METADATA_FILENAMES` - a static field with a set of names of metadata files managed by this class. - `WheelFile.writestr_distinfo` - similar to `write_distinfo`, this is a safe diff --git a/tests/test_wheelfile_cloning.py b/tests/test_wheelfile_cloning.py index 5870144..1ac6ea1 100644 --- a/tests/test_wheelfile_cloning.py +++ b/tests/test_wheelfile_cloning.py @@ -418,7 +418,7 @@ def test_raises_VE_when_same_path_used(self, wf, buf, tmp_file): with pytest.raises(ValueError): WheelFile.from_wheelfile(wf, tmp_file) - def test_raises_VE_when_same_path_used_relatively(self, wf, buf, tmp_path): + def test_raises_VE_when_same_path_used_relatively(self, wf, tmp_path): (tmp_path / 'relative/').mkdir() (tmp_path / 'path/').mkdir() path = (tmp_path / 'relative/../path/../') @@ -426,3 +426,15 @@ def test_raises_VE_when_same_path_used_relatively(self, wf, buf, tmp_path): with WheelFile(path, mode='w', distname='_', version='0') as wf: with pytest.raises(ValueError): WheelFile.from_wheelfile(wf, tmp_path) + + @pytest.fixture + def tmp_cwd(self, tmp_path): + old_dir = os.getcwd() + os.chdir(tmp_path) + yield tmp_path + os.chdir(old_dir) + + def test_raises_VE_when_same_path_used_via_curdir(self, tmp_cwd): + with WheelFile(tmp_cwd, mode='w', distname='_', version='0') as wf: + with pytest.raises(ValueError): + WheelFile.from_wheelfile(wf) diff --git a/wheelfile.py b/wheelfile.py index 2eaa2a1..3c87caa 100644 --- a/wheelfile.py +++ b/wheelfile.py @@ -1342,6 +1342,12 @@ def from_wheelfile( if platform_tag is cls._unspecified: platform_tag = wf.platform_tag + # Required for the path check below + if isinstance(version, str): + version = Version(version) + if isinstance(file_or_path, str): + file_or_path = Path(file_or_path) + # For MyPy assert isinstance(distname, str) or distname is None assert isinstance(version, (str, Version)) or version is None @@ -1356,6 +1362,36 @@ def from_wheelfile( "same as the one used by the other WheelFile object." ) + f_o_p = file_or_path # For brevity + dir_path = ( + f_o_p.resolve() if isinstance(f_o_p, Path) and f_o_p.is_dir() else + f_o_p.parent.resolve() if isinstance(f_o_p, Path) else + getattr(f_o_p, 'name', None) + ) + + # wf.zipfile.filename is not None only when it is writing to a file + both_are_files = ( + wf.zipfile.filename is not None + and dir_path is not None + ) + + if both_are_files: + assert wf.zipfile.filename is not None # For MyPy + # Ensure we won't overwrite wf + wf_dir_path = Path(wf.zipfile.filename).parent.resolve() + if wf_dir_path == dir_path and ( + wf.distname == distname + and wf.version == version + and wf.build_tag == build_tag + and wf.language_tag == language_tag + and wf.abi_tag == abi_tag + and wf.platform_tag == platform_tag + ): + raise ValueError( + "Operation would overwrite the old wheel - " + "both objects' paths point at the same file." + ) + new_wf = WheelFile( file_or_path, mode, distname=distname,