Summary
When a #[staticmethod] declares its first parameter with a self-shaped type (PyRef<'_, Self>, PyRefMut<'_, Self>, Bound<'_, Self>, &Bound<'_, Self>, or Py<Self>), the parameter is silently dropped from the generated .pyi stub. The runtime function still expects the argument, so the stub disagrees with the actual signature.
Reproduction
#[gen_stub_pymethods]
#[pymethods]
impl A {
#[staticmethod]
fn from_bound(a: Bound<'_, Self>) -> usize {
a.borrow().x
}
}
Generated stub:
@staticmethod
def from_bound() -> int: ... # `a` is missing
Root cause
parse_args in pyo3-stub-gen-derive/src/gen_stub/arg.rs skips first-position arguments matching the receiver shapes whenever the inner generic is the literal Self. It has no knowledge of MethodType, so the same skip fires for #[staticmethod] (and would for free #[pyfunction]s if Self were syntactically writable there).
Note
This is a pre-existing issue. It existed before #455 for PyRef<'_, Self> / PyRefMut<'_, Self> and was extended to Bound/Py by that PR. #455 strictly improves the common (instance method) case; this edge was surfaced during review and is being tracked separately.
Possible fixes
- Plumb
MethodType (or just an is_static flag) into parse_args and skip the receiver only for instance methods.
- Move receiver detection out of
parse_args and into method.rs, where the method kind is already known.
Severity
Low. Self-shaped first arguments on #[staticmethod] are very unusual in practice — but the failure mode (silent stub/runtime divergence) is bad, so a fix is worth doing once the structural change above is on the table.
Summary
When a
#[staticmethod]declares its first parameter with a self-shaped type (PyRef<'_, Self>,PyRefMut<'_, Self>,Bound<'_, Self>,&Bound<'_, Self>, orPy<Self>), the parameter is silently dropped from the generated.pyistub. The runtime function still expects the argument, so the stub disagrees with the actual signature.Reproduction
Generated stub:
Root cause
parse_argsinpyo3-stub-gen-derive/src/gen_stub/arg.rsskips first-position arguments matching the receiver shapes whenever the inner generic is the literalSelf. It has no knowledge ofMethodType, so the same skip fires for#[staticmethod](and would for free#[pyfunction]s ifSelfwere syntactically writable there).Note
This is a pre-existing issue. It existed before #455 for
PyRef<'_, Self>/PyRefMut<'_, Self>and was extended toBound/Pyby that PR. #455 strictly improves the common (instance method) case; this edge was surfaced during review and is being tracked separately.Possible fixes
MethodType(or just anis_staticflag) intoparse_argsand skip the receiver only for instance methods.parse_argsand intomethod.rs, where the method kind is already known.Severity
Low. Self-shaped first arguments on
#[staticmethod]are very unusual in practice — but the failure mode (silent stub/runtime divergence) is bad, so a fix is worth doing once the structural change above is on the table.