Skip to content

Commit

Permalink
Use compat.py312.PTH_ENCODING instead of locale
Browse files Browse the repository at this point in the history
  • Loading branch information
abravalheri committed May 22, 2024
1 parent 36324d6 commit 5f7adfd
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 20 deletions.
48 changes: 34 additions & 14 deletions setuptools/command/easy_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
DEVELOP_DIST,
)
import pkg_resources
from ..compat import py39, py311
from ..compat import py39, py311, py312
from .._path import ensure_directory
from ..extern.jaraco.text import yield_lines

Expand Down Expand Up @@ -588,8 +588,9 @@ def check_pth_processing(self): # noqa: C901
os.unlink(ok_file)
dirname = os.path.dirname(ok_file)
os.makedirs(dirname, exist_ok=True)
f = open(pth_file, 'w', encoding=py39.LOCALE_ENCODING)
# ^-- Requires encoding="locale" instead of "utf-8" (python/cpython#77102).
f = open(pth_file, 'w', encoding=py312.PTH_ENCODING)
# ^-- Python<3.13 require encoding="locale" instead of "utf-8",
# see python/cpython#77102.
except OSError:
self.cant_write_to_target()
else:
Expand Down Expand Up @@ -1279,8 +1280,9 @@ def update_pth(self, dist): # noqa: C901 # is too complex (11) # FIXME
if os.path.islink(filename):
os.unlink(filename)

with open(filename, 'wt', encoding=py39.LOCALE_ENCODING) as f:
# Requires encoding="locale" instead of "utf-8" (python/cpython#77102).
with open(filename, 'wt', encoding=py312.PTH_ENCODING) as f:
# ^-- Python<3.13 require encoding="locale" instead of "utf-8",
# see python/cpython#77102.
f.write(self.pth_file.make_relative(dist.location) + '\n')

def unpack_progress(self, src, dst):
Expand Down Expand Up @@ -1506,9 +1508,8 @@ def expand_paths(inputs): # noqa: C901 # is too complex (11) # FIXME
continue

# Read the .pth file
with open(os.path.join(dirname, name), encoding=py39.LOCALE_ENCODING) as f:
# Requires encoding="locale" instead of "utf-8" (python/cpython#77102).
lines = list(yield_lines(f))
content = _read_pth(os.path.join(dirname, name))
lines = list(yield_lines(content))

# Yield existing non-dupe, non-import directory lines from it
for line in lines:
Expand Down Expand Up @@ -1622,9 +1623,8 @@ def _load_raw(self):
paths = []
dirty = saw_import = False
seen = dict.fromkeys(self.sitedirs)
f = open(self.filename, 'rt', encoding=py39.LOCALE_ENCODING)
# ^-- Requires encoding="locale" instead of "utf-8" (python/cpython#77102).
for line in f:
content = _read_pth(self.filename)
for line in content.splitlines():
path = line.rstrip()
# still keep imports and empty/commented lines for formatting
paths.append(path)
Expand All @@ -1643,7 +1643,6 @@ def _load_raw(self):
paths.pop()
continue
seen[normalized_path] = 1
f.close()
# remove any trailing empty/blank line
while paths and not paths[-1].strip():
paths.pop()
Expand Down Expand Up @@ -1694,8 +1693,9 @@ def save(self):
data = '\n'.join(lines) + '\n'
if os.path.islink(self.filename):
os.unlink(self.filename)
with open(self.filename, 'wt', encoding=py39.LOCALE_ENCODING) as f:
# Requires encoding="locale" instead of "utf-8" (python/cpython#77102).
with open(self.filename, 'wt', encoding=py312.PTH_ENCODING) as f:
# ^-- Python<3.13 require encoding="locale" instead of "utf-8",
# see python/cpython#77102.
f.write(data)
elif os.path.exists(self.filename):
log.debug("Deleting empty %s", self.filename)
Expand Down Expand Up @@ -2350,6 +2350,26 @@ def only_strs(values):
return filter(lambda val: isinstance(val, str), values)


def _read_pth(fullname: str) -> str:
# Python<3.13 require encoding="locale" instead of "utf-8", see python/cpython#77102
# In the case old versions of setuptools are producing `pth` files with
# different encodings that might be problematic... So we fallback to "locale".

try:
with open(fullname, encoding=py312.PTH_ENCODING) as f:
return f.read()
except UnicodeDecodeError: # pragma: no cover
# This error may only happen for Python >= 3.13
# TODO: Possible deprecation warnings to be added in the future:
# ``.pth file {fullname!r} is not UTF-8.``
# Your environment contain {fullname!r} that cannot be read as UTF-8.
# This is likely to have been produced with an old version of setuptools.
# Please be mindful that this is deprecated and in the future, non-utf8
# .pth files may cause setuptools to fail.
with open(fullname, encoding=py39.LOCALE_ENCODING) as f:
return f.read()


class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning):
_SUMMARY = "easy_install command is deprecated."
_DETAILS = """
Expand Down
9 changes: 6 additions & 3 deletions setuptools/command/editable_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
namespaces,
)
from .._path import StrPath
from ..compat import py39
from ..compat import py312
from ..discovery import find_package_path
from ..dist import Distribution
from ..warnings import (
Expand Down Expand Up @@ -559,7 +559,9 @@ def __exit__(self, _exc_type, _exc_value, _traceback):


def _encode_pth(content: str) -> bytes:
""".pth files are always read with 'locale' encoding, the recommendation
"""
Prior to Python 3.13 (see https://github.com/python/cpython/issues/77102),
.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
Expand All @@ -569,7 +571,8 @@ def _encode_pth(content: str) -> bytes:
or ``locale.getencoding()``).
"""
with io.BytesIO() as buffer:
wrapper = io.TextIOWrapper(buffer, encoding=py39.LOCALE_ENCODING)
wrapper = io.TextIOWrapper(buffer, encoding=py312.PTH_ENCODING)
# TODO: Python 3.13 replace the whole function with `bytes(content, "utf-8")`
wrapper.write(content)
wrapper.flush()
buffer.seek(0)
Expand Down
7 changes: 4 additions & 3 deletions setuptools/namespaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from distutils import log
import itertools

from .compat import py39
from .compat import py312


flatten = itertools.chain.from_iterable
Expand All @@ -25,8 +25,9 @@ def install_namespaces(self):
list(lines)
return

with open(filename, 'wt', encoding=py39.LOCALE_ENCODING) as f:
# Requires encoding="locale" instead of "utf-8" (python/cpython#77102).
with open(filename, 'wt', encoding=py312.PTH_ENCODING) as f:
# Python<3.13 requires encoding="locale" instead of "utf-8"
# See: python/cpython#77102
f.writelines(lines)

def uninstall_namespaces(self):
Expand Down

0 comments on commit 5f7adfd

Please sign in to comment.