Skip to content

Stubs: flatten all service field sections, annotate multiple selectors as lists - #878

Merged
craigbarratt merged 1 commit into
custom-components:masterfrom
jeyrb:stubs-sections-and-multiple
Nov 7, 2026
Merged

craigbarratt merged 1 commit into
custom-components:masterfrom
jeyrb:stubs-sections-and-multiple

Conversation

@jeyrb

@jeyrb jeyrb commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

I encountered this when trying to make sure Supernotify worked well with Pyscript.

It has its own notify action now, which is much richer than the plain vanilla notify.send_message style to be easier to use from the actions UI. So a more complicated services.yaml, though other integrations might similarly be pushing what the configflow UI can do.

Problem

pyscript.generate_stubs gets the signature wrong for services whose services.yaml uses sections or multiple selectors.

  • Sections. fix stub generator dropping additional_fields entries #867 flattened the sections named additional_fields and advanced_fields, but a section can have any name. Any other section becomes a bogus untyped parameter, and the fields inside it are dropped.
  • multiple: true. A text, select or entity selector with multiple: true takes a list, but is annotated as a single value, so passing a list is reported as a type error.

For example, a service with a multimedia section and a multiple text field currently generates:

def notify(*, message: str | None=None, delivery: str | None=None, multimedia=None): ...

Change

  • A field is treated as a section when it has fields and no selector, whatever its name.
  • A selector with multiple: true is annotated as list[...] of its usual type.

The same service now generates:

def notify(*, message: str | None=None, delivery: list[str] | None=None, camera_entity_id: str | None=None, snapshot_url: str | None=None): ...

Testing

Added test_stubs_flatten_named_sections_and_multiple, which fails on master and passes with this change. The existing stub tests still pass.

@jeyrb
jeyrb marked this pull request as ready for review October 8, 2026 12:43

@craigbarratt craigbarratt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! Flattening sections and handling multiple selectors are both good improvements. I've left a few inline comments. The main one is the duplicate-parameter case, which can make the generated stub file fail to parse. The list[...] annotation is also stricter than what Home Assistant accepts, which leads to type errors on valid calls.

Also, #867 has since been merged and changes the same section-flattening code in _build_services (advanced_fields → additional_fields), so this will need a rebase onto current master.

Comment thread tests/test_stubs.py Resolved
@jeyrb
jeyrb force-pushed the stubs-sections-and-multiple branch from f8db2c4 to 153b8fb Compare November 6, 2026 19:08
@jeyrb

jeyrb commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for feedback, rebased and addressed

@jeyrb

jeyrb commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review. I've rebased onto current master (including #867) and squashed into a single commit. Each inline comment is addressed in its thread.

@craigbarratt craigbarratt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick turnaround! I've checked all the fixes against the code and they look good, and tests/test_stubs.py passes locally. Two small things remain, both easy to fix. Once they're in, I'm happy to merge. I'll handle a few other minor type-annotation edge cases in a follow-up commit after merging.

…ultiple selectors

- treat any field with a dict of field dicts under `fields` and no `selector`
  as a UI section and flatten it, whatever its name
- skip duplicate field names across top level and sections, so the generated
  stub module always parses
- annotate `multiple: true` selectors as `T | list[T]`, matching cv.ensure_list,
  using the `multiple` flag of the selector entry that set the base type
- check default/annotation compatibility on AST names, not a substring of the
  unparsed annotation
- clean up generated stubs in a finally block in the new test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jeyrb
jeyrb force-pushed the stubs-sections-and-multiple branch from 153b8fb to 860a26b Compare November 7, 2026 08:56
@craigbarratt
craigbarratt merged commit a11a1ff into custom-components:master Nov 7, 2026
6 checks passed
@craigbarratt

Copy link
Copy Markdown
Member

Thanks for the PR!

craigbarratt added a commit that referenced this pull request Nov 7, 2026
Follow-up to #878:
- parse SELECTOR_SIMPLE_TYPES entries so compound types like
  tuple[int, int, int] have real Name nodes for the default check
- don't widen an annotation that already accepts the default
  (Any, or a Literal that includes it)
- treat any field whose fields is a dict of dicts as a section, as
  HA's _SERVICE_SCHEMA does, even if it also has a selector
- check the generated signature via ast instead of substrings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants