Errors¶
Everything polspec raises on its own behalf derives from one base class, so a caller can separate "polspec objected" from "something else went wrong" with a single clause:
from polspec import PolspecError
try:
Orders.validate(df)
except PolspecError as exc:
log.warning("rejected: %s", exc)
| Exception | Raised when | Also a |
|---|---|---|
PolspecError |
Base class; never raised directly | Exception |
SpecError |
A declaration cannot mean anything: bounds a dtype cannot hold, a rule naming a column that does not exist, two attributes resolving to one column name | ValueError, TypeError |
ValidationError |
Data does not meet its spec. err.report is the ValidationReport; err.errors lists its messages |
ValueError |
GenerationError |
A spec that declares fine cannot be turned into data as asked: no column for method="cartesian" to cover, a coverage set past the size cap, a foreign key with an empty parent. Errors from the Rust engine surface as this |
ValueError |
SerializationError |
A spec file cannot be written or read: a dtype with no file representation, an unrecognised dtype name, a category reference the registry does not hold | ValueError |
RegistryError |
A Registry is inconsistent: an unknown or duplicated spec name, a key whose target is not in it, a cycle, two specs disagreeing about a shared category |
LookupError |
Each subclass keeps the built-in type it replaced, so except ValueError
written against an earlier version still catches it.
Ordinary argument misuse is not a PolspecError. A negative row count, an
unknown method=, a batch_size of zero, or the wrong object passed where a
DataFrame was expected raise the plain ValueError or TypeError any Python
API would.
The command line prints a PolspecError as a one-line error: ... and exits
with status 1; anything else is a bug and keeps its traceback.
Finding codes¶
Every violation inspect() reports, and validate() raises, is a Finding
with one of these codes. Row-level findings can return the offending rows
through report.rows(finding); structural ones describe the frame's shape.
| Code | Kind | Raised when |
|---|---|---|
extra_columns |
structural | the frame has columns the spec does not declare (extra_cols="raise") |
missing_columns |
structural | the frame lacks declared columns (missing_cols="raise") |
dtype |
structural | a column's dtype is not compatible with its declaration |
foreign_key_unresolved |
structural | a key references another spec and references= had no entry for it |
nullability |
row-level | a non-nullable column holds nulls |
choices |
row-level | a value is outside choices or the Enum categories |
bounds |
row-level | a value is outside bounds; details carry the extremes found |
string_length |
row-level | a string or binary value's length is outside string_length |
list_length |
row-level | a list holds a number of elements outside list_length |
format |
row-level | a string value does not have the declared format; details name the format |
pattern |
row-level | a string value does not match the declared pattern; details carry it |
rule |
row-level | a row matched a ColRule but holds a value outside its choices |
validator |
row-level | a ColSpec.validators predicate is false |
unique |
row-level | a unique=True column holds duplicates |
unique_together |
row-level | a composite key holds duplicate combinations |
check |
row-level | a __checks__ predicate is false |
foreign_key |
row-level | a key value has no matching parent row (also structural when the parent lacks the referenced columns) |
Drift codes¶
A DriftReport (from diff() or drift()) carries DriftFindings with one
of these codes. Each also carries a severity: breaking when a frame
that satisfied the old side could fail the new one, compatible
otherwise. See Schema and data drift.
| Code | From | Severity | Raised when |
|---|---|---|---|
column_added |
both | breaking | the new spec declares a column the old lacks, or the data has an undeclared column |
column_removed |
both | breaking | the old spec declares a column the new lacks, or the data lacks a declared column |
column_renamed |
diff |
compatible | a rename given through renames= |
dtype_changed |
both | as validation decides | the dtypes differ; compatible when the old values would still validate |
nullability_changed |
both | off → on compatible; on → off breaking; nulls in a non-nullable column breaking | |
domain_widened |
diff |
compatible | bounds, choices, format or string length accept more than before |
domain_narrowed |
diff |
breaking | they accept less |
domain_changed |
diff |
breaking | neither is inside the other |
bounds_exceeded |
drift |
breaking | values escape bounds, string_length or list_length; details say which and by how much |
new_values |
drift |
breaking | values outside choices, an Enum or a finite format |
format_violated |
drift |
breaking | values that do not match the declared format |
null_rate_moved |
drift |
compatible | the null rate sits further from null_probability than the tolerance |
cardinality_moved |
drift |
compatible | declared values the data never holds |
constraint_added |
diff |
breaking | unique, a validator, rule, check, composite key, foreign key or hierarchy present only in the new spec |
constraint_removed |
diff |
compatible | the reverse |
field_changed |
diff |
compatible | tags, weights, distribution, distribution_params, null_probability, pattern or seed_name differ |
A struct's fields are compared by every row above, as columns are, and a
finding about one is keyed by its path -- point.lat__domain -- with
columns naming the struct column.