Skip to content

Improve stubs for __pow__ - #6287

Merged
hauntsaninja merged 9 commits into
python:masterfrom
AlexWaygood:improve-pow
Nov 12, 2021
Merged

hauntsaninja merged 9 commits into
python:masterfrom
AlexWaygood:improve-pow

Conversation

@AlexWaygood

Copy link
Copy Markdown
Member

No description provided.

Comment thread stdlib/builtins.pyi Outdated
@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

freqtrade (https://github.com/freqtrade/freqtrade.git)
+ freqtrade/templates/sample_hyperopt_loss.py:47: error: Argument 1 to "exp" has incompatible type "complex"; expected "Union[SupportsFloat, SupportsIndex]"
+ freqtrade/optimize/hyperopt_loss_short_trade_dur.py:48: error: Argument 1 to "exp" has incompatible type "complex"; expected "Union[SupportsFloat, SupportsIndex]"

pandas (https://github.com/pandas-dev/pandas.git)
+ pandas/io/stata.py:2990: error: Incompatible return value type (got "float", expected "int")  [return-value]

vision (https://github.com/pytorch/vision.git)
+ torchvision/models/detection/backbone_utils.py:133: error: Argument 3 to "BackboneWithFPN" has incompatible type "List[float]"; expected "List[int]"  [arg-type]

aiortc (https://github.com/aiortc/aiortc)
+ src/aiortc/rate.py:158: error: Incompatible types in assignment (expression has type "Union[float, complex]", variable has type "float")
+ src/aiortc/rate.py:440: error: Incompatible types in assignment (expression has type "complex", variable has type "float")
+ src/aiortc/rate.py:442: error: Incompatible types in assignment (expression has type "complex", variable has type "float")

prefect (https://github.com/PrefectHQ/prefect.git)
+ src/prefect/utilities/datetimes.py:51: error: Incompatible return value type (got "Union[timedelta, float]", expected "timedelta")
+ src/prefect/utilities/datetimes.py:51: error: Unsupported operand types for * ("None" and "float")
+ src/prefect/utilities/datetimes.py:51: note: Left operand is of type "Optional[timedelta]"

kornia (https://github.com/kornia/kornia.git)
+ kornia/geometry/transform/pyramid.py:203: error: Argument 1 to "sqrt" has incompatible type "complex"; expected "Union[SupportsFloat, SupportsIndex]"  [arg-type]

paasta (https://github.com/yelp/paasta.git)
+ paasta_tools/utils.py:3553: error: Incompatible return value type (got "float", expected "int")

rich (https://github.com/willmcgugan/rich.git)
+ rich/filesize.py:50: error: Incompatible return value type (got "Tuple[float, str]", expected "Tuple[int, str]")

sympy (https://github.com/sympy/sympy.git)
+ sympy/core/evalf.py:300: error: Incompatible types in assignment (expression has type "float", variable has type "int")
+ sympy/core/evalf.py:623: error: Incompatible types in assignment (expression has type "float", variable has type "int")
+ sympy/core/evalf.py:1196: error: Incompatible types in assignment (expression has type "float", variable has type "int")
+ sympy/core/evalf.py:1354: error: Incompatible types in assignment (expression has type "float", variable has type "Symbol")

@AlexWaygood

AlexWaygood commented Nov 12, 2021 •

Copy link
Copy Markdown
Member Author

Diff from mypy_primer, showing the effect of this PR on open source code

Hmm, it's annoying that the type system doesn't have a way of specifying a positive integer. The new rich error, for example, doesn't really need to be there. Will can be confident that base and i will both be >0 in line 47, and so can be confident that the type of base ** i will be int. But there's no way of telling mypy that, since mypy can't distinguish between positive and negative integers.

@AlexWaygood
AlexWaygood marked this pull request as draft November 12, 2021 19:33
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Comment thread stdlib/builtins.pyi Outdated
Comment thread stdlib/builtins.pyi Outdated
def __sub__(self, __x: complex) -> complex: ...
def __mul__(self, __x: complex) -> complex: ...
def __pow__(self, __x: complex, mod: None = ...) -> complex: ...
def __pow__(self, __x: complex | int | float, mod: None = ...) -> complex: ...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

complex | float is enough. Type checkers imagine that int is a subclass of float, even though it actually isn't.

A protocol involving SupportsIndex might be more accurate, if these behave similarly to math functions (#6211 and #6216).

@github-actions

This comment has been minimized.

@hauntsaninja hauntsaninja left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment thread stdlib/builtins.pyi Outdated
Comment thread stdlib/builtins.pyi Outdated
@github-actions

This comment has been minimized.

@AlexWaygood
AlexWaygood marked this pull request as ready for review November 12, 2021 20:14
Comment thread stdlib/builtins.pyi Outdated
def pow(base: float, exp: int, mod: None = ...) -> float: ...
@overload
def pow(base: float, exp: float, mod: None = ...) -> Any: ... # return type could be float or complex
def pow(base: float, exp: float, mod: None = ...) -> Any: ... # return type could be float or complex depending on x

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

depending on exp

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also depends on base. If the base is positive, then any power will also be positive. Complex numbers need a negative base and a negative power.

Maybe the whole "depending on" part should be deleted? It obviously depends on the arguments in some way, which is really all that needs to be said.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's worth spelling out the conditions... pow is like catnip for typeshed contributors, because everyone always starts off thinking only about positive integers :-)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah, sorry about that @hauntsaninja

@github-actions

This comment has been minimized.

1 similar comment
@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

@hauntsaninja
hauntsaninja merged commit 3324e22 into python:master Nov 12, 2021
@hauntsaninja

Copy link
Copy Markdown
Collaborator

Hooray!

Comment thread stdlib/builtins.pyi
def __rdivmod__(self, __x: int) -> tuple[int, int]: ...
@overload
def __pow__(self, __x: Literal[2], __modulo: int | None = ...) -> int: ...
def __pow__(self, __x: int, __modulo: Literal[0]) -> NoReturn: ...

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't result of x ** 0 == 1?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pow(1, 1, 0):

In [4]: pow(1, 1, 0)

Traceback (most recent call last):
  File "/main_instance_shell/jelle/venv/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 3343, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-4-23a0b67588cd>", line 1, in <module>
    pow(1, 1, 0)
ValueError: pow() 3rd argument cannot be 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants