| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
- `PipeFunc` is now `Generic[P, R]` (ParamSpec), so type checkers and IDEs see the wrapped function's parameters and return type on `__call__`, while `PipeFunc` methods like `update_renames` remain fully typed. - The wrapped function's `__doc__` is exposed on the instance for `help()` and Jupyter `?` introspection (skipping class docstrings of callable instances). - Added a `__wrapped__` property following the `functools.wraps` convention; `__signature__` (which reflects renames) still takes precedence for `inspect.signature`. - Set `__test__ = False` so pytest does not collect `PipeFunc` objects wrapping functions named `test*` (pytest follows `__wrapped__`). Note: calls using renamed/scoped parameters are now flagged by type checkers since the static signature is the original one; tests covering that dynamic behavior gained targeted `type: ignore` comments. Continues the work from #910 by @LennartGevers; addresses part of #902. Co-authored-by: Lennart Gevers <lgevers@uni-muenster.de>
Codecov Report✅ All modified and coverable lines are covered by tests.
... and 1 file with indirect coverage changes 🚀 New features to boost your workflow:
|
Sorry, something went wrong.
Merging this PR will not alter performance✅ 6 untouched benchmarks Comparing pipefunc-paramspec-typing (0de5adc) with main (ce55ab7) |
Sorry, something went wrong.
✅ PR Title Formatted CorrectlyThe title of this PR has been updated to match the correct format. Thank you! |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Summary
Addresses the IDE/introspection pain point from #902 and picks up the non-breaking part of #910 by @LennartGevers (credited as co-author). Unlike #910, this keeps PipeFunc.__call__'s pipeline semantics (renames, defaults, bound, hooks, profiling) fully intact — no behavior changes.
PipeFunc is now Generic[P, R] using ParamSpec, and @pipefunc returns PipeFunc[P, R]. Type checkers and IDEs now see the wrapped function's parameter names, types, and return type when calling it, while PipeFunc methods (update_renames, update_scope, ...) stay available and typed:
__doc__ propagation: the wrapped function's docstring is exposed on the instance, so help(f) and Jupyter's f? show the original docs. Class docstrings of callable instances are deliberately not copied.
__wrapped__ property following the functools.wraps convention. inspect.signature is unaffected since the existing __signature__ (which reflects renames/defaults) takes precedence.
__test__ = False on PipeFunc: pytest follows __wrapped__ during collection, so without this it would collect PipeFunc objects wrapping functions named test* (this bit our own tests/integration/map/test_error_handling.py).
Trade-off
The static signature is the original one, so calls using renamed/scoped parameters (f(a1=3) after renames={"a": "a1"}) are now flagged by type checkers even though they work at runtime — ParamSpec cannot express runtime signature rewrites (see the discussion in #910). Runtime behavior is unchanged; tests covering that dynamic behavior gained targeted # type: ignore[call-arg] comments. Unannotated functions are unaffected (gradual typing).
The remaining #910 question — whether __call__ should bypass pipeline semantics entirely — is left open; this PR is forward-compatible with either answer.
Verification
Part of #902; continues #910.
Breaking change (typing only)
PipeFunc was previously Generic[T] with a single type parameter (T bound to Callable). Code that explicitly subscripted it — e.g. x: PipeFunc[Callable[[int], int]] — must update to the new two-parameter form, e.g. PipeFunc[[int], int] or PipeFunc[..., int]. Unsubscripted PipeFunc annotations (the common case, used everywhere internally) are unaffected, and there is no runtime behavior change.