diff --git a/mypy/stubgen.py b/mypy/stubgen.py index fe90c3d256b7..cc207db42152 100755 --- a/mypy/stubgen.py +++ b/mypy/stubgen.py @@ -607,7 +607,10 @@ def _get_func_args(self, o: FuncDef, ctx: FunctionContext) -> list[ArgSig]: if not isinstance(get_proper_type(annotated_type), AnyType): typename = self.print_annotation(annotated_type) - if actually_pos_only_args and arg_.pos_only: + # A keyword-only argument is never positional-only, even when its name + # starts with two underscores, so it must not move the "/" marker past + # the "*" separator. + if actually_pos_only_args and arg_.pos_only and not kind.is_named(): pos_only_marker_position += 1 if kind.is_named() and not any(arg.name.startswith("*") for arg in args): diff --git a/test-data/unit/stubgen.test b/test-data/unit/stubgen.test index 0c8b74ecf29a..9a7d4e8313a1 100644 --- a/test-data/unit/stubgen.test +++ b/test-data/unit/stubgen.test @@ -4566,6 +4566,18 @@ def f6(x: int = 0, /, *, y: float): ... def f7(x: int, /, *, y: float = 1): ... def f8(x: int = 0, /, *, y: float = 1): ... +[case testHistoricalPosOnlyParamsWithKeywordOnly] +def f1(*, __kw): ... +def f2(x, /, *, __kw): ... +def f3(__pos, *, kw): ... +def f4(__pos, __other, *, __kw): ... + +[out] +def f1(*, __kw) -> None: ... +def f2(x, /, *, __kw) -> None: ... +def f3(__pos, /, *, kw) -> None: ... +def f4(__pos, __other, /, *, __kw) -> None: ... + [case testPreserveEmptyTuple] ann: tuple[()] alias = tuple[()]