-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
More precisely type pipe
methods
#10038
Changes from all commits
54475ed
369bb32
9815d61
e28f100
73f92c9
5d859b2
a6f9ef5
95084f1
d92b992
a9307cf
83b59fa
6d6083e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -6,7 +6,7 @@ | |||||
from contextlib import suppress | ||||||
from html import escape | ||||||
from textwrap import dedent | ||||||
from typing import TYPE_CHECKING, Any, TypeVar, Union, overload | ||||||
from typing import TYPE_CHECKING, Any, Concatenate, ParamSpec, TypeVar, Union, overload | ||||||
|
||||||
import numpy as np | ||||||
import pandas as pd | ||||||
|
@@ -60,6 +60,7 @@ | |||||
T_Resample = TypeVar("T_Resample", bound="Resample") | ||||||
C = TypeVar("C") | ||||||
T = TypeVar("T") | ||||||
P = ParamSpec("P") | ||||||
|
||||||
|
||||||
class ImplementsArrayReduce: | ||||||
|
@@ -718,11 +719,27 @@ def assign_attrs(self, *args: Any, **kwargs: Any) -> Self: | |||||
out.attrs.update(*args, **kwargs) | ||||||
return out | ||||||
|
||||||
@overload | ||||||
def pipe( | ||||||
self, | ||||||
func: Callable[Concatenate[Self, P], T], | ||||||
*args: P.args, | ||||||
**kwargs: P.kwargs, | ||||||
) -> T: ... | ||||||
|
||||||
@overload | ||||||
def pipe( | ||||||
self, | ||||||
func: Callable[..., T] | tuple[Callable[..., T], str], | ||||||
func: tuple[Callable[..., T], str], | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not this as well?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We cannot do that because when we pass the function as part of a tuple we don't have enough information to precisely type the function's parameters. In your suggested change, the ParamSpec If that's as clear as mud, let me try to clarify with more detail. In the first form, where we pass only a function as the first argument to This means we can type the function more precisely, like so, indicating that the data parameter is first, concatenated with zero or more positional and keyword parameters (and returning a value of some type
Therefore, after passing
However, when we pass a function/keyword 2-tuple as the first argument to This means, we cannot do the following, as you suggest, because in this case
To clarify, although Technically speaking, as far as mypy is concerned, your suggestion probably make no difference from what I propose, but in terms of the information it conveys to the reader, it is incorrect. This is why I discourage the use of the tuple form, and instead recommend the use of a For example (taken from the test cases in
IMHO, the tuple form should not be supported, for this very reason, but I don't expect that deprecating that form would get much traction from anybody else. |
||||||
*args: Any, | ||||||
**kwargs: Any, | ||||||
) -> T: ... | ||||||
|
||||||
def pipe( | ||||||
self, | ||||||
func: Callable[Concatenate[Self, P], T] | tuple[Callable[P, T], str], | ||||||
*args: P.args, | ||||||
**kwargs: P.kwargs, | ||||||
) -> T: | ||||||
""" | ||||||
Apply ``func(self, *args, **kwargs)`` | ||||||
|
@@ -840,15 +857,19 @@ def pipe( | |||||
pandas.DataFrame.pipe | ||||||
""" | ||||||
if isinstance(func, tuple): | ||||||
func, target = func | ||||||
# Use different var when unpacking function from tuple because the type | ||||||
# signature of the unpacked function differs from the expected type | ||||||
# signature in the case where only a function is given, rather than a tuple. | ||||||
# This makes type checkers happy at both call sites below. | ||||||
f, target = func | ||||||
if target in kwargs: | ||||||
raise ValueError( | ||||||
f"{target} is both the pipe target and a keyword argument" | ||||||
) | ||||||
kwargs[target] = self | ||||||
return func(*args, **kwargs) | ||||||
else: | ||||||
return func(self, *args, **kwargs) | ||||||
return f(*args, **kwargs) | ||||||
|
||||||
return func(self, *args, **kwargs) | ||||||
|
||||||
def rolling_exp( | ||||||
self: T_DataWithCoords, | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, not ideal to use the test name, but v nice comment