Skip to content

Fix invalid type annotations in generated SeleniumLibrary stub - #1997

Draft
simonyang08 wants to merge 1 commit into
robotframework:masterfrom
simonyang08:codex/sl-1919-fix-broken-stubs
Draft

Fix invalid type annotations in generated SeleniumLibrary stub#1997
simonyang08 wants to merge 1 commit into
robotframework:masterfrom
simonyang08:codex/sl-1919-fix-broken-stubs

Conversation

@simonyang08

Copy link
Copy Markdown

Fixes #1919

Root cause

gen_stub.py rendered every typing.Union[...], typing.Optional[...], and PEP 604 X | Y annotation as a bare Union, because all three expose __name__ == "Union" and the generator trusted hasattr(t, "__name__"). keyword_line also wrapped Optional[...] around every None-defaulted parameter even when the type already included None. Together this produced the invalid annotations in SeleniumLibrary/__init__.pyi (Optional[Optional], bare Union, modifier: Union = False, parent: WebElement = None) reported in the issue.

Fix

  • get_type_string_from_type now discriminates unions properly (typing.Union/Optional via get_origin, PEP 604 via types.UnionType), filters NoneType out of the members, and recurses so parameters render as Union[WebElement, str, list], Optional[str], etc.
  • keyword_line only wraps Optional[...] when the rendered type does not already include None.
  • The boilerplate block now imports Secret and FirefoxProfile, which keyword annotations reference (matching the source imports in browsermanagement.py / formelement.py).
  • src/SeleniumLibrary/__init__.pyi regenerated.

__init__.pyi is a generated artifact — the hand-written change is confined to gen_stub.py.

Verification

  • mypy --ignore-missing-imports on the regenerated stub in an isolated directory: 0 errors (the old committed stub reports 64, including 6+ incompatible-default hard errors and 107 bare Union renders).
  • Zero occurrences remain of Optional[Optional], bare Union, Union = defaults, or unimported names.
  • Regeneration is reproducible: identical stub output under robotframework-pythonlibcore 4.4.1 (requirements floor) and 4.6.0, RF 7.4.2, selenium 4.48, Python 3.14.
  • utest/run.py: 258 passed, 2 skipped (unchanged from master).

Notes for maintainers

  • The regenerated stub also picks up drag_and_drop_across_frames and get_css_property_value, which existed in the source but were missing from the stale committed stub — no new keywords were added by this PR.
  • Out of scope (separate decisions, happy to help with either): removing the stub in favor of inline annotations + py.typed (as discussed in the issue), and adding -> None return annotations in the generator (the remaining mypy [no-untyped-def] reports).

DCO: Signed-off-by: simonyang08 <ppt5928@gmail.com>.

The generator emitted invalid PEP 484 annotations in
src/SeleniumLibrary/__init__.pyi:

- Optional[Optional] (and Optional[Union[...]]) when an argument type
  already accepted None. get_type_string_from_type fell back to
  argument_type.__name__, which is 'Union' for typing.Union,
  typing.Optional and PEP 604 union types. keyword_line then wrapped
  that with Optional[...] whenever the default was None.
- Bare 'Union' for any union-typed argument (e.g. locators), because
  every union form exposes __name__ == 'Union'.
- Incompatible defaults such as 'modifier: Union = False' because the
  bare-Union type was paired with the runtime default.

Rewrite get_type_string_from_type to walk typing.get_origin /
get_args so typing.Union, typing.Optional and PEP 604 types.UnionType
all expand to a valid Union[...] form, and teach keyword_line to skip
the Optional[...] wrap when the rendered type already accepts None.

Follow-up: the more accurate Union[...] rendering exposes two extra
symbols (Secret in input_password/input_text, FirefoxProfile in
open_browser) that the previous bare-Union stub never referenced. Add
matching imports to the pyi boilerplate so the generated stub stays
self-contained. Also fix the pre-existing find_elements(parent:
WebElement = None) row in the boilerplate.

Regenerated src/SeleniumLibrary/__init__.pyi with 'python3 gen_stub.py'.

Validation: mypy --ignore-missing-imports on the regenerated stub in
an isolated directory goes from 3 errors (3x [name-defined] for
Secret / FirefoxProfile) on the previous patch to 0 errors. Full
utest run remains green (258 passed, 2 skipped, unchanged).

Closes robotframework#1919 (annotation validity portion; py.typed and stub deletion
are separate decisions left to the maintainers).

Signed-off-by: simonyang08 <ppt5928@gmail.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.

stubs are completely broken

2 participants