Skip to content

Commit

Permalink
pythongh-77102: site: try utf-8 and fallback to locale encoding when …
Browse files Browse the repository at this point in the history
…reading .pth file (python#117802)
  • Loading branch information
methane authored and diegorusso committed Apr 17, 2024
1 parent 8135251 commit b99f984
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 26 deletions.
4 changes: 4 additions & 0 deletions Doc/library/site.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ with ``import`` (followed by space or tab) are executed.
Limiting a code chunk to a single line is a deliberate measure
to discourage putting anything more complex here.

.. versionchanged:: 3.13
The :file:`.pth` files are now decoded by UTF-8 at first and then by the
:term:`locale encoding` if it fails.

.. index::
single: package
triple: path; configuration; file
Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,13 @@ re
* Rename :exc:`!re.error` to :exc:`re.PatternError` for improved clarity.
:exc:`!re.error` is kept for backward compatibility.

site
----

* :file:`.pth` files are now decoded by UTF-8 first, and then by the
:term:`locale encoding` if the UTF-8 decoding fails.
(Contributed by Inada Naoki in :gh:`117802`.)

sqlite3
-------

Expand Down
61 changes: 35 additions & 26 deletions Lib/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,35 +179,44 @@ def addpackage(sitedir, name, known_paths):
return
_trace(f"Processing .pth file: {fullname!r}")
try:
# locale encoding is not ideal especially on Windows. But we have used
# it for a long time. setuptools uses the locale encoding too.
f = io.TextIOWrapper(io.open_code(fullname), encoding="locale")
with io.open_code(fullname) as f:
pth_content = f.read()
except OSError:
return
with f:
for n, line in enumerate(f):
if line.startswith("#"):
continue
if line.strip() == "":

try:
pth_content = pth_content.decode()
except UnicodeDecodeError:
# Fallback to locale encoding for backward compatibility.
# We will deprecate this fallback in the future.
import locale
pth_content = pth_content.decode(locale.getencoding())
_trace(f"Cannot read {fullname!r} as UTF-8. "
f"Using fallback encoding {locale.getencoding()!r}")

for n, line in enumerate(pth_content.splitlines(), 1):
if line.startswith("#"):
continue
if line.strip() == "":
continue
try:
if line.startswith(("import ", "import\t")):
exec(line)
continue
try:
if line.startswith(("import ", "import\t")):
exec(line)
continue
line = line.rstrip()
dir, dircase = makepath(sitedir, line)
if not dircase in known_paths and os.path.exists(dir):
sys.path.append(dir)
known_paths.add(dircase)
except Exception as exc:
print("Error processing line {:d} of {}:\n".format(n+1, fullname),
file=sys.stderr)
import traceback
for record in traceback.format_exception(exc):
for line in record.splitlines():
print(' '+line, file=sys.stderr)
print("\nRemainder of file ignored", file=sys.stderr)
break
line = line.rstrip()
dir, dircase = makepath(sitedir, line)
if dircase not in known_paths and os.path.exists(dir):
sys.path.append(dir)
known_paths.add(dircase)
except Exception as exc:
print(f"Error processing line {n:d} of {fullname}:\n",
file=sys.stderr)
import traceback
for record in traceback.format_exception(exc):
for line in record.splitlines():
print(' '+line, file=sys.stderr)
print("\nRemainder of file ignored", file=sys.stderr)
break
if reset:
known_paths = None
return known_paths
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:mod:`site` module now parses ``.pth`` file with UTF-8 first, and
:term:`locale encoding` if ``UnicodeDecodeError`` happened. It supported
only locale encoding before.

0 comments on commit b99f984

Please sign in to comment.