Skip to content

Commit e8552eb

Browse files
committed
centralize encoding_for_open
1 parent b8dd8b0 commit e8552eb

23 files changed

+148
-158
lines changed

pkg_resources/__init__.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import time
2828
import re
2929
import types
30+
import locale
31+
import sys
3032
from typing import Protocol
3133
import zipfile
3234
import zipimport
@@ -48,7 +50,6 @@
4850
import importlib
4951
import importlib.machinery
5052
from pkgutil import get_importer
51-
5253
import _imp
5354

5455
# capture these to bypass sandboxing
@@ -73,14 +74,22 @@
7374

7475
from pkg_resources.extern import platformdirs
7576
from pkg_resources.extern import packaging
76-
import locale
7777

7878
__import__('pkg_resources.extern.packaging.version')
7979
__import__('pkg_resources.extern.packaging.specifiers')
8080
__import__('pkg_resources.extern.packaging.requirements')
8181
__import__('pkg_resources.extern.packaging.markers')
8282
__import__('pkg_resources.extern.packaging.utils')
8383

84+
encoding_for_open = (
85+
"locale" if sys.version_info >= (3, 10) else locale.getpreferredencoding(False)
86+
)
87+
"""
88+
This variable exists to centralize calls to `getpreferredencoding`
89+
to reduce the amount of `EncodingWarning` in tests logs.
90+
"""
91+
92+
8493
# declare some globals that will be defined later to
8594
# satisfy the linters.
8695
require = None
@@ -1539,9 +1548,7 @@ def run_script(self, script_name, namespace):
15391548
script_filename = self._fn(self.egg_info, script)
15401549
namespace['__file__'] = script_filename
15411550
if os.path.exists(script_filename):
1542-
with open(
1543-
script_filename, encoding=locale.getpreferredencoding(False)
1544-
) as fid:
1551+
with open(script_filename, encoding=encoding_for_open) as fid:
15451552
source = fid.read()
15461553
code = compile(source, script_filename, 'exec')
15471554
exec(code, namespace, namespace)
@@ -2192,7 +2199,7 @@ def non_empty_lines(path):
21922199
"""
21932200
Yield non-empty lines from file at path
21942201
"""
2195-
with open(path, encoding=locale.getpreferredencoding(False)) as f:
2202+
with open(path, encoding=encoding_for_open) as f:
21962203
for line in f:
21972204
line = line.strip()
21982205
if line:

pkg_resources/tests/test_pkg_resources.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
DistInfoDistribution,
1717
Distribution,
1818
EggInfoDistribution,
19+
encoding_for_open,
1920
)
2021

2122
import pytest
2223

2324
import pkg_resources
24-
import locale
2525

2626

2727
class EggRemover(str):
@@ -111,13 +111,13 @@ def test_resource_filename_rewrites_on_change(self):
111111
filename = zp.get_resource_filename(manager, 'data.dat')
112112
actual = datetime.datetime.fromtimestamp(os.stat(filename).st_mtime)
113113
assert actual == self.ref_time
114-
f = open(filename, 'w', encoding=locale.getpreferredencoding(False))
114+
f = open(filename, 'w', encoding=encoding_for_open)
115115
f.write('hello, world?')
116116
f.close()
117117
ts = self.ref_time.timestamp()
118118
os.utime(filename, (ts, ts))
119119
filename = zp.get_resource_filename(manager, 'data.dat')
120-
with open(filename, encoding=locale.getpreferredencoding(False)) as f:
120+
with open(filename, encoding=encoding_for_open) as f:
121121
assert f.read() == 'hello, world!'
122122
manager.cleanup_resources()
123123

setuptools/command/bdist_egg.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
from setuptools.extension import Library
1515
from setuptools import Command
1616
from .._path import ensure_directory
17+
from ..compat.encoding import encoding_for_open
1718

1819
from sysconfig import get_path, get_python_version
19-
import locale
2020

2121

2222
def _get_purelib():
@@ -55,7 +55,7 @@ def __bootstrap__():
5555
__bootstrap__()
5656
"""
5757
).lstrip()
58-
with open(pyfile, 'w', encoding=locale.getpreferredencoding(False)) as f:
58+
with open(pyfile, 'w', encoding=encoding_for_open) as f:
5959
f.write(_stub_template % resource)
6060

6161

@@ -201,9 +201,7 @@ def run(self): # noqa: C901 # is too complex (14) # FIXME
201201
log.info("writing %s", native_libs)
202202
if not self.dry_run:
203203
ensure_directory(native_libs)
204-
libs_file = open(
205-
native_libs, 'wt', encoding=locale.getpreferredencoding(False)
206-
)
204+
libs_file = open(native_libs, 'wt', encoding=encoding_for_open)
207205
libs_file.write('\n'.join(all_outputs))
208206
libs_file.write('\n')
209207
libs_file.close()
@@ -353,7 +351,7 @@ def write_safety_flag(egg_dir, safe):
353351
if safe is None or bool(safe) != flag:
354352
os.unlink(fn)
355353
elif safe is not None and bool(safe) == flag:
356-
f = open(fn, 'wt', encoding=locale.getpreferredencoding(False))
354+
f = open(fn, 'wt', encoding=encoding_for_open)
357355
f.write('\n')
358356
f.close()
359357

setuptools/command/build_ext.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import os
22
import sys
33
import itertools
4-
import locale
54
from importlib.machinery import EXTENSION_SUFFIXES
65
from importlib.util import cache_from_source as _compiled_file_name
76
from typing import Dict, Iterator, List, Tuple
@@ -15,6 +14,8 @@
1514
from setuptools.errors import BaseError
1615
from setuptools.extension import Extension, Library
1716

17+
from ..compat.encoding import encoding_for_open
18+
1819
try:
1920
# Attempt to use Cython for building extensions, if available
2021
from Cython.Distutils.build_ext import build_ext as _build_ext
@@ -341,7 +342,7 @@ def _write_stub_file(self, stub_file: str, ext: Extension, compile=False):
341342
if compile and os.path.exists(stub_file):
342343
raise BaseError(stub_file + " already exists! Please delete.")
343344
if not self.dry_run:
344-
f = open(stub_file, 'w', encoding=locale.getpreferredencoding(False))
345+
f = open(stub_file, 'w', encoding=encoding_for_open)
345346
f.write(
346347
'\n'.join([
347348
"def __bootstrap__():",

setuptools/command/develop.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from setuptools import _path
1010
from setuptools import namespaces
1111
import setuptools
12-
import locale
12+
13+
from ..compat.encoding import encoding_for_open
1314

1415

1516
class develop(namespaces.DevelopInstaller, easy_install):
@@ -120,9 +121,7 @@ def install_for_development(self):
120121
# create an .egg-link in the installation dir, pointing to our egg
121122
log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)
122123
if not self.dry_run:
123-
with open(
124-
self.egg_link, "w", encoding=locale.getpreferredencoding(False)
125-
) as f:
124+
with open(self.egg_link, "w", encoding=encoding_for_open) as f:
126125
f.write(self.egg_path + "\n" + self.setup_path)
127126
# postprocess the installed distro, fixing up .pth, installing scripts,
128127
# and handling requirements
@@ -131,9 +130,7 @@ def install_for_development(self):
131130
def uninstall_link(self):
132131
if os.path.exists(self.egg_link):
133132
log.info("Removing %s (link to %s)", self.egg_link, self.egg_base)
134-
egg_link_file = open(
135-
self.egg_link, encoding=locale.getpreferredencoding(False)
136-
)
133+
egg_link_file = open(self.egg_link, encoding=encoding_for_open)
137134
contents = [line.rstrip() for line in egg_link_file]
138135
egg_link_file.close()
139136
if contents not in ([self.egg_path], [self.egg_path, self.setup_path]):
@@ -161,7 +158,7 @@ def install_egg_scripts(self, dist):
161158
for script_name in self.distribution.scripts or []:
162159
script_path = os.path.abspath(convert_path(script_name))
163160
script_name = os.path.basename(script_path)
164-
with open(script_path, encoding=locale.getpreferredencoding(False)) as strm:
161+
with open(script_path, encoding=encoding_for_open) as strm:
165162
script_text = strm.read()
166163
self.install_script(dist, script_name, script_text, script_path)
167164

setuptools/command/easy_install.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,9 @@
7575
)
7676
import pkg_resources
7777
from ..compat import py311
78+
from ..compat.encoding import encoding_for_open
7879
from .._path import ensure_directory
7980
from ..extern.jaraco.text import yield_lines
80-
import locale
81-
8281

8382
# Turn on PEP440Warnings
8483
warnings.filterwarnings("default", category=pkg_resources.PEP440Warning)
@@ -492,7 +491,7 @@ def check_site_dir(self): # noqa: C901 # is too complex (12) # FIXME
492491
try:
493492
if test_exists:
494493
os.unlink(testfile)
495-
open(testfile, 'w', encoding=locale.getpreferredencoding(False)).close()
494+
open(testfile, 'w', encoding=encoding_for_open).close()
496495
os.unlink(testfile)
497496
except OSError:
498497
self.cant_write_to_target()
@@ -589,7 +588,7 @@ def check_pth_processing(self):
589588
os.unlink(ok_file)
590589
dirname = os.path.dirname(ok_file)
591590
os.makedirs(dirname, exist_ok=True)
592-
f = open(pth_file, 'w', encoding=locale.getpreferredencoding(False))
591+
f = open(pth_file, 'w', encoding=encoding_for_open)
593592
except OSError:
594593
self.cant_write_to_target()
595594
else:
@@ -1017,7 +1016,7 @@ def install_exe(self, dist_filename, tmpdir):
10171016

10181017
# Write EGG-INFO/PKG-INFO
10191018
if not os.path.exists(pkg_inf):
1020-
f = open(pkg_inf, 'w', encoding=locale.getpreferredencoding(False))
1019+
f = open(pkg_inf, 'w', encoding=encoding_for_open)
10211020
f.write('Metadata-Version: 1.0\n')
10221021
for k, v in cfg.items('metadata'):
10231022
if k != 'target_version':
@@ -1088,7 +1087,7 @@ def process(src, dst):
10881087
if locals()[name]:
10891088
txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt')
10901089
if not os.path.exists(txt):
1091-
f = open(txt, 'w', encoding=locale.getpreferredencoding(False))
1090+
f = open(txt, 'w', encoding=encoding_for_open)
10921091
f.write('\n'.join(locals()[name]) + '\n')
10931092
f.close()
10941093

@@ -1278,7 +1277,7 @@ def update_pth(self, dist): # noqa: C901 # is too complex (11) # FIXME
12781277
filename = os.path.join(self.install_dir, 'setuptools.pth')
12791278
if os.path.islink(filename):
12801279
os.unlink(filename)
1281-
with open(filename, 'wt', encoding=locale.getpreferredencoding(False)) as f:
1280+
with open(filename, 'wt', encoding=encoding_for_open) as f:
12821281
f.write(self.pth_file.make_relative(dist.location) + '\n')
12831282

12841283
def unpack_progress(self, src, dst):
@@ -1504,9 +1503,7 @@ def expand_paths(inputs): # noqa: C901 # is too complex (11) # FIXME
15041503
continue
15051504

15061505
# Read the .pth file
1507-
f = open(
1508-
os.path.join(dirname, name), encoding=locale.getpreferredencoding(False)
1509-
)
1506+
f = open(os.path.join(dirname, name), encoding=encoding_for_open)
15101507
lines = list(yield_lines(f))
15111508
f.close()
15121509

@@ -1622,7 +1619,7 @@ def _load_raw(self):
16221619
paths = []
16231620
dirty = saw_import = False
16241621
seen = dict.fromkeys(self.sitedirs)
1625-
f = open(self.filename, 'rt', encoding=locale.getpreferredencoding(False))
1622+
f = open(self.filename, 'rt', encoding=encoding_for_open)
16261623
for line in f:
16271624
path = line.rstrip()
16281625
# still keep imports and empty/commented lines for formatting
@@ -1693,9 +1690,7 @@ def save(self):
16931690
data = '\n'.join(lines) + '\n'
16941691
if os.path.islink(self.filename):
16951692
os.unlink(self.filename)
1696-
with open(
1697-
self.filename, 'wt', encoding=locale.getpreferredencoding(False)
1698-
) as f:
1693+
with open(self.filename, 'wt', encoding=encoding_for_open) as f:
16991694
f.write(data)
17001695
elif os.path.exists(self.filename):
17011696
log.debug("Deleting empty %s", self.filename)

setuptools/command/setopt.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import configparser
77

88
from setuptools import Command
9-
import locale
9+
10+
from ..compat.encoding import encoding_for_open
1011

1112
__all__ = ['config_file', 'edit_config', 'option_base', 'setopt']
1213

@@ -63,7 +64,7 @@ def edit_config(filename, settings, dry_run=False):
6364

6465
log.info("Writing %s", filename)
6566
if not dry_run:
66-
with open(filename, 'w', encoding=locale.getpreferredencoding(False)) as f:
67+
with open(filename, 'w', encoding=encoding_for_open) as f:
6768
opts.write(f)
6869

6970

setuptools/compat/encoding.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import locale
2+
import sys
3+
4+
5+
encoding_for_open = (
6+
"locale" if sys.version_info >= (3, 10) else locale.getpreferredencoding(False)
7+
)
8+
"""
9+
This variable exists to centralize calls to `getpreferredencoding`
10+
to reduce the amount of `EncodingWarning` in tests logs.
11+
"""
12+
13+
encoding_for_pth = locale.getencoding() if sys.version_info >= (3, 11) else None
14+
"""
15+
When working with ``.pth`` files, let's ignore UTF-8 mode (``PYTHONUTF8`` or ``python -X utf8``)
16+
Ref.: https://peps.python.org/pep-0686/#locale-getencoding
17+
18+
``.pth`` files break with UTF-8 encoding.
19+
https://github.com/python/cpython/issues/77102#issuecomment-1568457039
20+
21+
Until Python 3.11 `TextIOWrapper` still used UTF-8 even with ``encoding='locale'``
22+
Ref.: https://peps.python.org/pep-0686/#fixing-encoding-locale-option
23+
"""

setuptools/dist.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from distutils.fancy_getopt import translate_longopt
2323
from distutils.util import strtobool
2424

25+
2526
from .extern.more_itertools import partition, unique_everseen
2627
from .extern.ordered_set import OrderedSet
2728
from .extern.packaging.markers import InvalidMarker, Marker
@@ -34,10 +35,10 @@
3435
from . import command as _ # noqa -- imported for side-effects
3536
from ._importlib import metadata
3637
from .config import setupcfg, pyprojecttoml
38+
from .compat.encoding import encoding_for_open
3739
from .discovery import ConfigDiscovery
3840
from .monkey import get_unpatched
3941
from .warnings import InformationOnly, SetuptoolsDeprecationWarning
40-
import locale
4142

4243

4344
sequence = tuple, list
@@ -682,9 +683,7 @@ def get_egg_cache_dir(self):
682683
os.mkdir(egg_cache_dir)
683684
windows_support.hide_file(egg_cache_dir)
684685
readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt')
685-
with open(
686-
readme_txt_filename, 'w', encoding=locale.getpreferredencoding(False)
687-
) as f:
686+
with open(readme_txt_filename, 'w', encoding=encoding_for_open) as f:
688687
f.write(
689688
'This directory contains eggs that were downloaded '
690689
'by setuptools to build, test, and run plug-ins.\n\n'

setuptools/namespaces.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import os
22
from distutils import log
33
import itertools
4-
import locale
54

5+
from .compat.encoding import encoding_for_open
66

77
flatten = itertools.chain.from_iterable
88

@@ -24,7 +24,7 @@ def install_namespaces(self):
2424
list(lines)
2525
return
2626

27-
with open(filename, 'wt', encoding=locale.getpreferredencoding(False)) as f:
27+
with open(filename, 'wt', encoding=encoding_for_open) as f:
2828
f.writelines(lines)
2929

3030
def uninstall_namespaces(self):

0 commit comments

Comments
 (0)