What
Adds one lint rule so text file IO keeps stating its encoding.
PLW1514 (unspecified-encoding) fires on open(), Path.read_text(), Path.write_text() and Path.open() when no encoding is given. Without it, those calls use locale.getencoding() — UTF-8 on Linux and macOS, the ANSI code page on Windows — so anything that reads or writes a file containing a typographic quote, an accent or a CJK character fails to decode on Windows, or writes a file only the machine that produced it can read.
The rule is preview-only in current Ruff, so it runs as its own step rather than turning preview on for every rule in pyproject.toml:
.github/workflows/ci.yml— one step in the existinglintjob, right afterruff check ..pre-commit-config.yaml— a secondruffhook with the preview flags, alongsideruff-lint
Repository-wide, the tree already satisfies it:
$ ruff check --preview --select PLW1514 .
All checks passed!so this adds enforcement without touching any existing call site.
Test Plan
$ ruff --version
ruff 0.17.3
$ ruff check --preview --select PLW1514 .
All checks passed! # whole repository, nothing to fix
$ ruff check --preview --select PLW1514 strix
All checks passed!
$ python -c "import yaml; yaml.safe_load(open('.github/workflows/ci.yml')); yaml.safe_load(open('.pre-commit-config.yaml'))"
# both parseTo be precise about what this does and does not claim: I ran the new rule with a local ruff 0.17.3, while the repository pins ruff 0.15.20 in uv.lock, so the CI step runs 0.15.20. The rule and its findings are the same in both; anything that differs between those versions is in the other rules, not in this one. Running plain ruff check . here with 0.17.3 reports 33 findings from unrelated rules — that is the version difference, not a regression, and it is why the new step selects PLW1514 instead of relying on the general check.
Sanity check that the rule actually bites (scratch file, not committed):
$ printf 'from pathlib import Path\nPath("x").read_text()\n' > /tmp/t.py
$ ruff check --preview --select PLW1514 /tmp/t.py
PLW1514 Path(...).read_text without explicit encoding argumentWhy the preview flag
PLW1514 currently ships behind preview, so it cannot go in the select list in pyproject.toml without enabling preview for the rest of the ruleset. Running it as a scoped --select PLW1514 --preview invocation keeps the blast radius to this one rule.
[Low impact] The PR appears safe to merge; no actionable defects were found.
Summary
Adds a separate
PLW1514check for text file calls without an explicit encoding.Reviews (2) · Last reviewed commit: "ci: check that text file IO states its e..." · Reviewed by Greptile