From 0e5728f86a0d190b3a8412a44ed51eafc4e30778 Mon Sep 17 00:00:00 2001 From: Bharat Kaurav <117659673+TheNetherWatcher@users.noreply.github.com> Date: Sat, 31 Oct 2026 23:12:28 +0530 Subject: [PATCH] Allow None for annotations without notes in wrann The docstring says aux_note can hold None for annotations without a note, and compact_fields already writes None like an empty string, but check_field rejected it with a TypeError. --- docs/changes.rst | 3 +++ src/wfdb/io/annotation.py | 3 +++ tests/test_annotation.py | 20 ++++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/docs/changes.rst b/docs/changes.rst index 8c63c074..ccd52451 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -44,6 +44,9 @@ Unreleased **Reject aux notes that can't be written in wrann** ``wrann`` now raises a ``ValueError`` if an ``aux_note`` is longer than 255 characters or contains characters outside Latin-1, instead of writing a corrupt annotation file. A longer note used to be read back as many extra annotations, and other characters were silently replaced. +**Allow None for annotations without notes in wrann** + ``wrann`` now accepts ``None`` in ``aux_note`` for annotations without a note, as the docstring says, and writes it the same way as an empty string. It used to raise a ``TypeError``. + Version 4.3.1 (Feb 2026) ----------------------------- diff --git a/src/wfdb/io/annotation.py b/src/wfdb/io/annotation.py index 463cf770..2321fb5e 100644 --- a/src/wfdb/io/annotation.py +++ b/src/wfdb/io/annotation.py @@ -514,6 +514,9 @@ def check_field(self, field): # The string fields elif field in ["symbol", "description", "aux_note"]: uniq_elements = set(item) + # None means no note, the same as an empty string + if field == "aux_note": + uniq_elements.discard(None) for e in uniq_elements: if not isinstance(e, str_types): diff --git a/tests/test_annotation.py b/tests/test_annotation.py index 2ecfeab3..a0e901fd 100644 --- a/tests/test_annotation.py +++ b/tests/test_annotation.py @@ -322,3 +322,23 @@ def test_aux_note_rejected(temp_path, aux_note, match): write_dir=temp_path, ) assert not os.path.exists(os.path.join(temp_path, "bad_aux.atr")) + + +def test_aux_note_none(temp_path): + """None in aux_note means no note, as for an empty string.""" + for name, aux_note in [("none", [None, "(VT", None]), ("empty", ["", "(VT", ""])]: + wfdb.wrann( + name, + "atr", + np.array([1, 5, 9]), + symbol=["N", "N", "V"], + aux_note=aux_note, + write_dir=temp_path, + ) + ann = wfdb.rdann(os.path.join(temp_path, "none"), "atr") + assert ann.aux_note == ["", "(VT", ""] + with ( + open(os.path.join(temp_path, "none.atr"), "rb") as f1, + open(os.path.join(temp_path, "empty.atr"), "rb") as f2, + ): + assert f1.read() == f2.read()