flet-validation
SkillDev toolsUse whenever editing validation for Python controls in sdk/python/packages/: adding/changing constrained properties, `Raises: ValueError` docstrings, `before_update()` checks, `raise ValueError`, Annotated/V rules, or __validation_rules__.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the flet-validation skill
What this skill tells your AI
The instructions your AI receives, as published by flet-dev/flet in .agents/skills/flet-validation/SKILL.md and read by ahel’s review.
When To Use
Use this skill when you:
- add validation to a control property,
- migrate manual
before_update()checks toVrules, - update
Raisessections tied to validation, - align Python validation with Dart-side control behavior.
Do not use this skill for unrelated doc-only edits outside control validation.
Do not use this skill for deprecation authoring conventions; use
flet-deprecation.
Source Of Truth
- Validation runtime API lives in:
sdk/python/packages/flet/src/flet/utils/validation.py - The same runtime can validate regular dataclass models via
validate(instance); this skill focuses on the control-specific authoring conventions. - Import from public path only:
from flet.utils.validation import Vand when neededfrom flet.utils.validation import ValidationRules
Validation Decision Order
Use this order and stop at the first option that keeps logic clear:
Annotated[..., V.*]field rules (default).__validation_rules__: ValidationRulesfor cross-field invariants that do not map cleanly to one field.before_update()only for normalization/mutation, or for truly non-ruleable invariants.
Never duplicate the same invariant in more than one layer.
Validation Authoring Rules
-
Prefer field-level validation with
Annotated[...]metadata.- Example (close to current slider controls):
@dataclass class Sample: opacity: Annotated[ Optional[Number], V.between(0.0, 1.0), ] = None value: Annotated[ Optional[Number], V.ge_field("min"), V.le_field("max"), ] = None min: Annotated[ Number, V.le_field("max"), V.le_field("value"), ] = 0.0 max: Annotated[ Number, V.ge_field("min"), V.ge_field("value"), ] = 1.0
- Example (close to current slider controls):
-
Use class-level
__validation_rules__only for invariants that cannot be expressed cleanly with field rules.- Type:
__validation_rules__: ValidationRules = (...) - Use
V.ensure(...)with an explicit message only when the predicate is short and readable. - If
V.ensure(lambda ...)becomes hard to read, prefer either:- a named predicate function passed to
V.ensure(...), or - a clear
before_update()check when it cannot be represented well with existingV.*rules.
- a named predicate function passed to
- Type:
-
Keep the
before_update()override for normalization/mutation first.- Remove validation checks duplicated by
Vrules. - Prefer raising validation errors from rule evaluation (
validate()), not from ad-hocbefore_update()checks, unless the invariant is genuinely non-ruleable with current validation primitives.
- Remove validation checks duplicated by
-
Cross-field comparisons use field rules only.
- Use:
V.gt_field,V.ge_field,V.lt_field,V.le_field
- Use:
-
Nonehandling is inferred from type hints.- If a field is annotated as optional (for example
Optional[T]),Noneis allowed. - If a field is not optional,
Nonefails validation. - For
*_fieldcomparisons, if either side is optional and currentlyNone, the comparison is skipped; if a non-optional side isNone, validation fails.
- If a field is annotated as optional (for example
-
Match Dart effective behavior.
- Review both:
- Flet Dart wrapper (
packages/flet/lib/src/controls/<control>.dartor extension wrapper), - wrapped Flutter widget source assertions/invariants.
- Flet Dart wrapper (
- Mirror those constraints in Python so invalid payloads fail before crossing to Dart.
- Validate against effective defaults applied on Dart side (for example
min/max). - Include wrapper-imposed constraints when relevant (for example bounds/rounding/division logic in wrapper formatting code).
- Review both:
-
For new properties, validate against base widget assertions before wiring.
- When adding a Python property to a Flet control, confirm whether the mapped Dart wrapper and underlying widget both enforce constraints for that property.
- Add equivalent Python-side validation (
Annotated[...],__validation_rules__, or readablebefore_update()) to prevent Dart assertions from being the first failure point.
-
Keep error ownership clear.
- Runtime outbound value failures should raise
ValueError. - Validation declaration/build errors (invalid
V.*arguments) should raiseValidationDeclarationError.
- Runtime outbound value failures should raise
Typing Style
- Follow the codebase typing style:
- prefer
Optional[T]overT | None, - use
Union[...]when needed.
- prefer
Property Docstring Style
When a property has validation, document it in that property’s docstring (google style).
-
Add a
Raises:block under the property docstring. -
Use one
ValueErrorentry per logical rule, exceptbetween(...).- For
V.between(a, b), use one entry:ValueError: If it is not between \a` and `b`, inclusive.`
- For
-
Start each entry with
If it ..., where 'it' refers to the property name. -
Use canonical wording from validation helper docstrings.
- The source of truth is
sdk/python/packages/flet/src/flet/utils/validation.py. - Each
V.*helper includesProperty docstring Raises wording. - Keep property
Raisesentries as negations of the annotation rule. - For strict inequalities, say
"strictly". For example:V.gt(x)->ValueError: If it is not strictly greater than \x`.` - For sign-neutral divisibility helpers (
factor_of,multiple_of), add explicit sign rules (V.gt(0)orV.lt(0)) when direction matters, and include separateRaisesentries for those sign rules.
- The source of truth is
-
Mention conditional applicability when needed.
- Example (for
min/maxchecks against optionalvalue):Raises: ValueError: If it is not less than or equal to [`value`][(c).], when [`value`][(c).] is set.
- Example (for
-
Keep examples and wording aligned with real control files.
- Prefer concrete property names such as
min,max,value,start_value,end_value,min_lines,max_lines. - For cross-field rules, use same-class links: [
min][(c).], [max][(c).].
- Prefer concrete property names such as
Cross-Referencing Conventions
Follow the cross-reference guidance in:
docs-conventions.
Most common pattern to use in control property docstrings:
- same-class properties:
[\prop`][(c).]`
Keep symbol labels wrapped in backticks.
Required Test Matrix
When adding/changing validation, include tests that cover:
- one valid case and one invalid case per new logical rule;
- boundary values (
==, min/max edges) where applicable; - cross-field set/unset combinations when optional values are involved;
- effective-default behavior when Dart applies defaults but Python value is omitted.
Prefer placing tests in:
sdk/python/packages/flet/tests/test_validation.pyfor validation runtime;- control-specific tests when behavior is tied to one control.
Common Pitfalls
- Keeping stale manual
before_update()validations after migration. - Missing
Raisesentries on validated properties. - Combining multiple non-between rules into one ambiguous
ValueErrorsentence. - Forgetting Dart defaults that still apply when Python property is omitted.
- Forcing complex
V.ensure(lambda ...)expressions whenbefore_update()would be cleaner.
Signals
- GitHub stars
- 17k
- Forks
- 691
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
flet-validation- Source
- github.com/flet-dev/flet