Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 0.1.8

### Fixed
- **CSV writer**: downgrade trailing blank row mismatch from error to warning
when a tall instruction's stripped continuation absorbs extra blank rows on
read-back — fixes `WriterError` on rungs with blank rows beyond an
instruction's visual height

## 0.1.7

### Fixed
Expand Down
28 changes: 22 additions & 6 deletions src/laddercodec/csv/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,26 @@ def _validate_roundtrip(rung: Rung, rows: Sequence[Sequence[str]]) -> None:
rebuilt = _rebuild_rung_from_rows(rows)

if rebuilt.logical_rows != rung.logical_rows:
raise WriterError(
"CSV round-trip validation failed: "
f"logical row count mismatch: expected {rung.logical_rows}, got {rebuilt.logical_rows}"
)
# Trailing blank rows (no conditions, no AF) can be lost when
# a tall instruction's stripped continuation absorbs them on
# read-back. This is cosmetic — warn instead of failing.
extra = rung.logical_rows - rebuilt.logical_rows
if extra > 0 and all(
_is_padding_row(rung.conditions[r]) and rung.instructions[r] == ""
for r in range(rebuilt.logical_rows, rung.logical_rows)
):
import warnings

warnings.warn(
f"CSV round-trip lost {extra} trailing blank row(s) "
f"(logical_rows {rung.logical_rows} → {rebuilt.logical_rows})",
stacklevel=2,
)
else:
raise WriterError(
"CSV round-trip validation failed: "
f"logical row count mismatch: expected {rung.logical_rows}, got {rebuilt.logical_rows}"
)

if rebuilt.comment != rung.comment:
raise WriterError(
Expand All @@ -377,7 +393,7 @@ def _validate_roundtrip(rung: Rung, rows: Sequence[Sequence[str]]) -> None:
)

for row_idx, (expected_row, actual_row) in enumerate(
zip(rung.conditions, rebuilt.conditions, strict=True),
zip(rung.conditions[: rebuilt.logical_rows], rebuilt.conditions, strict=True),
start=1,
):
for col_idx, (expected, actual) in enumerate(zip(expected_row, actual_row, strict=True)):
Expand All @@ -389,7 +405,7 @@ def _validate_roundtrip(rung: Rung, rows: Sequence[Sequence[str]]) -> None:
)

for row_idx, (expected, actual) in enumerate(
zip(rung.instructions, rebuilt.instructions, strict=True),
zip(rung.instructions[: rebuilt.logical_rows], rebuilt.instructions, strict=True),
start=1,
):
if not _af_tokens_match(expected, actual):
Expand Down