Skip to content

Fix _validate() silently accepting empty rows/cols due to falsy check#654

Open
maxtaran2010 wants to merge 1 commit into
jazzband:masterfrom
maxtaran2010:fix/validate-empty-row-falsy-check
Open

Fix _validate() silently accepting empty rows/cols due to falsy check#654
maxtaran2010 wants to merge 1 commit into
jazzband:masterfrom
maxtaran2010:fix/validate-empty-row-falsy-check

Conversation

@maxtaran2010

Copy link
Copy Markdown

Summary

Dataset._validate() uses if row: and elif col: to check whether a row or column was passed as an argument. This is a falsy check and fails silently when row or col is an empty sequence (() or []).

When row=() is passed (e.g. via insert() or __setitem__()), the condition if row: evaluates to False, so execution falls through to the else branch, which validates the entire existing dataset dimensions instead of checking the incoming row's length. This means an empty row can be silently inserted into a dataset with existing columns without raising InvalidDimensions.

Reproduction

import tablib

d = tablib.Dataset()
d.headers = ['a', 'b', 'c']
d.append((1, 2, 3))

# Should raise InvalidDimensions - empty row can't fit a 3-column dataset
d.insert(0, ())   # silently accepted before this fix

# Same issue via __setitem__
d[0] = ()         # silently accepted before this fix

Fix

Replace if row: with if row is not None: and elif col: with elif col is not None: so that empty sequences are correctly dispatched to the row/column dimension check instead of the fallback full-dataset check.

Tests

All 176 existing tests continue to pass. The fix does not change behavior for any non-empty row/col argument.

`if row:` and `elif col:` are falsy for empty sequences (e.g. `()`
or `[]`), causing `_validate` to fall through to the else branch which
validates existing dataset dimensions instead of checking the provided
row/col.  Replace with `is not None` so an empty row passed to
`insert()` or `__setitem__()` correctly raises `InvalidDimensions`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 9, 2026 21:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@claudep

claudep commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Thanks, but this needs a regression test.

@santhreal

Copy link
Copy Markdown

The is not None dispatch fixes the empty-row case, but the empty-column case still slips through because the col branch keeps its own short-circuit:

elif col is not None:
    if len(col) < 1:
        is_valid = True   # empty column still treated as valid
    else:
        ...

So an empty column inserted into a dataset that has rows still passes validation, and insert_col then inserts the header and crashes at col[i], leaving the dataset corrupted:

d = tablib.Dataset()
d.headers = ['a', 'b']
d.append([1, 2]); d.append([3, 4])
d.insert_col(0, col=None, header='z')   # col=None -> []
# IndexError: list index out of range, and d.headers is now ['z', 'a', 'b'] (width still 2)

Dropping the if len(col) < 1: is_valid = True line lets an empty column fall through to len(col) == self.height, which raises InvalidDimensions before any mutation, while an empty column into an empty/headers-only dataset stays valid via the else True. Happy to send a follow-up if you'd rather keep this PR row-only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants