Exceptions¶
textual-wtf defines four exception classes, all importable directly from textual_wtf.
ValidationError¶
ValidationError
¶
Raised when a validator or clean() rejects a value.
Attributes¶
message: str- The human-readable error message passed to the constructor.
When it is raised¶
- Inside a
FunctionValidatorcallable to signal a failed validation check. - By
IntegerField.to_python()when the input cannot be converted toint. - By custom validators that call
raise ValidationError(...).
Example¶
from textual_wtf import ValidationError
def must_be_even(value: int | None) -> None:
if value is not None and value % 2 != 0:
raise ValidationError(f"{value} is not an even number.")
FieldError¶
Raised when a field is configured incorrectly at class definition time.
When it is raised¶
ChoiceFieldis defined with an emptychoiceslist.- A custom
Fieldsubclass detects an invalid configuration.
Example¶
from textual_wtf import ChoiceField
# Raises FieldError immediately at class definition time:
class BadForm(Form):
size = ChoiceField("Size", choices=[]) # FieldError: non-empty list required
FormError¶
Raised for form definition or rendering errors.
When it is raised¶
- Embedding produces a field name that conflicts with an existing field.
add_error()is called with a field name that does not exist on the form.- A
BoundFieldis rendered a second time (double-yield guard).
Example¶
from textual_wtf import Form, StringField
class BadForm(Form):
billing_city = StringField("Billing city")
billing = AddressForm() # would create billing_city → FormError
AmbiguousFieldError¶
AmbiguousFieldError
¶
Raised when unqualified attribute access on a form matches more than one embedded field.
Attributes¶
name: str- The unqualified name that was looked up.
candidates: list[str]- The fully-qualified field names that all match the suffix.
When it is raised¶
form = OrderForm() # has billing_city and shipping_city
try:
form.city # ambiguous — matches both billing_city and shipping_city
except AmbiguousFieldError as e:
print(e.name) # "city"
print(e.candidates) # ["billing_city", "shipping_city"]
Resolution¶
Use the fully-qualified name: