Skip to content

Reject aux notes that can't be written in wrann - #605

Merged
tompollard merged 1 commit into
MIT-LCP:mainfrom
TheNetherWatcher:wrann-aux-note-check
Oct 31, 2026
Merged

tompollard merged 1 commit into
MIT-LCP:mainfrom
TheNetherWatcher:wrann-aux-note-check

Conversation

@TheNetherWatcher

Copy link
Copy Markdown
Contributor

wrann writes each aux note as a one-byte length followed by one byte per character, but it doesn't check that the note fits. The bytes are cast to uint8, so values above 255 wrap silently:

wfdb.wrann("a", "atr", sample=np.array([1, 2]), symbol=["+", "N"], aux_note=["x" * 256, ""])
len(wfdb.rdann("a", "atr").sample)  # 130 annotations instead of 2

wfdb.wrann("a", "atr", sample=np.array([1]), symbol=["+"], aux_note=["(€)"])
wfdb.rdann("a", "atr").aux_note  # ['(¬)']

rdann decodes each byte with chr, i.e. as Latin-1, so the notes that round-trip are those of at most 255 Latin-1 characters (the length byte also limits notes to 255 bytes in the WFDB format).

Changes:

  • check_field now raises a ValueError for an aux note that is longer than 255 characters or has characters outside Latin-1, before anything is written.
  • field2bytes writes value.encode("latin-1") and takes the length from the encoded bytes. For valid notes the output is the same as before.
  • The wrann docstring mentions the limits, and there's a changelog entry.

Tests: a round trip with a 255-character note and Latin-1 characters (°, ü), and both kinds of invalid note raising the error without creating a file. The invalid-note tests fail on main. pytest -m "not network" passes (99 tests), and the docs build passes.

@tompollard tompollard left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks, this looks good! I checked that valid notes are written exactly as before (record 100's annotations and your Latin-1 example give byte-identical files to main), and that both invalid-note tests fail on main. Latin-1 also matches how rdann decodes the notes.

Unrelated to this PR, but I noticed it while testing: the wrann docstring says an aux note can be None for annotations without notes, but None is rejected with TypeError: Subelements of the aux_note field must be strings (on main too). Either the docstring or the check should change at some point.

@tompollard

Copy link
Copy Markdown
Member

@TheNetherWatcher please could you resolve the conflict?

@TheNetherWatcher

Copy link
Copy Markdown
Contributor Author

working

The length of an aux note is stored in one byte and its characters as
single bytes, but wrann didn't check either. A note longer than 255
characters wrapped the length and was read back as many extra
annotations, and characters outside Latin-1 were silently replaced.

Raise a ValueError for these notes before writing, and write the
Latin-1 encoded bytes, which is what rdann decodes.
@TheNetherWatcher

Copy link
Copy Markdown
Contributor Author

Done, rebased onto main. The only conflict was the changelog, and I kept both entries. Tests pass (109).

@tompollard
tompollard merged commit 74a3f56 into MIT-LCP:main Oct 31, 2026
18 checks passed
tompollard added a commit that referenced this pull request Oct 31, 2026
Found by @tompollard while reviewing #605.

The `wrann` docstring (and the `Annotation` example) say an aux note can
be `None` for annotations without a note, but `None` was rejected:

```python
wfdb.wrann("a", "atr", np.array([1, 5, 9]), symbol=["N", "N", "V"], aux_note=[None, "(VT", None])
# TypeError: Subelements of the aux_note field must be strings
```

`compact_fields` already turns empty notes into `None` before writing,
so the writer handles `None`. Only `check_field` rejected it. It now
skips `None` in `aux_note`, so `None` is written exactly like `""`
(byte-identical files), and `rdann` reads both back as `""`. I kept the
docstring as it is, since it already describes this.


Tests: `None` and `""` notes give byte-identical files, and read back as
`""`. The test fails on `main`. `pytest -m "not network"` passes (100
tests), and the docs build passes.
@TheNetherWatcher
TheNetherWatcher deleted the wrann-aux-note-check branch November 1, 2026 06:13
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