Conversation
…ng test for window values
…rkbench into ui-features Update
There was a problem hiding this comment.
Pull request overview
Adds stricter duration/window validation for Timing fields (ISO 8601 / USDM-style), updates UI hints/constraints, and expands router tests to cover the new behavior.
Changes:
- Enforce duration format validation for
value,window_lower, andwindow_uppervia Pydantic validators. - Enforce “all-or-nothing” rule for the window triplet (
window_lower,window_upper,window_label) across API + UI. - Update templates and tests to use duration strings (e.g.,
P5D) and add validation-focused test cases.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_timings.py | Updates expected timing value/window fields to duration strings. |
| tests/test_routers_timings.py | Adds API/UI tests for invalid/valid durations and window all-or-none behavior. |
| src/soa_builder/web/templates/timings.html | Updates Timing UI fields/order, adds HTML pattern constraints and JS all-or-none enforcement. |
| src/soa_builder/web/templates/instances.html | Renames “Default Condition” label/header to “Next Instance (default condition)”. |
| src/soa_builder/web/schemas.py | Adds duration regex validation + window all-or-none model validation to Timing schemas. |
| src/soa_builder/web/routers/timings.py | Converts Pydantic ValidationError into HTTP 400 for UI form endpoints with aggregated messages. |
| @@ -178,4 +178,32 @@ <h2>Timings for SoA {{ soa_id }}</h2> | |||
| <tr><td colspan="12" style="padding:6px;color:#777;">No timings yet.</td></tr> | |||
There was a problem hiding this comment.
The table now has more than 12 columns (additional “Rel To/From” column was added, and columns were rearranged). With colspan="12", the “No timings yet” row won’t span the full table width. Update the colspan to match the current number of <th> columns.
| <tr><td colspan="12" style="padding:6px;color:#777;">No timings yet.</td></tr> | |
| <tr><td colspan="16" style="padding:6px;color:#777;">No timings yet.</td></tr> |
| # ISO 8601 duration pattern supporting both standard (-P2D) and USDM (P-2D) conventions | ||
| _ISO8601_DURATION_RE = re.compile( | ||
| r"^-?P-?(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$" | ||
| ) |
There was a problem hiding this comment.
This regex accepts durations where T is present but no time components are provided (e.g., P1DT), which is not a valid ISO 8601 duration. Consider adjusting the pattern so that if T is present, at least one of H/M/S must also be present.
| <div style="display:flex;flex-direction:column;gap:2px;"> | ||
| <label><strong>Value</strong></label> | ||
| <input name="value" placeholder="Value (optional)" /> | ||
| <input name="value" placeholder="e.g. P7D (optional)" pattern="-?P-?(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?" title="ISO 8601 duration, e.g. P1D, P2W, PT8H, -P2D" /> |
There was a problem hiding this comment.
The HTML pattern is looser than the backend validator: it appears to allow inputs like P or PT (no components), which the backend rejects. Tighten the client-side pattern to better match server validation (including disallowing “bare P” / “PT”) so users get immediate feedback and fewer 400/422 errors.
| <input name="value" placeholder="e.g. P7D (optional)" pattern="-?P-?(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?" title="ISO 8601 duration, e.g. P1D, P2W, PT8H, -P2D" /> | |
| <input name="value" placeholder="e.g. P7D (optional)" pattern="-?P(?=.*\d)-?(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?" title="ISO 8601 duration, e.g. P1D, P2W, PT8H, -P2D" /> |
| <label><strong>Window Label</strong></label> | ||
| <input name="window_label" placeholder="Window (optional)" /> | ||
| <label><strong>Window Lower</strong></label> | ||
| <input name="window_lower" placeholder="e.g. -P2D (optional)" pattern="-?P-?(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?" title="ISO 8601 duration, e.g. P1D, -P2D, PT8H" /> |
There was a problem hiding this comment.
The HTML pattern is looser than the backend validator: it appears to allow inputs like P or PT (no components), which the backend rejects. Tighten the client-side pattern to better match server validation (including disallowing “bare P” / “PT”) so users get immediate feedback and fewer 400/422 errors.
| <div style="display:flex;flex-direction:column;gap:2px;"> | ||
| <label><strong>Window Upper</strong></label> | ||
| <input name="window_upper" placeholder="+N (optional)" /> | ||
| <input name="window_upper" placeholder="e.g. P3D (optional)" pattern="-?P-?(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?" title="ISO 8601 duration, e.g. P1D, P3D, PT8H" /> |
There was a problem hiding this comment.
The HTML pattern is looser than the backend validator: it appears to allow inputs like P or PT (no components), which the backend rejects. Tighten the client-side pattern to better match server validation (including disallowing “bare P” / “PT”) so users get immediate feedback and fewer 400/422 errors.
| member_of_timeline=member_of_timeline, | ||
| ) | ||
| except ValidationError as exc: | ||
| msgs = "; ".join(e["msg"] for e in exc.errors()) |
There was a problem hiding this comment.
Aggregating only e["msg"] drops the field context, making UI errors harder to act on (e.g., users can’t tell whether window_upper vs value failed). Include the error location (typically e["loc"]) in the message formatting so the response clearly identifies which field(s) are invalid.
| msgs = "; ".join(e["msg"] for e in exc.errors()) | |
| msgs = "; ".join( | |
| ( | |
| f"{'.'.join(str(p) for p in e.get('loc', []))}: {e.get('msg')}" | |
| if e.get("loc") | |
| else str(e.get("msg")) | |
| ) | |
| for e in exc.errors() | |
| ) |
|
|
||
|
|
||
| def test_window_accepts_valid_iso8601_durations(): | ||
| """Test that various valid ISO 8601 durations are accepted.""" |
There was a problem hiding this comment.
The implementation and tests accept both standard ISO 8601 negatives (-P2D) and a USDM-style form (P-2D). Calling these values “ISO 8601” in docstrings (and UI titles) is misleading. Consider updating wording to something like “ISO 8601 (plus USDM-style P-… durations)” to match actual accepted inputs.
| """Test that various valid ISO 8601 durations are accepted.""" | |
| """Test that various valid ISO 8601 durations (plus USDM-style `P-…` durations) are accepted.""" |
|
The checks are reporting incorrectly so closing this PR |
Updates to requirements.txt - removed numpy
Udpates all-or-nothing checks for window Timings