Replaces the removed normalize_line_endings rewriter: release.py now
fails listing any text file containing CRLF instead of silently
rewriting it. .gitattributes (eol=lf) remains the preventive half.
release.py previously ran the code generator, 'ruff check --fix',
'ruff format', and line-ending normalization before building. Any drift
rewrote tracked files, dirtying the checkout and turning the release
into a dev version (the v0.10.6 PyPI 400). Generation and linting are
now validation-only:
- tools/generate.py gains a --check mode that reports stale generated
files without writing (comparing Python content in ruff-formatted
form, matching what write + format would produce)
- release.py runs generate --check, ruff check (no --fix), and
ruff format --check, failing with remediation hints
- normalize_line_endings() is removed; .gitattributes keeps checkouts LF
The tagged v0.10.6 CI build produced wheels versioned
0.10.7.dev0+g503ce8e49.d20261004: setup.py was not ruff-format-clean, so
release.py's own 'ruff format .' step rewrote it, dirtying the checkout
before setuptools_scm ran. PyPI then rejected the local version segment
with HTTP 400.
- ruff-format setup.py
- release.py: on a v*-tagged HEAD, fail before building if the version
is not a clean release, printing the dirty files
- add .gitattributes (eol=lf) so Windows checkouts can't dirty the tree
via normalize_line_endings either
os.open() on Windows defaults to O_TEXT, so the CRT translated \r\n in
binary ciphertext: writes grew, offsets shifted, reads came up short and
the RAF callbacks failed with EIO (probe/read/write depending on where
a 0x0A byte landed). Pass O_BINARY where it exists.
Also reconfigure stdout/stderr to UTF-8 in tools/release.py so the
✓/✗/⚠ summary lines don't crash on cp1252 Windows consoles.
- requires-python >= 3.12; abi3 limited API tag cp310 -> cp312
- util.Buffer now imported directly from collections.abc (no fallback)
- release.py: ABI3 wheel covers 3.12-3.15; PyPy wheels dropped (PyPy
has no 3.12 support yet)
Matrix job builds and tests wheels on linux/macos/windows (no Gitea
release, unlike mediahive); publish job uploads the merged dist/ to PyPI
only after all platforms succeed. release.py gains --no-upload for the
matrix jobs.