-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
pow(complex(…), <value>, <value>)
and pow(float(…), <value>, <value>)
should produce type errors
#6303
Comments
I don't think the fix can be as simple as simply removing the third argument of >>> pow(1.0, 2, None)
1.0
>>> 1.0.__pow__(2, None)
1.0
>>> pow(complex(1), 2, None)
(1+0j)
>>> complex(1).__pow__(3, None)
(1+0j) |
Perhaps if we changed from typing import TypeVar
_M = TypeVar("_M", contravariant=True) to from typing import TypeVar, SupportsIndex
_M = TypeVar("_M", contravariant=True, bound=SuppprtsIndex) ? |
And, to be fair, this works just fine at runtime: >>> pow(complex(1), 2, None)
(1+0j) In the |
Yeah, sort of. I think Mypy currently thinks |
Gotta go but some WIP experiments here https://mypy-play.net/?mypy=latest&python=3.10&flags=show-error-codes%2Cstrict&gist=b079cabb8620757ef16301a2dc12a352 |
Hmm, it's not the best error message, but this does seem to work: https://mypy-play.net/?mypy=latest&python=3.10&flags=show-error-codes%2Cstrict&gist=4e463e07a3a48610e140a4c98c18b0ca It involves changing the 5th overload from def pow(base: float, exp: float, mod: None = ...) -> Any: ... to def pow(base: complex, exp: complex, mod: None = ...) -> Any: ... as well as the change to the But, I haven't yet tested it with classes outside builtins. |
That's some expert level deep typing voodoo. I just thought of another wrinkle. Mypy treats I also just noticed that >>> pow(Decimal("1.0"), Decimal("1.0"), Decimal("1.0")) # works
Decimal('0') |
Weird false-positive error in this implementation if you try to do |
This is a better solution, I think -- introduce a third protocol to deal with classes that accept "three-argument from typing import TypeVar, Protocol, Any, Literal, NoReturn, overload
_E = TypeVar("_E", contravariant=True)
_M = TypeVar("_M", contravariant=True)
_T_co = TypeVar("_T_co", covariant=True)
class _SupportsPow2(Protocol[_E, _T_co]):
def __pow__(self, other: _E) -> _T_co: ...
class _SupportsPow3NoneOnly(Protocol[_E, _T_co]):
def __pow__(self, other: _E, modulo: None = ...) -> _T_co: ...
class _SupportsPow3(Protocol[_E, _M, _T_co]):
def __pow__(self, other: _E, modulo: _M = ...) -> _T_co: ...
@overload
def pow(base: int, exp: int, mod: Literal[0]) -> NoReturn: ...
# int base & positive-int exp -> int; int base & negative-int exp -> float
# return type must be Any as `int | float` causes too many false-positive errors
@overload
def pow(base: int, exp: int, mod: None = ...) -> Any: ...
@overload
def pow(base: int, exp: int, mod: int) -> int: ...
@overload
def pow(base: float, exp: int, mod: None = ...) -> float: ...
# float base & float exp could return float or complex
# return type must be Any as `float | complex` causes too many false-positive errors
@overload
def pow(base: complex, exp: complex, mod: None = ...) -> Any: ...
@overload
def pow(base: _SupportsPow2[_E, _T_co], exp: _E, mod: None = ...) -> _T_co: ...
@overload
def pow(base: _SupportsPow3NoneOnly[_E, _T_co], exp: _E, mod: None = ...) -> _T_co: ...
@overload
def pow(base: _SupportsPow3[_E, _M, _T_co], exp: _E, mod: _M = ...) -> _T_co: ... There's still a false positive with |
I definitely need to up my |
I don't think this actually solves your original problem, but, er, here's a PR fixing some other problems with |
@posita, I think this should maybe be refiled as a mypy issue now, since we now get error messages in the right places, it's just not the right kind of error messages. That feels like more of a mypy issue rather than a typeshed issue -- WDYT? 🙂 |
Closing as per my comments here |
complex
's versions of__pow__
and__rpow__
invite the third modulo argument. That means that the following validates, when it shouldn't:This applies to
float
s as well.These are guaranteed to fail at runtime, even if the first arguments are losslessly convertible to
int
s:I can't find an issue tracking this, and I don't think this is fixed by #6287.
As an aside, this "works" (in the sense it properly generates some error, but not what I would expect):
That second error might just be some variation on python/mypy#3186, however?
The text was updated successfully, but these errors were encountered: