Diagnostics And Validation Results⚓︎
Talika uses one immutable diagnostic model for runtime parsing, non-raising validation, static checking, pytest-bdd integration, and CLI JSON. This keeps a failure's code, source location, field identity, and values consistent no matter which entry point reports it.
Use the raising APIs when invalid table data should fail immediately:
Use validate() when a tool, test, or editor needs a result value:
result = UserTable.validate(datatable)
if result.valid:
records = result.records
else:
for diagnostic in result.errors:
print(diagnostic.code, diagnostic.row, diagnostic.column)
The functional and pytest forms run the same lifecycle:
from talika import validate_table
result = validate_table(UserTable, datatable, context={"locale": "en"})
result = talika.validate(datatable, schema=UserTable, context={"locale": "en"})
Understand ValidationResult⚓︎
ValidationResult[RecordType] is frozen and contains immutable tuples:
recordscontains schema records only when the complete table is validdiagnosticscontains errors and warnings in discovery ordererrorsandwarningsfilter that tuple without reordering itvalidis true when there are no error-severity diagnostics
Validation always uses safe collect semantics. It runs table transformation,
field parsing, defaults, IDs, variants, references, and record/table
validators. It deliberately skips output models and build_output().
result = UserTable.validate([["name", "age"], ["Alice", "bad"]])
assert not result.valid
assert result.records == ()
assert result.errors[0].code == "parser_failed"
Invalid results never expose partially parsed records. This prevents callers
from accidentally using records produced before a later field, reference, or
validator failed. Successful records remain mutable, matching parse().
Validation warnings⚓︎
Validation hooks may raise a TableError with
severity=DiagnosticSeverity.WARNING. Warning-only validation remains valid
and keeps its complete records.
validate() returns warnings in result.diagnostics and result.warnings.
The raising APIs emit a public TalikaWarning through Python's warnings system
and still return their data. If warnings and errors coexist, warnings remain in
discovery order, no partial records are returned, and raising APIs emit the
warnings before raising the error failures.
Schema declaration errors and API misuse still raise. For example, an invalid
schema family raises SchemaDefinitionError, and an unsupported error_mode
raises ValueError; neither is authored table data.
Read A Diagnostic⚓︎
Diagnostic is a frozen, slotted value with diagnostic_version = 1.
diagnostic = result.diagnostics[0]
print(diagnostic.code) # parser_failed
print(diagnostic.severity) # DiagnosticSeverity.ERROR
print(diagnostic.schema_name) # UserTable
print(diagnostic.field_name) # age
print(diagnostic.field_label) # Age
print(diagnostic.source_uri) # file:///.../users.feature, when known
print(diagnostic.row, diagnostic.column)
field_name identifies the Python declaration. field_label identifies the
authored canonical label or alias. An unknown authored label has no field name,
but is retained as the field label.
source_value is what the author wrote. logical_value is what a transformer
made available to later parsing. Both may be useful when compact syntax is
expanded or normalized.
if diagnostic.has_source_value:
print("authored:", diagnostic.source_value)
if diagnostic.has_logical_value:
print("logical:", diagnostic.logical_value)
The has_item_id, has_source_value, and has_logical_value flags distinguish
an omitted value from a value explicitly set to None. The public value
property returns None in both cases, so inspect the presence flag when that
distinction matters.
cause retains the original exception for programmatic debugging. It is
excluded from equality and JSON because exceptions are not stable data.
as_dict() returns deterministic JSON-compatible Model v1 fields.
Raising APIs Remain Compatible⚓︎
TableError, TableErrors, and SchemaDefinitionError remain the exceptions
used by existing applications.
TableError.diagnosticis the underlying immutableDiagnostic- legacy properties such as
schema,field,value,code, and coordinates remain available TableErrors.errorsremains an immutable tuple ofTableErrorTableErrors.diagnosticsexposes the corresponding diagnostic tupleSchemaDefinitionError.diagnosticusescode="schema_definition"
Formatted exception strings may gain source and explicit field information. Integrations should consume structured properties instead of parsing text.
Raise Deliberate Project Diagnostics⚓︎
At every user extension boundary, a deliberate TableError, TableErrors, or
SchemaDefinitionError passes through unchanged. This applies to parsers,
default factories, transformers, reference-key parsers, validators, and output
builders.
from talika import TableError, field
def project_code(value, context):
if not value.startswith("USR-"):
raise TableError(
"User code must start with USR-",
code="project_user_code",
schema=context.schema,
field_name=context.field_name,
field_label=context.field_label,
source_uri=context.source_uri,
row=context.row,
column=context.column,
source_value=context.source_value,
)
return value
code = field("Code", parser=project_code)
Raise an ordinary exception when Talika should classify the extension point:
parser exceptions become parser_failed, default-factory exceptions become
default_factory_failed, and so on. The wrapper retains the original cause.
Unexpected exceptions escaping Talika's own lifecycle become internal_error
with a bug-report hint. Control-flow exceptions such as KeyboardInterrupt and
SystemExit are never intercepted.
Respect Lifecycle Barriers⚓︎
Diagnostics remain in discovery order; Talika does not sort them. It collects independent failures within a safe phase, then stops before dependent work:
- schema finalization and context normalization
- raw table validation and transformation
- shape, labels, variants, fields, and IDs
- reference indexing and resolution
- record and whole-table validation
- output conversion for
parse_as()only
Structure or conversion errors stop references and validation. Reference errors stop validators and output. Validation errors stop output. These barriers avoid secondary diagnostics produced from incomplete data.
Diagnostic Code Catalog⚓︎
Talika-owned failures always use an explicit code. table_error is reserved as
the default for project-created TableError values.
| Code | Lifecycle owner | Meaning |
|---|---|---|
table_error |
Project extensions | Default code for a user-created custom error. |
schema_definition |
Schema compiler/family finalization | A schema declaration, inheritance contract, variant family, or reference contract is invalid. |
invalid_context |
Context normalization | The supplied parse context cannot be normalized. |
invalid_table_input |
Table boundary | Raw rows, cells, coordinates, or TableData are malformed. |
table_empty |
Table boundary/transformation | A table or grouped table has no usable cells. |
header_empty |
Orientation | A required row or column header is blank. |
ragged_row |
Orientation/transformation | Rows do not form the required rectangular shape. |
duplicate_label |
Label validation | A label or canonical-label/alias combination appears more than once. |
unknown_field |
Label validation | Authored text names a field the schema does not accept. |
missing_required |
Field conversion | A required field is absent. |
empty_required |
Field conversion | A required authored cell is blank. |
empty_optional |
Field conversion | An optional cell violates its empty-value policy. |
default_factory_failed |
Field conversion | A default factory raised a non-Talika exception. |
parser_failed |
Field conversion | A field parser raised a non-Talika exception. |
transform_failed |
Transformation | A table transformer or range/repeat rule raised unexpectedly. |
invalid_transform |
Transformation | A transformer or compact expansion returned an invalid structure. |
expansion_limit |
Group expansion | Numeric expansion would create more than 10,000 keys. |
unknown_variant |
Variant selection | A discriminator value has no registered variant. |
inapplicable_field |
Variant selection | Authored data populates a field unavailable on the selected variant. |
duplicate_id |
Identity | Two parsed records use the same ID. |
invalid_id |
Identity/orientation | An ID is unhashable or a column ID row has an invalid layout. |
reference_failed |
References | Target indexing, key conversion, uniqueness, or lookup failed. |
record_validation_failed |
Validation | A record validator raised a non-Talika exception. |
table_validation_failed |
Validation | A whole-table validator raised a non-Talika exception. |
output_failed |
Output conversion | An output model or custom builder rejected a valid record. |
checker_failed |
Static checker/CLI | Feature discovery, import, Gherkin, or context setup failed operationally. |
internal_error |
Lifecycle boundary | An unexpected Talika implementation failure escaped its owning stage. |
Code meanings are part of Diagnostic Model v1. New fields and codes may be added compatibly; removing a field or changing a code's meaning requires a new diagnostic or format version.
Choose An API⚓︎
- Use
parse()for raising validation that returns schema records. - Use
parse_as()for explicit or configured output conversion. - Use
validate()for non-raising tooling and complete-table acceptance. - Use static checking for feature-file discovery plus
validate(). - Use CLI JSON when another process needs versioned deterministic data.
All of these entry points share the compiled schema and diagnostic lifecycle.