Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-poetry for openSUSE:Factory 
checked in at 2026-04-15 16:07:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-poetry (Old)
 and      /work/SRC/openSUSE:Factory/.python-poetry.new.21863 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-poetry"

Wed Apr 15 16:07:58 2026 rev:42 rq:1347109 version:2.3.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-poetry/python-poetry.changes      
2026-03-31 15:24:24.517617841 +0200
+++ /work/SRC/openSUSE:Factory/.python-poetry.new.21863/python-poetry.changes   
2026-04-15 16:14:38.511838572 +0200
@@ -1,0 +2,11 @@
+Sun Apr 12 18:16:23 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 2.3.4:
+  * Fix a performance regression in the wheel installer that was
+    introduced in Poetry 2.3.3 (#10821).
+  * Fix a path traversal vulnerability in sdist extraction on
+    Python 3.10.0-3.10.12 and 3.11.0-3.11.4 that could allow
+    malicious tarball files to write files outside the target
+    directory (#10837).
+
+-------------------------------------------------------------------

Old:
----
  poetry-2.3.3.tar.gz

New:
----
  poetry-2.3.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-poetry.spec ++++++
--- /var/tmp/diff_new_pack.PnqXhi/_old  2026-04-15 16:14:39.235868160 +0200
+++ /var/tmp/diff_new_pack.PnqXhi/_new  2026-04-15 16:14:39.235868160 +0200
@@ -27,7 +27,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-poetry%{psuffix}
-Version:        2.3.3
+Version:        2.3.4
 Release:        0
 Summary:        Python dependency management and packaging
 License:        MIT
@@ -46,6 +46,7 @@
 Requires:       python-filelock >= 3.8.0
 # /cachecontrol[filecache]
 Requires:       (python-cleo >= 2.1.0 with python-cleo < 3.0.0)
+Requires:       python-installer >= 0.7.0
 Requires:       python-packaging >= 24.2
 Requires:       python-pbs-installer >= 2025.6.10
 Requires:       python-trove-classifiers >= 2022.5.19
@@ -53,7 +54,6 @@
 Requires:       (python-dulwich >= 0.25.0 with python-dulwich < 2)
 Requires:       (python-fastjsonschema >= 2.18.0 with python-fastjsonschema < 
3.0.0)
 Requires:       (python-findpython >= 0.6.2 with python-findpython < 0.8.0)
-Requires:       (python-installer >= 0.7.0 with python-installer < 0.8.0)
 Requires:       (python-keyring >= 25.1.0 with python-keyring < 26.0.0)
 Requires:       (python-pkginfo >= 1.12 with python-pkginfo < 2.0)
 Requires:       (python-platformdirs >= 3.0.0 with python-platformdirs < 5)

++++++ poetry-2.3.3.tar.gz -> poetry-2.3.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.3/CHANGELOG.md 
new/poetry-2.3.4/CHANGELOG.md
--- old/poetry-2.3.3/CHANGELOG.md       2026-03-29 14:13:27.000000000 +0200
+++ new/poetry-2.3.4/CHANGELOG.md       2026-04-12 17:09:54.000000000 +0200
@@ -1,5 +1,13 @@
 # Change Log
 
+## [2.3.4] - 2026-04-12
+
+### Fixed
+
+- Fix a performance regression in the wheel installer that was introduced in 
Poetry 2.3.3 ([#10821](https://github.com/python-poetry/poetry/pull/10821)).
+- Fix a path traversal vulnerability in sdist extraction on Python 
3.10.0-3.10.12 and 3.11.0-3.11.4 that could allow malicious tarball files to 
write files outside the target directory 
([#10837](https://github.com/python-poetry/poetry/pull/10837)).
+
+
 ## [2.3.3] - 2026-03-29
 
 ### Fixed
@@ -2693,7 +2701,8 @@
 
 
 
-[Unreleased]: https://github.com/python-poetry/poetry/compare/2.3.3...main
+[Unreleased]: https://github.com/python-poetry/poetry/compare/2.3.4...main
+[2.3.4]: https://github.com/python-poetry/poetry/releases/tag/2.3.4
 [2.3.3]: https://github.com/python-poetry/poetry/releases/tag/2.3.3
 [2.3.2]: https://github.com/python-poetry/poetry/releases/tag/2.3.2
 [2.3.1]: https://github.com/python-poetry/poetry/releases/tag/2.3.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.3/pyproject.toml 
new/poetry-2.3.4/pyproject.toml
--- old/poetry-2.3.3/pyproject.toml     2026-03-29 14:13:27.000000000 +0200
+++ new/poetry-2.3.4/pyproject.toml     2026-04-12 17:09:54.000000000 +0200
@@ -1,6 +1,6 @@
 [project]
 name = "poetry"
-version = "2.3.3"
+version = "2.3.4"
 description = "Python dependency management and packaging made easy."
 requires-python = ">=3.10,<4.0"
 dependencies = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/poetry-2.3.3/src/poetry/installation/wheel_installer.py 
new/poetry-2.3.4/src/poetry/installation/wheel_installer.py
--- old/poetry-2.3.3/src/poetry/installation/wheel_installer.py 2026-03-29 
14:13:27.000000000 +0200
+++ new/poetry-2.3.4/src/poetry/installation/wheel_installer.py 2026-04-12 
17:09:54.000000000 +0200
@@ -1,6 +1,7 @@
 from __future__ import annotations
 
 import logging
+import os
 import platform
 import sys
 
@@ -14,7 +15,6 @@
 
 from poetry.__version__ import __version__
 from poetry.utils._compat import WINDOWS
-from poetry.utils._compat import is_relative_to
 
 
 logger = logging.getLogger(__name__)
@@ -45,14 +45,20 @@
         from installer.utils import copyfileobj_with_hashing
         from installer.utils import make_file_executable
 
-        target_dir = Path(self.scheme_dict[scheme]).resolve()
-        target_path = (target_dir / path).resolve()
+        # See https://docs.python.org/3/library/zipfile.html#zipfile.Path:
+        #  When handling untrusted archives,
+        #  consider resolving filenames using os.path.abspath()
+        #  and checking against the target directory with os.path.commonpath().
+        #
+        # Attention: Path.absolute() is not sufficient because it does not
+        #  normalize, i.e. does not remove "..".
+        #
+        # We want to avoid Path.resolve() because it is significantly slower
+        # than os.path.abspath()!
+        target_dir = Path(os.path.abspath(self.scheme_dict[scheme]))
+        target_path = Path(os.path.abspath(target_dir / path))
 
-        # Use is_relative_to() instead of Path.is_relative_to()
-        # because the latter does not work if one of both paths
-        # has a Windows long path prefix and the other path has not.
-        # (A long path prefix may be added when calling resolve().)
-        if not is_relative_to(target_path, target_dir):
+        if not target_path.is_relative_to(target_dir):
             raise ValueError(
                 f"Attempting to write {path} outside of the target directory\n"
                 f"Target directory: {target_dir}\n"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.3/src/poetry/utils/helpers.py 
new/poetry-2.3.4/src/poetry/utils/helpers.py
--- old/poetry-2.3.3/src/poetry/utils/helpers.py        2026-03-29 
14:13:27.000000000 +0200
+++ new/poetry-2.3.4/src/poetry/utils/helpers.py        2026-04-12 
17:09:54.000000000 +0200
@@ -415,7 +415,7 @@
     else:
         # These versions of python shipped with a broken tarfile data_filter, 
per
         # https://github.com/python/cpython/issues/107845.
-        broken_tarfile_filter = {(3, 9, 17), (3, 10, 12), (3, 11, 4)}
+        broken_tarfile_filter = {(3, 10, 12), (3, 11, 4)}
         with tarfile.open(source) as archive:
             if (
                 hasattr(tarfile, "data_filter")
@@ -423,4 +423,37 @@
             ):
                 archive.extractall(dest, filter="data")
             else:
-                archive.extractall(dest)
+                # Validate all member paths before extraction
+                #
+                # Attention: Path.absolute() is not sufficient because it does 
not
+                #  normalize, i.e. does not remove "..".
+                #
+                # We want to avoid Path.resolve() because it is significantly 
slower
+                # than os.path.abspath()!
+                dest = Path(os.path.abspath(dest))
+                safe_members = []
+                for member in archive.getmembers():
+                    member_path = Path(os.path.abspath(dest / member.name))
+                    if not member_path.is_relative_to(dest):
+                        raise ValueError(
+                            f"Refusing to extract {member.name}: "
+                            f"would write outside {dest}"
+                        )
+                    if member.issym():
+                        link_target = Path(
+                            os.path.abspath(member_path.parent / 
member.linkname)
+                        )
+                        if not link_target.is_relative_to(dest):
+                            raise ValueError(
+                                f"Refusing symlink {member.name}: "
+                                f"target {member.linkname} outside {dest}"
+                            )
+                    elif member.islnk():
+                        link_target = Path(os.path.abspath(dest / 
member.linkname))
+                        if not link_target.is_relative_to(dest):
+                            raise ValueError(
+                                f"Refusing hardlink {member.name}: "
+                                f"target {member.linkname} outside {dest}"
+                            )
+                    safe_members.append(member)
+                archive.extractall(dest, members=safe_members)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.3/tests/conftest.py 
new/poetry-2.3.4/tests/conftest.py
--- old/poetry-2.3.3/tests/conftest.py  2026-03-29 14:13:27.000000000 +0200
+++ new/poetry-2.3.4/tests/conftest.py  2026-04-12 17:09:54.000000000 +0200
@@ -1047,3 +1047,85 @@
         return bin_dir
 
     return register
+
+
[email protected](params=[False, True])  # relative path
+def wheel_with_path_traversal(tmp_path: Path, request: pytest.FixtureRequest) 
-> Path:
+    import zipfile
+
+    traversal_path = (
+        "../../traversal.txt"
+        if request.param
+        else (tmp_path / "traversal.txt").as_posix()
+    )
+
+    wheel = tmp_path / "traversal-0.1-py3-none-any.whl"
+    files = {
+        "traversal/__init__.py": b"",
+        traversal_path: b"path traversal",
+        "traversal-0.1.dist-info/WHEEL": (
+            b"Wheel-Version: 1.0\nRoot-Is-Purelib: true\nTag: py3-none-any\n"
+        ),
+        "traversal-0.1.dist-info/METADATA": (
+            b"Metadata-Version: 2.1\nName: traversal\nVersion: 0.1\n"
+        ),
+    }
+    files["traversal-0.1.dist-info/RECORD"] = (
+        "\n".join([f"{k},," for k in files] + 
["traversal-0.1.dist-info/RECORD,,"])
+        + "\n"
+    ).encode()
+
+    with zipfile.ZipFile(wheel, "w") as z:
+        for k, v in files.items():
+            z.writestr(k, v)
+
+    return wheel
+
+
[email protected](params=[False, True])  # relative path
+def wheel_with_path_traversal_via_symlink(
+    tmp_path: Path, request: pytest.FixtureRequest
+) -> Path:
+    import stat
+    import zipfile
+
+    wheel = tmp_path / "symlink-0.1-py3-none-any.whl"
+    files = {
+        "symlink/__init__.py": b"",
+        "symlink-0.1.dist-info/WHEEL": (
+            b"Wheel-Version: 1.0\nRoot-Is-Purelib: true\nTag: py3-none-any\n"
+        ),
+        "symlink-0.1.dist-info/METADATA": (
+            b"Metadata-Version: 2.1\nName: symlink-pkg\nVersion: 0.1\n"
+        ),
+    }
+
+    symlink_entry = "symlink/traversal_link"
+    symlink_target = (
+        b"../../target"
+        if request.param
+        else (tmp_path / "target").as_posix().encode("utf-8")
+    )
+    traversal_file = "symlink/traversal_link/traversal.txt"
+
+    record_lines = [f"{k},," for k in files]
+    record_lines.append(f"{symlink_entry},,")
+    record_lines.append(f"{traversal_file},,")
+    record_lines.append("symlink-0.1.dist-info/RECORD,,")
+    files["symlink-0.1.dist-info/RECORD"] = ("\n".join(record_lines) + 
"\n").encode()
+
+    with zipfile.ZipFile(wheel, "w") as z:
+        for k, v in files.items():
+            z.writestr(k, v)
+
+        # Add a ZIP entry whose external attributes mark it as a symlink.
+        # The entry's data is the symlink target, pointing outside the
+        # installation directory.
+        info = zipfile.ZipInfo(symlink_entry)
+        info.create_system = 3  # unix
+        info.external_attr = (stat.S_IFLNK | 0o777) << 16
+        z.writestr(info, symlink_target)
+
+        z.writestr(traversal_file, b"path traversal")
+
+    return wheel
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/poetry-2.3.3/tests/installation/test_wheel_installer.py 
new/poetry-2.3.4/tests/installation/test_wheel_installer.py
--- old/poetry-2.3.3/tests/installation/test_wheel_installer.py 2026-03-29 
14:13:27.000000000 +0200
+++ new/poetry-2.3.4/tests/installation/test_wheel_installer.py 2026-04-12 
17:09:54.000000000 +0200
@@ -10,6 +10,7 @@
 from poetry.core.constraints.version import parse_constraint
 
 from poetry.installation.wheel_installer import WheelInstaller
+from poetry.utils._compat import WINDOWS
 from poetry.utils.env import MockEnv
 
 
@@ -21,7 +22,7 @@
 
 @pytest.fixture
 def env(tmp_path: Path) -> MockEnv:
-    return MockEnv(path=tmp_path)
+    return MockEnv(path=tmp_path / "env")
 
 
 @pytest.fixture(scope="module")
@@ -97,35 +98,49 @@
     assert (Path(env.paths["purelib"]) / "demo").exists()
 
 
[email protected]
-def wheel_with_path_traversal(tmp_path: Path) -> Path:
-    import zipfile
[email protected]("existing", [False, True])
+def test_no_path_traversal(
+    env: MockEnv, wheel_with_path_traversal: Path, existing: bool
+) -> None:
+    """see also test_extractall_wheel_no_path_traversal in test_helpers.py"""
+    target = env.path.parent / "traversal.txt"
+    if existing:
+        target.write_text("original", encoding="utf-8")
+    installer = WheelInstaller(env)
+    with pytest.raises(ValueError):
+        installer.install(wheel_with_path_traversal)
 
-    wheel = tmp_path / "traversal-0.1-py3-none-any.whl"
-    files = {
-        "traversal/__init__.py": b"",
-        "../../traversal.txt": b"",
-        "traversal-0.1.dist-info/WHEEL": (
-            b"Wheel-Version: 1.0\nRoot-Is-Purelib: true\nTag: py3-none-any\n"
-        ),
-        "traversal-0.1.dist-info/METADATA": (
-            b"Metadata-Version: 2.1\nName: traversal\nVersion: 0.1\n"
-        ),
-    }
-    files["traversal-0.1.dist-info/RECORD"] = (
-        "\n".join([f"{k},," for k in files] + 
["traversal-0.1.dist-info/RECORD,,"])
-        + "\n"
-    ).encode()
-
-    with zipfile.ZipFile(wheel, "w") as z:
-        for k, v in files.items():
-            z.writestr(k, v)
+    if existing:
+        assert target.exists()
+        assert target.read_text(encoding="utf-8") == "original"
+    else:
+        assert not target.exists()
 
-    return wheel
 
[email protected]("existing", [False, True])
+def test_no_path_traversal_via_symlink(
+    tmp_path: Path,
+    env: MockEnv,
+    wheel_with_path_traversal_via_symlink: Path,
+    existing: bool,
+) -> None:
+    """see also test_extractall_wheel_no_path_traversal_via_symlink
+    in test_helpers.py"""
+    target_dir = tmp_path / "target"
+    target_dir.mkdir()
+    target = target_dir / "traversal.txt"
+    if existing:
+        target.write_text("original", encoding="utf-8")
 
-def test_path_traversal(env: MockEnv, wheel_with_path_traversal: Path) -> None:
     installer = WheelInstaller(env)
-    with pytest.raises(ValueError):
-        installer.install(wheel_with_path_traversal)
-    assert not (env.path.parent / "traversal.txt").exists()
+    with pytest.raises(FileNotFoundError if WINDOWS else NotADirectoryError):
+        installer.install(wheel_with_path_traversal_via_symlink)
+
+    traversal_link = Path(env.paths["purelib"]) / "symlink" / "traversal_link"
+    assert traversal_link.exists()
+    assert not traversal_link.is_symlink()  # not even extracted as symlink
+    assert target_dir.exists()
+    if existing:
+        assert target.read_text(encoding="utf-8") == "original"
+    else:
+        assert not list(target_dir.iterdir())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/poetry-2.3.3/tests/utils/test_helpers.py 
new/poetry-2.3.4/tests/utils/test_helpers.py
--- old/poetry-2.3.3/tests/utils/test_helpers.py        2026-03-29 
14:13:27.000000000 +0200
+++ new/poetry-2.3.4/tests/utils/test_helpers.py        2026-04-12 
17:09:54.000000000 +0200
@@ -1,7 +1,10 @@
 from __future__ import annotations
 
 import base64
+import contextlib
 import re
+import sys
+import tarfile
 
 from pathlib import Path
 from typing import TYPE_CHECKING
@@ -13,10 +16,12 @@
 from poetry.core.utils.helpers import parse_requires
 from requests.exceptions import ChunkedEncodingError
 
+from poetry.utils._compat import WINDOWS
 from poetry.utils.helpers import Downloader
 from poetry.utils.helpers import HTTPRangeRequestSupportedError
 from poetry.utils.helpers import download_file
 from poetry.utils.helpers import ensure_path
+from poetry.utils.helpers import extractall
 from poetry.utils.helpers import get_file_hash
 from poetry.utils.helpers import get_highest_priority_hash_type
 
@@ -341,3 +346,165 @@
 
     path.mkdir()
     assert ensure_path(path=path, is_directory=True) is path
+
+
[email protected]("relative", [False, True])
[email protected]("existing", [False, True])
+def test_extractall_sdist_no_path_traversal(
+    tmp_path: Path, relative: bool, existing: bool
+) -> None:
+    import io
+    import tarfile
+
+    archive = tmp_path / "traversal.tar.gz"
+    dest = tmp_path / "dest"
+    dest.mkdir()
+
+    target = tmp_path / "traversal.txt"
+    if existing:
+        target.write_text("original", encoding="utf-8")
+
+    with tarfile.open(archive, "w:gz") as tar:
+        b = b"path traversal"
+        t = tarfile.TarInfo("../traversal.txt" if relative else 
target.as_posix())
+        t.size = len(b)
+        tar.addfile(t, io.BytesIO(b))
+
+    has_data_filter = hasattr(tarfile, "data_filter")
+    # The stdlib implementation just strips the leading "/" from absolute paths
+    # and extracts them relative to the target directory (except for Windows).
+    # We do not care and raise an error.
+    raises = (
+        relative
+        or WINDOWS
+        or not has_data_filter
+        or sys.version_info[:3] in {(3, 10, 12), (3, 11, 4)}
+    )
+    exceptions: tuple[type[Exception], ...]
+    if has_data_filter:
+        if relative:
+            exceptions = (tarfile.OutsideDestinationError, ValueError)
+        else:
+            exceptions = (tarfile.AbsolutePathError, ValueError)
+    else:
+        # tarfile.OutsideDestinationError does not exist
+        exceptions = (ValueError,)
+
+    with pytest.raises(exceptions) if raises else contextlib.nullcontext():
+        extractall(source=archive, dest=dest, zip=False)
+
+    if existing:
+        assert target.exists()
+        assert target.read_text(encoding="utf-8") == "original"
+    else:
+        assert not target.exists()
+    if not raises:
+        # check that expected location exists, otherwise we have to check
+        # that there is no traversal in an unexpected location
+        assert (dest / target.as_posix().lstrip("/")).exists()
+
+
[email protected]("link_type", [tarfile.SYMTYPE, tarfile.LNKTYPE])
[email protected]("relative", [False, True])
[email protected]("existing", [False, True])
+def test_extractall_sdist_no_symlink_path_traversal(
+    tmp_path: Path, link_type: bytes, relative: bool, existing: bool
+) -> None:
+    import io
+    import tarfile
+
+    archive = tmp_path / "traversal.tar.gz"
+    dest = tmp_path / "dest"
+    dest.mkdir()
+
+    target = tmp_path / "traversal.txt"
+    if existing:
+        target.write_text("original", encoding="utf-8")
+
+    with tarfile.open(archive, "w:gz") as tar:
+        # We use a link in a subdirectory to test the difference
+        # between symlinks and hardlinks:
+        # symlinks are relative to the directory of the symlink,
+        # while hardlinks are relative to the root of the archive
+        s = tarfile.TarInfo("sub/link")
+        s.type = link_type
+        if relative:
+            s.linkname = (
+                "../../traversal.txt"
+                if link_type == tarfile.SYMTYPE
+                else "../traversal.txt"
+            )
+        else:
+            s.linkname = target.as_posix()
+        tar.addfile(s)
+        p = b"path traversal"
+        f = tarfile.TarInfo("sub/link")
+        f.size = len(p)
+        tar.addfile(f, io.BytesIO(p))
+
+    exceptions: tuple[type[Exception], ...]
+    if hasattr(tarfile, "data_filter"):
+        exceptions = (
+            tarfile.AbsoluteLinkError,
+            tarfile.LinkOutsideDestinationError,
+            ValueError,
+        )
+    else:
+        # tarfile.OutsideDestinationError does not exist
+        exceptions = (ValueError,)
+
+    with pytest.raises(exceptions):
+        extractall(source=archive, dest=dest, zip=False)
+
+    if existing:
+        assert target.exists()
+        assert target.read_text(encoding="utf-8") == "original"
+    else:
+        assert not target.exists()
+
+
[email protected]("existing", [False, True])
+def test_extractall_wheel_no_path_traversal(
+    tmp_path: Path, wheel_with_path_traversal: Path, existing: bool
+) -> None:
+    """see also test_no_path_traversal in test_wheel_installer.py"""
+    dest = tmp_path / "dest" / "dir"
+    dest.mkdir(parents=True)
+    target = tmp_path / "traversal.txt"
+    if existing:
+        target.write_text("original", encoding="utf-8")
+
+    extractall(source=wheel_with_path_traversal, dest=dest, zip=True)
+
+    if existing:
+        assert target.exists()
+        assert target.read_text(encoding="utf-8") == "original"
+    else:
+        assert not target.exists()
+
+    # target is "../.." but also check ".." just to be sure
+    assert not (dest.parent / "traversal.txt").exists()
+
+
[email protected]("existing", [False, True])
+def test_extractall_wheel_no_path_traversal_via_symlink(
+    tmp_path: Path, wheel_with_path_traversal_via_symlink: Path, existing: bool
+) -> None:
+    """see also test_no_path_traversal_via_symlink in 
test_wheel_installer.py"""
+    dest = tmp_path / "dest" / "dir"
+    dest.mkdir(parents=True)
+    target_dir = tmp_path / "target"
+    target_dir.mkdir()
+    target = target_dir / "traversal.txt"
+    if existing:
+        target.write_text("original", encoding="utf-8")
+
+    with pytest.raises(FileNotFoundError if WINDOWS else NotADirectoryError):
+        extractall(source=wheel_with_path_traversal_via_symlink, dest=dest, 
zip=True)
+
+    assert target_dir.exists()
+    if existing:
+        assert target.exists()
+        assert target.read_text(encoding="utf-8") == "original"
+    else:
+        assert not target.exists()

Reply via email to