Skip to content

Commit 8b22a0a

Browse files
authored
Fix UnicodeDecodeError in the top-level tooling on non-UTF-8 locales (#299)
The tooling called read_text()/write_text() with no encoding=, so Python fell back to the locale encoding. Four model LICENSE files contain UTF-8 curly quotes whose 0x9d byte is undefined in cp1252, so `make gallery` and the regenerate-license pre-commit hook crashed on Windows.
1 parent da76818 commit 8b22a0a

4 files changed

Lines changed: 20 additions & 12 deletions

File tree

format_xml.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,14 @@ def main() -> int:
170170

171171
failed: list[pathlib.Path] = []
172172
for p in args.paths:
173-
text = p.read_text()
173+
text = p.read_text(encoding='utf-8')
174174
formatted = format_xml(text)
175175
if args.check:
176176
if text != formatted:
177177
failed.append(p)
178178
elif args.write:
179179
if text != formatted:
180-
p.write_text(formatted)
180+
p.write_text(formatted, encoding='utf-8')
181181
else:
182182
sys.stdout.write(formatted)
183183

generate_gallery.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,13 @@ def display_name(robot):
7676
maker = robot.split('/')[0]
7777
readme = pathlib.Path(f'{maker}/README.md')
7878
if readme.exists():
79-
title = readme.read_text().splitlines()[0].strip().lstrip('#').strip()
79+
title = (
80+
readme.read_text(encoding='utf-8')
81+
.splitlines()[0]
82+
.strip()
83+
.lstrip('#')
84+
.strip()
85+
)
8086
title = _README_TITLE_SUFFIX.sub('', title).rstrip()
8187
if title:
8288
return title
@@ -382,7 +388,7 @@ def sort_func(xml):
382388

383389
def detect_license(license_path):
384390
"""Identify the SPDX license name from the LICENSE file contents."""
385-
text = pathlib.Path(license_path).read_text()
391+
text = pathlib.Path(license_path).read_text(encoding='utf-8')
386392
lower = text.lower()
387393
if 'apache license' in lower and 'version 2' in lower:
388394
return 'Apache-2.0'
@@ -441,7 +447,7 @@ def write_gallery_to_readme(rendered, dofs, readme_path='README.md'):
441447
sections.append(table)
442448

443449
body = '\n\n'.join(sections)
444-
readme = pathlib.Path(readme_path).read_text()
450+
readme = pathlib.Path(readme_path).read_text(encoding='utf-8')
445451
pattern = re.compile(
446452
re.escape(MODELS_BEGIN) + r'.*?' + re.escape(MODELS_END), re.DOTALL
447453
)
@@ -450,7 +456,7 @@ def write_gallery_to_readme(rendered, dofs, readme_path='README.md'):
450456
f'models markers not found in {readme_path}; expected\n {MODELS_BEGIN}\n {MODELS_END}'
451457
)
452458
new = pattern.sub(f'{MODELS_BEGIN}\n\n{body}\n\n{MODELS_END}', readme)
453-
pathlib.Path(readme_path).write_text(new)
459+
pathlib.Path(readme_path).write_text(new, encoding='utf-8')
454460

455461

456462
def main(argv):

regenerate_license.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ def get_base_license(root: pathlib.Path) -> str:
4545
"""
4646
opensource_license = root / 'opensource' / 'LICENSE'
4747
if opensource_license.exists():
48-
return opensource_license.read_text()
48+
return opensource_license.read_text(encoding='utf-8')
4949

5050
# Fall back to extracting from the existing concatenated LICENSE.
5151
existing = root / 'LICENSE'
5252
if existing.exists():
53-
sections = existing.read_text().split(HLINE + '\n')
53+
sections = existing.read_text(encoding='utf-8').split(HLINE + '\n')
5454
if sections:
5555
return sections[-1]
5656

@@ -84,7 +84,7 @@ def generate_license(root: pathlib.Path) -> str:
8484
out += HLINE
8585
out += f"License for contents in the directory '{lf.parent.name}/'\n"
8686
out += HLINE + '\n'
87-
out += lf.read_text() + '\n\n'
87+
out += lf.read_text(encoding='utf-8') + '\n\n'
8888

8989
out += HLINE
9090
out += 'The following license applies to all other contents\n'
@@ -115,7 +115,7 @@ def main():
115115
print('FAIL: LICENSE file does not exist.', file=sys.stderr)
116116
sys.exit(1)
117117

118-
current = license_path.read_text()
118+
current = license_path.read_text(encoding='utf-8')
119119
if current != generated:
120120
print(
121121
'FAIL: LICENSE file is out of date. '
@@ -127,7 +127,7 @@ def main():
127127
print('OK: LICENSE file is up to date.')
128128
return
129129

130-
license_path.write_text(generated)
130+
license_path.write_text(generated, encoding='utf-8')
131131
print(f'LICENSE file regenerated at {license_path}')
132132

133133

test/model_dir_test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ class ContributorsTest(absltest.TestCase):
8484
"""Checks CONTRIBUTORS.md sections are sorted alphabetically by first name."""
8585

8686
def test_sorted(self) -> None:
87-
contributors = (_ROOT_DIR / 'CONTRIBUTORS.md').read_text().splitlines()
87+
contributors = (
88+
(_ROOT_DIR / 'CONTRIBUTORS.md').read_text(encoding='utf-8').splitlines()
89+
)
8890

8991
# Each section is a contiguous block of lines starting with "- ".
9092
section_start = None

0 commit comments

Comments
 (0)