Skip to content

stubtest doesn't expand **kwargs: Unpack[...] #21023

@jbytheway

Description

@jbytheway

Bug Report

I am working on a library where some functions have many keyword arguments in common. Therefore, to reduce code duplication, we're taking advantage of the Python typing feature of defining a TypedDict to give a name to that collection of keyword arguments and using **kwargs: Unpack[...] in the stubs file to document these functions.

However, when these functions are implemented in Rust (using PyO3) and have all the arguments listed separately, stubtest reports errors, even though (I believe) these functions are implemented correctly.

To Reproduce

I've created a minimal example project to demonstrate the problem, but I'll quote the important parts of the implementation here:

The stubs file uses two different approaches to document two functions, which I believe should be equivalent, from a typing perspective:

class _Args(TypedDict):
    a: int
    b: int

def f1(**kwargs: Unpack[_Args]):
    ...

def f2(*, a: int, b: int):
    ...

The Rust implementation implements the two identically:

    #[pyfunction]
    #[pyo3(signature = (*, a, b))]
    fn f1(a: usize, b: usize) -> PyResult<String> {
        Ok((a + b).to_string())
    }

    #[pyfunction]
    #[pyo3(signature = (*, a, b))]
    fn f2(a: usize, b: usize) -> PyResult<String> {
        Ok((a + b).to_string())
    }

Expected Behavior

No stubtest errors.

Actual Behavior

stubtest reports errors for f1, but not for f2:

error: stubtest_unpack._rust.f1 is inconsistent, stub does not have parameter "a"
Stub: in file /home/runner/work/stubtest-unpack/stubtest-unpack/.venv/lib/python3.14/site-packages/stubtest_unpack/_rust.pyi:9
def (**kwargs: Unpack[TypedDict('stubtest_unpack._rust._Args', {'a': builtins.int, 'b': builtins.int})]) -> Any
Runtime:
def (*, a, b)

error: stubtest_unpack._rust.f1 is inconsistent, stub does not have parameter "b"
Stub: in file /home/runner/work/stubtest-unpack/stubtest-unpack/.venv/lib/python3.14/site-packages/stubtest_unpack/_rust.pyi:9
def (**kwargs: Unpack[TypedDict('stubtest_unpack._rust._Args', {'a': builtins.int, 'b': builtins.int})]) -> Any
Runtime:
def (*, a, b)

error: stubtest_unpack._rust.f1 is inconsistent, runtime does not have **kwargs parameter "kwargs"
Stub: in file /home/runner/work/stubtest-unpack/stubtest-unpack/.venv/lib/python3.14/site-packages/stubtest_unpack/_rust.pyi:9
def (**kwargs: Unpack[TypedDict('stubtest_unpack._rust._Args', {'a': builtins.int, 'b': builtins.int})]) -> Any
Runtime:
def (*, a, b)

Found 3 errors (checked 1 module)

Your Environment

You can see the full GitHub CI output generating the above errors, but here are the highlights:

  • Mypy version used: 1.19.1
  • stubtest command-line flags: Nothing beyond the module name.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions