From 78750f78fb142fabc69b37214f3d5111c3b65608 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 9 Aug 2023 14:28:08 +0100 Subject: [PATCH 1/3] Use default encoding when creating .pth files in editable_wheel --- setuptools/command/editable_wheel.py | 23 +++++++++++++++++++++-- setuptools/tests/test_editable_install.py | 8 ++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/setuptools/command/editable_wheel.py b/setuptools/command/editable_wheel.py index c978adad57..79e916bb78 100644 --- a/setuptools/command/editable_wheel.py +++ b/setuptools/command/editable_wheel.py @@ -11,6 +11,7 @@ """ import logging +import io import os import shutil import sys @@ -401,7 +402,7 @@ def __init__(self, dist: Distribution, name: str, path_entries: List[Path]): def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): entries = "\n".join((str(p.resolve()) for p in self.path_entries)) - contents = bytes(f"{entries}\n", "utf-8") + contents = _encode_pth(f"{entries}\n") wheel.writestr(f"__editable__.{self.name}.pth", contents) def __enter__(self): @@ -509,7 +510,7 @@ def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str] content = bytes(_finder_template(name, roots, namespaces_), "utf-8") wheel.writestr(f"{finder}.py", content) - content = bytes(f"import {finder}; {finder}.install()", "utf-8") + content = _encode_pth(f"import {finder}; {finder}.install()") wheel.writestr(f"__editable__.{self.name}.pth", content) def __enter__(self): @@ -525,6 +526,24 @@ def __exit__(self, _exc_type, _exc_value, _traceback): InformationOnly.emit("Editable installation.", msg) +def _encode_pth(content: str) -> bytes: + """.pth files are always read with 'locale' encoding, the recommendation + from the cpython core developers is to write them as ``open(path, "w")`` + and ignore warnings (see python/cpython#77102, pypa/setuptools#3937). + This function tries to simulate this behaviour without having to create an + actual file, in a way that supports a range of active Python versions. + (There seems to be some variety in the way different version of Python handle + ``encoding=None``, not all of them use ``locale.getpreferredencoding(False)``). + """ + encoding = "locale" if sys.version_info >= (3, 10) else None + with io.BytesIO() as buffer: + wrapper = io.TextIOWrapper(buffer, encoding) + wrapper.write(content) + wrapper.flush() + buffer.seek(0) + return buffer.read() + + def _can_symlink_files(base_dir: Path) -> bool: with TemporaryDirectory(dir=str(base_dir.resolve())) as tmp: path1, path2 = Path(tmp, "file1.txt"), Path(tmp, "file2.txt") diff --git a/setuptools/tests/test_editable_install.py b/setuptools/tests/test_editable_install.py index 0f1d716fef..0a86f8ed2a 100644 --- a/setuptools/tests/test_editable_install.py +++ b/setuptools/tests/test_editable_install.py @@ -22,6 +22,7 @@ from setuptools.command.editable_wheel import ( _DebuggingTips, _LinkTree, + _encode_pth, _find_virtual_namespaces, _find_namespaces, _find_package_roots, @@ -1025,6 +1026,13 @@ def test_debugging_tips(tmpdir_cwd, monkeypatch): cmd.run() +@pytest.mark.filterwarnings("error") +def test_encode_pth(): + """Ensure _encode_pth function does not produce encoding warnings""" + content = _encode_pth("hellò ŵørld") # no warnings (would be turned into errors) + assert isinstance(content, bytes) + + def install_project(name, venv, tmp_path, files, *opts): project = tmp_path / name project.mkdir() From 19c7186af29432b19195a1ac47174f53414aaea6 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 9 Aug 2023 14:33:11 +0100 Subject: [PATCH 2/3] Add newsfragment --- newsfragments/4009.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/4009.misc.rst diff --git a/newsfragments/4009.misc.rst b/newsfragments/4009.misc.rst new file mode 100644 index 0000000000..f127889cbc --- /dev/null +++ b/newsfragments/4009.misc.rst @@ -0,0 +1 @@ +Use default encoding to create ``.pth`` files with ``editable_wheel``. From 8aefb2a32f4fd9013ce4f118a30f89f313ec932b Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Wed, 9 Aug 2023 15:01:44 +0100 Subject: [PATCH 3/3] Change UTF-8 example to something simpler to parse --- setuptools/tests/test_editable_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setuptools/tests/test_editable_install.py b/setuptools/tests/test_editable_install.py index 0a86f8ed2a..08dd6e5f25 100644 --- a/setuptools/tests/test_editable_install.py +++ b/setuptools/tests/test_editable_install.py @@ -1029,7 +1029,7 @@ def test_debugging_tips(tmpdir_cwd, monkeypatch): @pytest.mark.filterwarnings("error") def test_encode_pth(): """Ensure _encode_pth function does not produce encoding warnings""" - content = _encode_pth("hellò ŵørld") # no warnings (would be turned into errors) + content = _encode_pth("tkmilan_ç_utf8") # no warnings (would be turned into errors) assert isinstance(content, bytes)