Validation

xlea supports per-column value validation before type conversion. A validator is a plain callable that returns True if the value is acceptable and False otherwise.

Attaching a validator

Pass any Callable[[Any], bool] to the validator argument of Column():

from xlea import Schema, Column

class Employee(Schema):
    id: int  = Column("ID", validator=lambda v: str(v).isnumeric())
    age: int = Column("Age", validator=lambda v: 0 < int(v) < 120)

The validator receives the raw cell value (before type conversion). This means you should handle the value as a string or whatever the provider returns — not as the annotated type.

Raise vs skip

By default, a failed validator raises InvalidRowError. Set skip_invalid_row=True to silently drop the row instead:

class Sale(Schema):
    amount: float = Column(
        "Amount",
        validator=lambda v: str(v).replace(".", "", 1).lstrip("-").isnumeric(),
        skip_invalid_row=True,
    )

# rows where "Amount" is "N/A", "-", or "" are silently omitted
for sale in xlea.autoread("sales.xlsx", schema=Sale):
    print(sale.amount)

Multiple validators

xlea supports only one validator per column. Combine conditions with and:

is_valid_age = lambda v: str(v).isnumeric() and 0 < int(v) < 150

class Person(Schema):
    age: int = Column("Age", validator=is_valid_age, skip_invalid_row=True)

Validator return type

The validator must return a bool. Returning any other type (e.g. a truthy integer or a string) raises IncompatibleReturnValueTypeError:

# ✗ Wrong — str() is truthy but not bool
Column("Age", validator=str)

# ✓ Correct
Column("Age", validator=lambda v: bool(str(v)))

Warning

bool itself is a valid validator because bool(value) returns True or False. It will mark empty strings, 0, and None as invalid.

Real-world example

A schema that reads a sales report and skips rows with missing or non-numeric amounts:

import xlea
from xlea import Schema, Column

def is_numeric(v) -> bool:
    try:
        float(str(v))
        return True
    except ValueError:
        return False

class SalesRow(Schema):
    date: str    = Column("Date")
    product: str = Column("Product")
    revenue: float = Column(
        "Revenue",
        validator=is_numeric,
        skip_invalid_row=True,
    )

total = sum(
    row.revenue
    for row in xlea.autoread("sales_report.xlsx", schema=SalesRow)
)
print(f"Total revenue: {total:.2f}")