Skip to content

docs: add Cython gotchas section to CLAUDE.md#1679

Merged
bdraco merged 3 commits into
masterfrom
docs-cython-gotchas
May 15, 2026
Merged

docs: add Cython gotchas section to CLAUDE.md#1679
bdraco merged 3 commits into
masterfrom
docs-cython-gotchas

Conversation

@bdraco

@bdraco bdraco commented May 15, 2026

Copy link
Copy Markdown
Member

Summary

Add a Cython gotchas section to CLAUDE.md, mirroring esphome/aioesphomeapi#1653 and adapted to python-zeroconf's code layout. Documents the non-obvious .py + .pxd traps that work in pure-Python mode but break or silently misbehave in shipped Cython wheels — exactly the class of bug where SKIP_CYTHON=1 tests pass while use_cython CI catches it (or worse, it ships).

Details

New section sits between ## Build conventions and ## Reporting security issues, capturing seven traps:

  • cdef-typed module constants are not Python-importable. Pattern: keep both a public MAX_X and a cdef-typed _MAX_X = MAX_X alias so from module import _MAX_X doesn't silently break under Cython.
  • noexcept cdef paths must be pure C. Raising from inside cdef ... noexcept is undefined; Cython prints via WriteUnraisable and continues. Keep noexcept paths to sentinel returns.
  • unsigned int returned through cdef int can flip sign for values with bit 31 set — silently hitting < 0 sentinel branches. Called out specifically for parsers in _protocol/incoming where DNS name pointers and RR length fields cross the signed-int boundary.
  • except * / except? -N adds per-call PyErr_Occurred() checks — negligible cold, measurable hot.
  • Module-level Python int constants force PyLong_AsLong in hot-path comparisons; cdef int in the .pxd makes it a native C compare. Called out for constants in const.py consumed by _protocol/, _cache, _handlers/, _listener.
  • Sign-compare warnings in generated C are real and predict the unsigned -> signed overflow class of bug.
  • CodSpeed regressions only show in the Cython build. Pure-Python tests can pass while production hot paths regress. Use REQUIRE_CYTHON=1 poetry install --only=main,dev to rebuild in place locally.

Aioesphomeapi-specific references in the original section (issue / PR numbers, BLE function names, _handle_error_and_close, _read_varuint) are dropped or generalized. Each trap is grounded in this repo's actual hot-path modules instead.

Docs only; no production code, no tests touched.

Test plan

  • lint and commitlint jobs are green (commit subject is docs: — semantic-release will skip it from the changelog, which is the right behaviour for a docs-only contributor-guide change).
  • test matrix continues to pass unchanged (no code touched).

Mirror of esphome/aioesphomeapi#1653, adapted to python-zeroconf's
code layout (`_protocol/`, `_cache`, `_handlers/`, `_listener`,
`const.py`).

Captures non-obvious `.py` + `.pxd` traps that work fine in pure-
Python mode but break or silently misbehave in the shipped Cython
wheels:

- `cdef`-typed module constants are not Python-importable; the
  pattern is to keep both a public `MAX_X` and a `_MAX_X` alias
  for cdef use.
- `noexcept` cdef paths must be pure C; raising from inside a
  `noexcept` function is undefined / lossy (Cython prints via
  `WriteUnraisable` and continues).
- `unsigned int` returned through `cdef int` can flip sign for
  values with bit 31 set, silently hitting `< 0` sentinel
  branches and bypassing length / offset checks — the parser hot
  path in `_protocol/incoming` is exactly where this class of bug
  bites.
- `except *` / `except? -N` adds per-call `PyErr_Occurred()`
  checks; measurable on hot paths.
- Module-level Python int constants force `PyLong_AsLong` on
  every hot-path comparison; declare `cdef int` in the `.pxd` to
  get a native C compare.
- Sign-compare warnings in generated C predict the unsigned ->
  signed overflow class of bug.
- CodSpeed regressions only show in the Cython build — pure-
  Python tests can pass while production hot paths regress.

Docs only; no production code touched.
@bdraco bdraco requested a review from Copilot May 15, 2026 20:29
Trim and reshape the section added in the previous commit to
match python-zeroconf's reality rather than aioesphomeapi's:

- Drop the `noexcept` cdef bullet and the `except *` / `except? -N`
  bullet. The authored .pxd files in this repo don't use either —
  warning about traps the codebase doesn't reach is noise.
- Fix the `unsigned int` -> `cdef int` bullet. DNS RR length and
  name compression pointer fields are 16-bit and 14-bit, so they
  don't cross the bit-31 signed boundary. Cite TTL instead — it
  is 32-bit (RFC 1035 §3.2.1) and the only field where the trap
  applies — and frame the rule as "stay with `unsigned int` end-
  to-end" since that is the convention `_protocol/incoming.pxd`,
  `_cache.pxd`, and `_handlers/*.pxd` already follow.
- Ground the `cdef`-typed module constants bullet in an actual
  example: `_ANSWER_STRATEGY_POINTER` in
  `_handlers/query_handler.{py,pxd}`.
- Ground the PyLong-conversion bullet in actual examples:
  `_TYPE_PTR`, `_DNS_PTR_MIN_TTL`, `_MIN_SCHEDULED_RECORD_EXPIRATION`
  already use the `cdef unsigned int` alias pattern.
- Drop "(things that have bitten us)" from the heading — most of
  the surviving bullets are preventative for this repo, not
  historical incidents.

Docs only.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a "Cython gotchas" section to CLAUDE.md documenting non-obvious traps in the .py + .pxd setup that work in pure-Python mode but fail or misbehave in shipped Cython wheels.

Changes:

  • New documentation section between "Build conventions" and "Reporting security issues" listing five Cython traps adapted to python-zeroconf's code layout.
  • No production code or tests changed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread CLAUDE.md Outdated
Comment thread CLAUDE.md Outdated
@codecov

codecov Bot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.76%. Comparing base (dd8ede3) to head (76268fa).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1679   +/-   ##
=======================================
  Coverage   99.76%   99.76%           
=======================================
  Files          33       33           
  Lines        3401     3401           
  Branches      461      461           
=======================================
  Hits         3393     3393           
  Misses          5        5           
  Partials        3        3           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq

codspeed-hq Bot commented May 15, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 6 untouched benchmarks


Comparing docs-cython-gotchas (76268fa) with master (cbdc404)1

Open in CodSpeed

Footnotes

  1. No successful run was found on master (dd8ede3) during the generation of this report, so cbdc404 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@bdraco bdraco merged commit 5cfb09d into master May 15, 2026
1 check was pending
@bdraco bdraco deleted the docs-cython-gotchas branch May 15, 2026 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants