Round-trip a scalar wait_until as a scalar - #2825
Conversation
The parser stores a bare scalar under id when the catalog shorthand names a
condition gate or an action-list key, but the emitter kept the catalog key and
could never collapse it, so a scalar wait_until was rewritten as
wait_until: {id: ...}. One shared shorthand_key helper now decides the collapse
key for both sides.
|
@esphbot review |
Merging this PR will not alter performance
Comparing Footnotes
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2825 +/- ##
=======================================
Coverage 99.75% 99.75%
=======================================
Files 294 294
Lines 25384 25421 +37
=======================================
+ Hits 25321 25359 +38
+ Misses 63 62 -1
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
No unresolved blocking issues were identified, and targeted round-trip tests are included.
Review effort: Lite
Findings: None
What changed in this PR
Fixes scalar wait_until round-tripping by sharing shorthand-key resolution between parsing and emitting.
Changes:
- Adds gate/action-list-aware shorthand resolution.
- Reuses the helper in parsing and emission.
- Adds scalar and lambda round-trip tests.
| File | Summary |
|---|---|
tests/test_automations_writer.py |
Tests wait_until lambda round-tripping. |
tests/test_automations_branches.py |
Adds catalog-wide scalar shorthand coverage. |
esphome_device_builder/controllers/automations/parsing.py |
Re-exports the shared helper. |
esphome_device_builder/controllers/automations/emitter.py |
Uses shared shorthand resolution. |
esphome_device_builder/controllers/automations/_decompose.py |
Implements shared shorthand-key logic. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
shorthand_key and its id fallback live in helpers.automation_keys with CONDITION_GATE_KEYS, so the parser and emitter import the rule directly and parsing no longer re-exports it. scalar_param_key gives the parser the total form. The catalog-wide test pins the emit and re-parse round trip instead of restating the rule.
|
@esphbot review |
|
|
b9f8323 to
96354bc
Compare
|
@esphbot review |
esphbot
left a comment
There was a problem hiding this comment.
Tip
No blocking issues found — ready to merge.
|
@esphbot review |
|
@esphbot review |
esphome validates a string condition as that id with no config, so
wait_until: api.connected and if: {condition: api.connected} decompose to a
condition node instead of a phantom id param or a dropped gate; a non-string
scalar under wait_until still round-trips as a scalar.
|
The review ran against 4873c27; the docstring and catalog-test findings were already addressed in b9f8323 (the suggested fixpoint assertion and the Finding 3 taken in afff943: a bare string in a condition position now decomposes to that condition id with no config, which is how esphome's registry validator reads it, so Finding 2 declined: the @esphbot review |
Confirmed against String path covers strings only. A Two new suggestions: unknown bare string under |
|
|
esphbot
left a comment
There was a problem hiding this comment.
Tip
No blocking issues found — ready to merge.
… bodies A string under wait_until becomes a condition only when the catalog knows the id; a substitution or a typo stays the lossless id param. A condition body that is neither a mapping, a condition id nor a list of those faults the automation instead of decomposing to no gate, which the next save would have deleted.
|
Suggestion 1 taken in 452cd19: the string path is gated on Finding 3 taken in the same commit: a condition body that is not a mapping, a condition id, or a list of those (an Finding 4 resolves with suggestion 1: an unknown string re-parses to the same Suggestion 2 declined: collapsing a lone param-less condition back to the string spelling would also rewrite the documented @esphbot review |
Verified 452cd19. Gate checks |
|
|
An !include or other tagged scalar in a condition position is valid YAML the tree cannot represent, so it takes the unsupported path the editor renders as the edit-in-YAML hint; a malformed body stays a plain invalid_args error.
esphbot
left a comment
There was a problem hiding this comment.
Tip
No blocking issues found — ready to merge.
|
Taken in 5547721: a tagged scalar in a condition position raises @esphbot review |
Confirmed at 5547721. |
|
|
|
Suggestion 1 taken in 7f7f817: the class, Suggestion 2 is the pre-existing action-side drop and stays a follow-up, as you note. On the @esphbot review |
esphbot
left a comment
There was a problem hiding this comment.
Tip
No blocking issues found — ready to merge.
Confirmed resolved. Checked all four surfaces: Deferral of suggestion 2 accepted. Filed as
One new note: line 199 gates on |
|
|
esphbot
left a comment
There was a problem hiding this comment.
Tip
No blocking issues found — ready to merge.
is_known_condition answers from the condition id set, so the parser's per-string check never loads a body and cannot mistake a missing body for an unknown id.
|
Suggestion 1 taken in ae0de0c: Finding 3 declined: Finding 2 remains the deferred action-side follow-up. @esphbot review |
Verified ae0de0c. Finding 3 decline accepted. Finding 2 carried as |
PR Review — Round-trip a scalar wait_until as a scalarMerge-ready. The last open suggestion is fixed in ae0de0c, and the one remaining finding is the author's own deferred follow-up. Verified statically against the head checkout (
✅ Resolved since last review (1)Previously-flagged issues verified fixed
🟢 Suggestions
1. [Deferred] Action-list entries that are not mappings are still dropped silently
|
esphbot
left a comment
There was a problem hiding this comment.
Tip
No blocking issues found — ready to merge.
What does this implement/fix?
A scalar
wait_untilwas rewritten on every save aswait_until: {id: ...}. The parser stores a bare scalar underidwhen the catalog shorthand is a gate key, but the emitter kept the catalog key and never collapsed it back. One sharedshorthand_keyhelper inhelpers/automation_keys.pynow decides the key for both sides; a catalog wide test pins the emit and re-parse round trip.A bare string in a condition position is the condition id with no config, as esphome reads it, so
wait_until: api.connecteddecomposes to its condition andif: {condition: api.connected}no longer loses the gate on save; a non-string scalar underwait_untilstill round-trips as written.Related issue or feature (if applicable):
Types of changes
bugfixnew-featureenhancementbreaking-changerefactordocsmaintenancecidependenciesFrontend coordination
Checklist
ruff,codespell, yaml/json/python checks).tests/where applicable.components.index.json/definitions/components/*.jsonhave not been hand-edited (regenerate viascript/sync_components.pyif a sync is needed).docs/ARCHITECTURE.mdand/ordocs/API.md.