Commit ae80391
authored
Fix: current-module prefix stripping (#301)
`fix.py`:
Current-module prefix stripping now also walks nested annotation
parameters instead of only the outer type. The fix covers the exact
shapes that broke in my downstream projects (pyAMReX, ImpactX):
`list[...]`, `typing.Optional[...]`, and `dict[..., ...]` for the type
`...`.
Concrete example seen downstream in ImpactX for
`impactx.MADXParser.*` types: LHS broken -> RHS correct now.
- `list[impactx.MADXParser.Token]` -> `list[Token]`
- `typing.Optional[impactx.MADXParser.Expression]` ->
`typing.Optional[Expression]`
- `dict[str, impactx.MADXParser.Expression]` -> `dict[str, Expression]`
This originated in a pure Python file that is used on top of pybind11
modules. I have seen similar issues for a while though and [patch
around](https://github.com/AMReX-Codes/pyamrex/blob/26.04/.github/update_stub.sh#L20-L26)
them
[awkwardly](https://github.com/BLAST-ImpactX/impactx/blob/26.03/.github/update_stub.sh#L19-L21).
`parse.py`:
Runtime generic annotations are parsed before falling back to opaque
values, and `_is_generic_alias()` now also recognizes typing generics
like `Optional[...]`
<details>
<summary>Reproducer (PyTest)</summary>
```py
"""Regression tests for current-module prefix cleanup in parsed annotations."""
from argparse import Namespace
from types import ModuleType
from pybind11_stubgen import stub_parser_from_args
from pybind11_stubgen.printer import Printer
from pybind11_stubgen.structs import QualifiedName
def make_args() -> Namespace:
"""Build the same parser configuration shape used by the CLI entrypoint."""
return Namespace(
output_dir=".",
root_suffix=None,
ignore_invalid_expressions=None,
ignore_invalid_identifiers=None,
ignore_unresolved_names=None,
ignore_all_errors=False,
enum_class_locations=[],
numpy_array_wrap_with_annotated=False,
numpy_array_use_type_var=False,
numpy_array_remove_parameters=False,
print_invalid_expressions_as_is=False,
print_safe_value_reprs=None,
print_value_comments=False,
exit_code=False,
dry_run=True,
stub_extension="pyi",
module_names=[],
)
def make_module() -> ModuleType:
"""
Create an in-memory module that mirrors the ImpactX regression.
The module intentionally does not use ``from __future__ import annotations``.
That forces Python to evaluate local annotations such as ``list[Token]`` into
runtime generic objects whose string form contains the fully-qualified module
name, e.g. ``list[impactx.MADXParser.Token]``.
"""
module = ModuleType("impactx.MADXParser")
module.__dict__["__name__"] = "impactx.MADXParser"
exec(
"""
from typing import Optional
class Token:
pass
class Expression:
pass
def tokenize(tokens: list[Token], expr: Optional[Expression] = None) -> dict[str, Expression]:
pass
""",
module.__dict__,
)
return module
def test_current_module_prefix_is_stripped_from_runtime_generic_annotations():
"""
Parse a module through the normal stub parser stack and verify that nested
references to names from the current module are rendered as local names.
"""
parser = stub_parser_from_args(make_args())
module = parser.handle_module(QualifiedName.from_str("impactx.MADXParser"), make_module())
assert module is not None
functions = {function.name: function for function in module.functions}
tokenize = functions["tokenize"]
rendered = Printer(invalid_expr_as_ellipses=False).print_function(tokenize)
assert str(tokenize.args[0].annotation) == "list[Token]"
assert str(tokenize.returns) == "dict[str, Expression]"
assert rendered[0] == (
"def tokenize(tokens: list[Token], expr: Expression | None = None) "
"-> dict[str, Expression]:"
)
```
</details>1 parent 3a2dac9 commit ae80391
17 files changed
Lines changed: 286 additions & 38 deletions
File tree
- pybind11_stubgen/parser/mixins
- tests
- py-demo/demo/pure_python
- stubs
- python-3.11
- pybind11-v2.11/numpy-array-wrap-with-annotated/demo/pure_python
- pybind11-v2.12/numpy-array-wrap-with-annotated/demo/pure_python
- pybind11-v2.13
- numpy-array-use-type-var/demo/pure_python
- numpy-array-wrap-with-annotated/demo/pure_python
- pybind11-v2.9/numpy-array-wrap-with-annotated/demo/pure_python
- pybind11-v3.0
- numpy-array-use-type-var/demo/pure_python
- numpy-array-wrap-with-annotated/demo/pure_python
- python-3.12
- pybind11-v2.11/numpy-array-wrap-with-annotated/demo/pure_python
- pybind11-v2.12/numpy-array-wrap-with-annotated/demo/pure_python
- pybind11-v2.13
- numpy-array-use-type-var/demo/pure_python
- numpy-array-wrap-with-annotated/demo/pure_python
- pybind11-v2.9/numpy-array-wrap-with-annotated/demo/pure_python
- pybind11-v3.0
- numpy-array-use-type-var/demo/pure_python
- numpy-array-wrap-with-annotated/demo/pure_python
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
487 | 487 | | |
488 | 488 | | |
489 | 489 | | |
490 | | - | |
491 | | - | |
| 490 | + | |
| 491 | + | |
492 | 492 | | |
493 | 493 | | |
494 | 494 | | |
| |||
516 | 516 | | |
517 | 517 | | |
518 | 518 | | |
519 | | - | |
520 | | - | |
521 | | - | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
522 | 544 | | |
523 | 545 | | |
524 | 546 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
296 | 297 | | |
297 | 298 | | |
298 | 299 | | |
299 | | - | |
300 | | - | |
301 | 300 | | |
302 | 301 | | |
303 | 302 | | |
304 | 303 | | |
| 304 | + | |
| 305 | + | |
305 | 306 | | |
306 | 307 | | |
307 | 308 | | |
| |||
335 | 336 | | |
336 | 337 | | |
337 | 338 | | |
338 | | - | |
339 | | - | |
340 | | - | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
341 | 344 | | |
342 | 345 | | |
343 | 346 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
4 | 12 | | |
5 | 13 | | |
6 | 14 | | |
| |||
11 | 19 | | |
12 | 20 | | |
13 | 21 | | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
Lines changed: 17 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
6 | 18 | | |
7 | 19 | | |
8 | 20 | | |
| |||
11 | 23 | | |
12 | 24 | | |
13 | 25 | | |
14 | | - | |
| 26 | + | |
15 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
Lines changed: 17 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
6 | 18 | | |
7 | 19 | | |
8 | 20 | | |
| |||
11 | 23 | | |
12 | 24 | | |
13 | 25 | | |
14 | | - | |
| 26 | + | |
15 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
Lines changed: 17 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
6 | 18 | | |
7 | 19 | | |
8 | 20 | | |
| |||
11 | 23 | | |
12 | 24 | | |
13 | 25 | | |
14 | | - | |
| 26 | + | |
15 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
Lines changed: 17 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
6 | 18 | | |
7 | 19 | | |
8 | 20 | | |
| |||
11 | 23 | | |
12 | 24 | | |
13 | 25 | | |
14 | | - | |
| 26 | + | |
15 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
Lines changed: 17 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
6 | 18 | | |
7 | 19 | | |
8 | 20 | | |
| |||
11 | 23 | | |
12 | 24 | | |
13 | 25 | | |
14 | | - | |
| 26 | + | |
15 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
Lines changed: 17 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
6 | 18 | | |
7 | 19 | | |
8 | 20 | | |
| |||
11 | 23 | | |
12 | 24 | | |
13 | 25 | | |
14 | | - | |
| 26 | + | |
15 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
Lines changed: 17 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
6 | 18 | | |
7 | 19 | | |
8 | 20 | | |
| |||
11 | 23 | | |
12 | 24 | | |
13 | 25 | | |
14 | | - | |
| 26 | + | |
15 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
0 commit comments