Skip to content

Cannot assign an Optional[float] to a float #10340

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

Closed
fpdotmonkey opened this issue Apr 19, 2021 · 6 comments
Closed

Cannot assign an Optional[float] to a float #10340

fpdotmonkey opened this issue Apr 19, 2021 · 6 comments

Comments

@fpdotmonkey
Copy link

fpdotmonkey commented Apr 19, 2021

I have the class below which can optionally take a tuple, which itself optionally has float members, so (1.0, 2.0), None, (1.0, None), etc are all valid inputs.

I do checking in the class to see if None has been input, and ignore the input in those cases, but mypy is saying Optional[float] and float are incompatible for these assignments.

How can I specify to mypy that I've done my due diligence in type checking the input?

# foo.py
from typing import Optional, Tuple


class Foo:
    def __init__(
        self, bounds: Optional[Tuple[Optional[float], Optional[float]]] = None
    ):
        self._lower_bound: float = float("-inf")
        self._upper_bound: float = float("inf")
        if bounds:
            if bounds[0]:
                self._lower_bound = bounds[0]
            if bounds[1]:
                self._upper_bound = bounds[1]


Foo((1, 2))
$ mypy foo.py
foo.py:12: error: Incompatible types in assignment (expression has type "Optional[float]", variable has type "float")
foo.py:14: error: Incompatible types in assignment (expression has type "Optional[float]", variable has type "float")
Found 2 errors in 1 file (checked 1 source file)

I'm running mypy 0.812 with Python 3.8.5

@JelleZijlstra
Copy link
Member

The problem here is that mypy doesn't do type narrowing on bounds[0]. Here's a shorter example to demonstrate that:

from typing import Optional
tpl: tuple[Optional[int]]
reveal_type(tpl[0])  # int | None
if tpl[0]:
    reveal_type(tpl[0])  # int | None

There are some similar existing issues like #7339, but Ivan's comments on that issue suggest that tpl[0] should work for type narrowing.

@hauntsaninja
Copy link
Collaborator

If you rephrase your check as bounds[0] is not None, it works

@fpdotmonkey
Copy link
Author

If you rephrase your check as bounds[0] is not None, it works

Ok this works. It does seem unpythonic to disallow truthiness, but whatever works.

@hauntsaninja
Copy link
Collaborator

Yeah, definitely a bug / am sort of surprised by this

@Akuli
Copy link
Contributor

Akuli commented Oct 25, 2021

No longer happens on master:

(env310) akuli@akuli-desktop:~/mypy$ python3 -m mypy a.py
Success: no issues found in 1 source file

(env310) akuli@akuli-desktop:~/mypy$ cat a.py
from typing import Optional, Tuple
class Foo:
    def __init__(
        self, bounds: Optional[Tuple[Optional[float], Optional[float]]] = None
    ):
        self._lower_bound: float = float("-inf")
        self._upper_bound: float = float("inf")
        if bounds:
            if bounds[0]:
                self._lower_bound = bounds[0]
            if bounds[1]:
                self._upper_bound = bounds[1]
Foo((1, 2))

@hauntsaninja
Copy link
Collaborator

hauntsaninja commented Oct 25, 2021

Thanks, I think this was fixed by #11202

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

No branches or pull requests

4 participants