Skip to content

Commit 2f1da95

Browse files
authored
fix: add encoding arguments, fixes #1966
* fix: add encoding arguments Signed-off-by: Henry Schreiner <[email protected]> * fix: apply patch from review Signed-off-by: Henry Schreiner <[email protected]> * Update tests/helpers.py * fix: erase the type to get past unreachable error Signed-off-by: Henry Schreiner <[email protected]> --------- Signed-off-by: Henry Schreiner <[email protected]>
1 parent fd8be1d commit 2f1da95

37 files changed

+115
-97
lines changed

benchmark/benchmark.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,16 @@ def file_replace(file_name: Path, old_text: str, new_text: str) -> Iterator[None
148148
"""
149149
file_text = ""
150150
if old_text:
151-
file_text = file_name.read_text()
151+
file_text = file_name.read_text(encoding="utf-8")
152152
if old_text not in file_text:
153153
raise Exception("Old text {old_text!r} not found in {file_name}")
154154
updated_text = file_text.replace(old_text, new_text)
155-
file_name.write_text(updated_text)
155+
file_name.write_text(updated_text, encoding="utf-8")
156156
try:
157157
yield
158158
finally:
159159
if old_text:
160-
file_name.write_text(file_text)
160+
file_name.write_text(file_text, encoding="utf-8")
161161

162162

163163
def file_must_exist(file_name: str, kind: str = "file") -> Path:
@@ -624,7 +624,7 @@ def run_no_coverage(self, env: Env) -> float:
624624
def run_with_coverage(self, env: Env, cov_ver: Coverage) -> float:
625625
env.shell.run_command(f"{env.python} -m pip install {cov_ver.pip_args}")
626626
pforce = Path("force.ini")
627-
pforce.write_text("[run]\nbranch=false\n")
627+
pforce.write_text("[run]\nbranch=false\n", encoding="utf-8")
628628
with env.shell.set_env({"COVERAGE_FORCE_CONFIG": str(pforce.resolve())}):
629629
env.shell.run_command(f"{env.python} -m pytest {self.FAST} --cov")
630630
duration = env.shell.last_duration
@@ -907,13 +907,13 @@ def __init__(
907907

908908
def save_results(self) -> None:
909909
"""Save current results to the JSON file."""
910-
with self.results_file.open("w") as f:
910+
with self.results_file.open("w", encoding="utf-8") as f:
911911
json.dump({" ".join(k): v for k, v in self.result_data.items()}, f)
912912

913913
def load_results(self) -> dict[ResultKey, list[float]]:
914914
"""Load results from the JSON file if it exists."""
915915
if self.results_file.exists():
916-
with self.results_file.open("r") as f:
916+
with self.results_file.open("r", encoding="utf-8") as f:
917917
data: dict[str, list[float]] = json.load(f)
918918
return {
919919
(k.split()[0], k.split()[1], k.split()[2]): v for k, v in data.items()

coverage/html.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def data_filename(fname: str) -> str:
5151

5252
def read_data(fname: str) -> str:
5353
"""Return the contents of a data file of ours."""
54-
with open(data_filename(fname)) as data_file:
54+
with open(data_filename(fname), encoding="utf-8") as data_file:
5555
return data_file.read()
5656

5757

@@ -412,7 +412,7 @@ def make_local_static_report_files(self) -> None:
412412
# .gitignore can't be copied from the source tree because if it was in
413413
# the source tree, it would stop the static files from being checked in.
414414
if self.directory_was_empty:
415-
with open(os.path.join(self.directory, ".gitignore"), "w") as fgi:
415+
with open(os.path.join(self.directory, ".gitignore"), "w", encoding="utf-8") as fgi:
416416
fgi.write("# Created by coverage.py\n*\n")
417417

418418
def should_report(self, analysis: Analysis, index_page: IndexPage) -> bool:
@@ -706,7 +706,7 @@ def read(self) -> None:
706706
"""Read the information we stored last time."""
707707
try:
708708
status_file = os.path.join(self.directory, self.STATUS_FILE)
709-
with open(status_file) as fstatus:
709+
with open(status_file, encoding="utf-8") as fstatus:
710710
status = json.load(fstatus)
711711
except (OSError, ValueError):
712712
# Status file is missing or malformed.
@@ -747,7 +747,7 @@ def write(self) -> None:
747747
for fname, finfo in self.files.items()
748748
},
749749
}
750-
with open(status_file, "w") as fout:
750+
with open(status_file, "w", encoding="utf-8") as fout:
751751
json.dump(status_data, fout, separators=(",", ":"))
752752

753753
def check_global_data(self, *data: Any) -> None:

coverage/pytracer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def __repr__(self) -> str:
126126

127127
def log(self, marker: str, *args: Any) -> None:
128128
"""For hard-core logging of what this tracer is doing."""
129-
with open("/tmp/debug_trace.txt", "a") as f:
129+
with open("/tmp/debug_trace.txt", "a", encoding="utf-8") as f:
130130
f.write(f"{marker} {self.id}[{len(self.data_stack)}]")
131131
if 0: # if you want thread ids..
132132
f.write(".{:x}.{:x}".format( # type: ignore[unreachable]

coverage/sysmon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def log(msg: str) -> None:
104104
# f"{root}-{pid}.out",
105105
# f"{root}-{pid}-{tslug}.out",
106106
]:
107-
with open(filename, "a") as f:
107+
with open(filename, "a", encoding="utf-8") as f:
108108
try:
109109
print(f"{pid}:{tslug}: {msg}", file=f, flush=True)
110110
except UnicodeError:

doc/cog_helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def _read_config(text, fname):
5252
text = textwrap.dedent(text[1:])
5353

5454
os.makedirs("tmp", exist_ok=True)
55-
with open(f"tmp/{fname}", "w") as f:
55+
with open(f"tmp/{fname}", "w", encoding="utf-8") as f:
5656
f.write(text)
5757

5858
config = read_coverage_config(f"tmp/{fname}", warn=cog.error)

doc/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@
215215
# missing, so only use the extension if we are specifically spell-checking.
216216
extensions += ['sphinxcontrib.spelling']
217217
names_file = tempfile.NamedTemporaryFile(mode='w', prefix="coverage_names_", suffix=".txt")
218-
with open("../CONTRIBUTORS.txt") as contributors:
218+
with open("../CONTRIBUTORS.txt", encoding="utf-8") as contributors:
219219
names = set(re.split(r"[^\w']", contributors.read()))
220220
names = [n for n in names if len(n) >= 2 and n[0].isupper()]
221221
names_file.write("\n".join(names))

igor.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def run_tests_with_coverage(core, *runner_args):
196196
# There's an entry in "make clean" to get rid of this file.
197197
pth_dir = sysconfig.get_path("purelib")
198198
pth_path = os.path.join(pth_dir, "zzz_metacov.pth")
199-
with open(pth_path, "w") as pth_file:
199+
with open(pth_path, "w", encoding="utf-8") as pth_file:
200200
pth_file.write("import coverage; coverage.process_startup()\n")
201201

202202
suffix = f"{make_env_id(core)}_{platform.platform()}"
@@ -374,14 +374,14 @@ def get_release_facts():
374374

375375
def update_file(fname, pattern, replacement):
376376
"""Update the contents of a file, replacing pattern with replacement."""
377-
with open(fname) as fobj:
377+
with open(fname, encoding="utf-8") as fobj:
378378
old_text = fobj.read()
379379

380380
new_text = re.sub(pattern, replacement, old_text, count=1)
381381

382382
if new_text != old_text:
383383
print(f"Updating {fname}")
384-
with open(fname, "w") as fobj:
384+
with open(fname, "w", encoding="utf-8") as fobj:
385385
fobj.write(new_text)
386386

387387

lab/branch_trace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def trace(frame, event, arg):
1111
last = this
1212
return trace
1313

14-
code = open(sys.argv[1]).read()
14+
code = open(sys.argv[1], encoding="utf-8").read()
1515
sys.settrace(trace)
1616
exec(code)
1717
print(sorted(pairs))

lab/extract_code.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def f(a, b):
5252
fname, lineno = sys.argv[1:]
5353
lineno = int(lineno)
5454

55-
with open(fname) as code_file:
55+
with open(fname, encoding="utf-8") as code_file:
5656
lines = ["", *code_file]
5757

5858
# Find opening triple-quote

lab/goals.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def main(argv):
6464
print("Need either --file or --group")
6565
return 1
6666

67-
with open("coverage.json") as j:
67+
with open("coverage.json", encoding="utf-8") as j:
6868
data = json.load(j)
6969
all_files = list(data["files"].keys())
7070
selected = select_files(all_files, args.pattern)

lab/run_sysmon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
print(sys.version)
1010
the_program = sys.argv[1]
1111

12-
code = compile(open(the_program).read(), filename=the_program, mode="exec")
12+
code = compile(open(the_program, encoding="utf-8").read(), filename=the_program, mode="exec")
1313

1414
my_id = sys.monitoring.COVERAGE_ID
1515
sys.monitoring.use_tool_id(my_id, "run_sysmon.py")

lab/run_trace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ def trace(frame, event, arg):
3232
print(sys.version)
3333
the_program = sys.argv[1]
3434

35-
code = open(the_program).read()
35+
code = open(the_program, encoding="utf-8").read()
3636
sys.settrace(trace)
3737
exec(code)

lab/show_pyc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def show_pyc_file(fname):
4444
show_code(code)
4545

4646
def show_py_file(fname):
47-
text = open(fname).read().replace('\r\n', '\n')
47+
text = open(fname, encoding="utf-8").read().replace('\r\n', '\n')
4848
show_py_text(text, fname=fname)
4949

5050
def show_py_text(text, fname="<string>"):

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@
3535
"""
3636

3737
cov_ver_py = os.path.join(os.path.split(__file__)[0], "coverage/version.py")
38-
with open(cov_ver_py) as version_file:
38+
with open(cov_ver_py, encoding="utf-8") as version_file:
3939
# __doc__ will be overwritten by version.py.
4040
doc = __doc__
4141
# Keep pylint happy.
4242
__version__ = __url__ = version_info = ""
4343
# Execute the code in version.py.
4444
exec(compile(version_file.read(), cov_ver_py, "exec", dont_inherit=True))
4545

46-
with open("README.rst") as readme:
46+
with open("README.rst", encoding="utf-8") as readme:
4747
readme_text = readme.read()
4848

4949
temp_url = __url__.replace("readthedocs", "@@")

tests/balance_xdist_plugin.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def pytest_sessionstart(self, session):
7171
if self.worker == "none":
7272
if tests_csv_dir.exists():
7373
for csv_file in tests_csv_dir.iterdir():
74-
with csv_file.open(newline="") as fcsv:
74+
with csv_file.open(newline="", encoding="utf-8") as fcsv:
7575
reader = csv.reader(fcsv)
7676
for row in reader:
7777
self.times[row[1]] += float(row[3])
@@ -81,7 +81,7 @@ def write_duration_row(self, item, phase, duration):
8181
"""Helper to write a row to the tracked-test csv file."""
8282
if self.running_all:
8383
self.tests_csv.parent.mkdir(parents=True, exist_ok=True)
84-
with self.tests_csv.open("a", newline="") as fcsv:
84+
with self.tests_csv.open("a", newline="", encoding="utf-8") as fcsv:
8585
csv.writer(fcsv).writerow([self.worker, item.nodeid, phase, duration])
8686

8787
@pytest.hookimpl(hookwrapper=True)
@@ -171,7 +171,7 @@ def show_worker_times(): # pragma: debugging
171171
tests_csv_dir = Path("tmp/tests_csv")
172172

173173
for csv_file in tests_csv_dir.iterdir():
174-
with csv_file.open(newline="") as fcsv:
174+
with csv_file.open(newline="", encoding="utf-8") as fcsv:
175175
reader = csv.reader(fcsv)
176176
for row in reader:
177177
worker = row[0]

tests/conftest.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ def pytest_sessionstart() -> None:
104104
# Create a .pth file for measuring subprocess coverage.
105105
pth_dir = find_writable_pth_directory()
106106
assert pth_dir
107-
(pth_dir / "subcover.pth").write_text("import coverage; coverage.process_startup()\n")
107+
sub_dir = pth_dir / "subcover.pth"
108+
sub_dir.write_text("import coverage; coverage.process_startup()\n", encoding="utf-8")
108109
# subcover.pth is deleted by pytest_sessionfinish below.
109110

110111

@@ -137,7 +138,7 @@ def find_writable_pth_directory() -> Path | None:
137138
for pth_dir in possible_pth_dirs(): # pragma: part covered
138139
try_it = pth_dir / f"touch_{WORKER}.it"
139140
try:
140-
try_it.write_text("foo")
141+
try_it.write_text("foo", encoding="utf-8")
141142
except OSError: # pragma: cant happen
142143
continue
143144

tests/goldtest.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ def save_mismatch(f: str) -> None:
5959
save_path = expected_dir.replace(os_sep("/gold/"), os_sep("/actual/"))
6060
os.makedirs(save_path, exist_ok=True)
6161
save_file = os.path.join(save_path, f)
62-
with open(save_file, "w") as savef:
63-
with open(os.path.join(actual_dir, f)) as readf:
62+
with open(save_file, "w", encoding="utf-8") as savef:
63+
with open(os.path.join(actual_dir, f), encoding="utf-8") as readf:
6464
savef.write(readf.read())
6565
print(os_sep(f"Saved actual output to '{save_file}': see tests/gold/README.rst"))
6666

@@ -70,13 +70,13 @@ def save_mismatch(f: str) -> None:
7070
text_diff = []
7171
for f in diff_files:
7272
expected_file = os.path.join(expected_dir, f)
73-
with open(expected_file) as fobj:
73+
with open(expected_file, encoding="utf-8") as fobj:
7474
expected = fobj.read()
7575
if expected_file.endswith(".xml"):
7676
expected = canonicalize_xml(expected)
7777

7878
actual_file = os.path.join(actual_dir, f)
79-
with open(actual_file) as fobj:
79+
with open(actual_file, encoding="utf-8") as fobj:
8080
actual = fobj.read()
8181
if actual_file.endswith(".xml"):
8282
actual = canonicalize_xml(actual)
@@ -114,7 +114,7 @@ def contains(filename: str, *strlist: str) -> None:
114114
115115
"""
116116
__tracebackhide__ = True # pytest, please don't show me this function.
117-
with open(filename) as fobj:
117+
with open(filename, encoding="utf-8") as fobj:
118118
text = fobj.read()
119119
for s in strlist:
120120
assert s in text, f"Missing content in {filename}: {s!r}"
@@ -128,7 +128,7 @@ def contains_rx(filename: str, *rxlist: str) -> None:
128128
129129
"""
130130
__tracebackhide__ = True # pytest, please don't show me this function.
131-
with open(filename) as fobj:
131+
with open(filename, encoding="utf-8") as fobj:
132132
lines = fobj.readlines()
133133
for rx in rxlist:
134134
assert any(re.search(rx, line) for line in lines), (
@@ -144,7 +144,7 @@ def contains_any(filename: str, *strlist: str) -> None:
144144
145145
"""
146146
__tracebackhide__ = True # pytest, please don't show me this function.
147-
with open(filename) as fobj:
147+
with open(filename, encoding="utf-8") as fobj:
148148
text = fobj.read()
149149
for s in strlist:
150150
if s in text:
@@ -161,7 +161,7 @@ def doesnt_contain(filename: str, *strlist: str) -> None:
161161
162162
"""
163163
__tracebackhide__ = True # pytest, please don't show me this function.
164-
with open(filename) as fobj:
164+
with open(filename, encoding="utf-8") as fobj:
165165
text = fobj.read()
166166
for s in strlist:
167167
assert s not in text, f"Forbidden content in {filename}: {s!r}"

tests/helpers.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import re
1616
import shutil
1717
import subprocess
18+
import sys
1819
import textwrap
1920
import warnings
2021

@@ -42,10 +43,18 @@ def run_command(cmd: str) -> tuple[int, str]:
4243
# Subprocesses are expensive, but convenient, and so may be over-used in
4344
# the test suite. Use these lines to get a list of the tests using them:
4445
if 0: # pragma: debugging
45-
with open("/tmp/processes.txt", "a") as proctxt: # type: ignore[unreachable]
46+
pth = "/tmp/processes.txt" # type: ignore[unreachable]
47+
with open(pth, "a", encoding="utf-8") as proctxt:
4648
print(os.getenv("PYTEST_CURRENT_TEST", "unknown"), file=proctxt, flush=True)
4749

48-
encoding = os.device_encoding(1) or locale.getpreferredencoding()
50+
# Type checking trick due to "unreachable" being set
51+
_locale_type_erased: Any = locale
52+
53+
encoding = os.device_encoding(1) or (
54+
_locale_type_erased.getpreferredencoding()
55+
if sys.version_info < (3, 11)
56+
else _locale_type_erased.getencoding()
57+
)
4958

5059
# In some strange cases (PyPy3 in a virtualenv!?) the stdout encoding of
5160
# the subprocess is set incorrectly to ascii. Use an environment variable
@@ -113,7 +122,7 @@ def make_file(
113122

114123
if text and basename.endswith(".py") and SHOW_DIS: # pragma: debugging
115124
os.makedirs("/tmp/dis", exist_ok=True)
116-
with open(f"/tmp/dis/{basename}.dis", "w") as fdis:
125+
with open(f"/tmp/dis/{basename}.dis", "w", encoding="utf-8") as fdis:
117126
print(f"# {os.path.abspath(filename)}", file=fdis)
118127
cur_test = os.getenv("PYTEST_CURRENT_TEST", "unknown")
119128
print(f"# PYTEST_CURRENT_TEST = {cur_test}", file=fdis)

tests/osinfo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def _VmB(key: str) -> int:
6464
"""Read the /proc/PID/status file to find memory use."""
6565
try:
6666
# Get pseudo file /proc/<pid>/status
67-
with open(f"/proc/{os.getpid()}/status") as t:
67+
with open(f"/proc/{os.getpid()}/status", encoding="utf-8") as t:
6868
v = t.read()
6969
except OSError: # pragma: cant happen
7070
return 0 # non-Linux?

0 commit comments

Comments
 (0)