-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
TYP: Improve clip() return and argument typing. #40860
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
Conversation
DriesSchaumont
commented
Apr 9, 2021
•
edited
Loading
edited
- closes TYP return type of DataFrame.clip not correct #40829
- Ensure all linting tests pass, see here for how to run them
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.
This is off to a good start!
You have overloads for:
- ✅
inplace: Literal[False] = ...
- ✅
inplace: bool = ...
- ✅
inplace: Literal[True]
:- when
lower
,upper
, andaxis
are passed - when
lower
andupper
, but notaxis
, are passed
- when
You're missing:
inplace: Literal[True]
:- when
lower
andaxis
, but notupper
, are passed - when
upper
andaxis
, but notlower
, are passed - when
lower
, but notaxis
orupper
, is passed - when
upper
, but notaxis
orlower
, is passed - when
axis
, but notlower
orupper
, is passed - when none of
axis
,lower
, orupper
are passed
- when
Thank you for this nice overview! I will try to add these cases. I am a bit confused on how to handle the syntax for: "when
|
can you try @overload
def clip(
self: FrameOrSeries,
*
upper,
inplace: Literal[True],
*args,
**kwargs,
) -> None:
... ? |
Thanks! I think I got them all now. Could you check if I did everything right? I am quite new to type overloading. |
Congrats for having braved this not-so-simple issue then! To check if you've done it correctly, could you make a new file If you could do that, and paste here the content of |
I think the last one are correct - if If you repeat the first block but put |
Yes, just as I left my last comment (which I then deleted), I realized my mistake. Here is the file and the output!
|
@MarcoGorelli thank you for the guidance and the explanations! |
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.
Nice one, thanks @DriesSchaumont ! Just left a small comment about how you've typed axis
in some overloads but not in others, other than that this looks good to me (cc @simonjayhawkins in case you have further comments)
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.
lgtm
self: FrameOrSeries, | ||
lower=..., | ||
upper=..., | ||
axis: Axis | None = ..., |
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.
users of the pandas api should not pass None.
axis: int or str axis name, optional
for the default (should be listed in the docstring instead of optional - not for this PR though), the argument should not be passed.
@MarcoGorelli what are you thoughts about not including None
in the overloads and also now that we are using PEP 604, removing no_implicit_optional = True
from setup.cfg
and excluding None
actual function signatures too?
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.
Hey @simonjayhawkins
+1 on removing no_implicit_optional
Not sure what you mean about not including None
in overloads - if axis=None
is passed internally, then won't it need to be in one of the overloads for type checking to work?
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.
I guess the question is (in general) should None
ever be passed internally or should kwargs always be (in general) validated at the top level.
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.
IIRC we have had issues reported where None
is passed by users and when we change defaults (I think bool True/False in a specific case I remember recently) this is results in a perceived regression. We also sometime use lib.nodefault
to detect if a kwarg has been specified. So I was thinking to that discouraging users passing None
could be worthwhile.
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.
@simonjayhawkins I looked into the no_implicit_optional = True
, but it seems it's only possible to omit if you only have two possible types.
e.g. the following works:
from __future__ import annotations
from typing import Tuple
def foo(
a: str | int | None = None,
b: str = None,
): ...
but the following doesn't:
from __future__ import annotations
from typing import Tuple
def foo(
a: str | int = None,
b: str = None,
): ...
, we get
t.py:5: error: Incompatible default for argument "a" (default has type "None", argument has type "Union[str, int]") [assignment]
Found 1 error in 1 file (checked 1 source file)
So I think it's cleaerer to keep no_implicit_optional
* Improve clip() typing. * Update typing. * More clip overloads. * Add missing axis types