-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
TYP: setter for index/columns property-like (AxisProperty) #46565
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
Changes from 1 commit
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 |
---|---|---|
@@ -1,9 +1,28 @@ | ||
# pyright: reportIncompleteStub = false | ||
from typing import Any | ||
from typing import ( | ||
Sequence, | ||
overload, | ||
) | ||
|
||
from pandas._typing import ( | ||
AnyArrayLike, | ||
DataFrame, | ||
Index, | ||
Series, | ||
) | ||
|
||
# note: this is a lie to make type checkers happy (they special | ||
# case property). cache_readonly uses attribute names similar to | ||
# property (fget) but it does not provide fset and fdel. | ||
cache_readonly = property | ||
|
||
def __getattr__(name: str) -> Any: ... # incomplete | ||
class AxisProperty: | ||
|
||
axis: int | ||
def __init__(self, axis: int = ..., doc: str = ...) -> None: ... | ||
@overload | ||
def __get__(self, obj: DataFrame | Series, type) -> Index: ... | ||
@overload | ||
def __get__(self, obj: None, type) -> AxisProperty: ... | ||
def __set__( | ||
self, obj: DataFrame | Series, value: AnyArrayLike | Sequence | ||
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. type annotation for 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. Just an idea, might be not worth it to enforce that IndexCompatibleT = TypeVar("IndexCompatibleT", AnyArrayLike, Sequence)
class Has_set_axis(Protocol[IndexCompatibleT]):
def _set_axis(self: NDFrame, axis: int, value: IndexCompatibleT) -> object:
...
def __set__(self, obj: Has_set_axis[IndexCompatibleT], value: IndexCompatibleT) -> None:
... 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. from the other response, I think that only NDFrame objects use AxisProperty and we tend to avoid NDFrame in annotations that would be part of the public API since NDFrame is not public, but obviously need to use it in some circumstances. Until the other issue is resolved, I'm not sure I can comment on whether we would be better off using a protocol here instead. 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. to be fair, 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. the index/column properties are only actually added to DataFrame/Series in the codebase. In theory they could be added to any NDFrame object and I suppose we could refactor the code to add the AxisProperty dynamically in the base class based on the other NDFrame attributes, i.e. we know the axis numbers and names. Having said that, i'm -1 on doing this dynamically and therefore happy with the DataFrame|Series to match the actual code. |
||
) -> None: ... |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -234,8 +234,12 @@ def transform(self) -> DataFrame | Series: | |
and not obj.empty | ||
): | ||
raise ValueError("Transform function failed") | ||
# error: Argument 1 to "__get__" of "AxisProperty" has incompatible type | ||
# "Union[Series, DataFrame, GroupBy[Any], SeriesGroupBy, | ||
# DataFrameGroupBy, BaseWindow, Resampler]"; expected "Union[DataFrame, | ||
# Series]" | ||
if not isinstance(result, (ABCSeries, ABCDataFrame)) or not result.index.equals( | ||
obj.index | ||
obj.index # type:ignore[arg-type] | ||
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. not investigated this one yet. maybe fix later. 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. Is A slightly (too) complex approach would be to use a Protocol for 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. I'm not sure that all those objects are valid e.g. I assume that the condition should be narrowing to DataFrame/Series from the error message. |
||
): | ||
raise ValueError("Function did not transform") | ||
|
||
|
@@ -639,7 +643,11 @@ class NDFrameApply(Apply): | |
|
||
@property | ||
def index(self) -> Index: | ||
return self.obj.index | ||
# error: Argument 1 to "__get__" of "AxisProperty" has incompatible type | ||
# "Union[Series, DataFrame, GroupBy[Any], SeriesGroupBy, | ||
# DataFrameGroupBy, BaseWindow, Resampler]"; expected "Union[DataFrame, | ||
# Series]" | ||
return self.obj.index # type:ignore[arg-type] | ||
|
||
@property | ||
def agg_axis(self) -> Index: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -270,9 +270,9 @@ def aggregate(self, func=None, *args, engine=None, engine_kwargs=None, **kwargs) | |
func = maybe_mangle_lambdas(func) | ||
ret = self._aggregate_multiple_funcs(func) | ||
if relabeling: | ||
# error: Incompatible types in assignment (expression has type | ||
# "Optional[List[str]]", variable has type "Index") | ||
ret.columns = columns # type: ignore[assignment] | ||
# columns is not narrowed by mypy from relabeling flag | ||
assert columns is not None # for mypy | ||
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. not yet ran the tests locally to check we don't get failures but it appears |
||
ret.columns = columns | ||
return ret | ||
|
||
else: | ||
|
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.
There is an issue with mypy that can't resolve the types for the decorated methods that IIRC @jbrockmendel encountered before when adding the stubs for the Cython code initially. It seems to be related to the imports and putting them here seems prevent the problem resurfacing.