-
-
Notifications
You must be signed in to change notification settings - Fork 119
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
mypy plugin allows false positive error when exhaustively pattern matching on Result #1361
Comments
Also, related to this issue and #1090, is this still valid? Lines 164 to 165 in cd08c2a
Curious if @ariebovenberg has any thoughts as someone who has been using pattern matching and |
I am 80% sure that this is a mypy bug 🤔 |
I did a little more digging and added an #!/usr/bin/env python3
from enum import Enum, auto
import math
from typing import NoReturn
from returns.result import Failure, Result, Success
# TODO: Remove this once mypy > 0.942 is released and simply import typing_extensions.assert_never
# https://github.com/python/mypy/issues/12613
def assert_never(__arg: NoReturn) -> NoReturn:
"""Assert to the type checker that a line of code is unreachable.
Example::
def int_or_str(arg: int | str) -> None:
match arg:
case int():
print("It's an int")
case str():
print("It's a str")
case _:
assert_never(arg)
If a type checker finds that a call to assert_never() is
reachable, it will emit an error.
At runtime, this throws an exception when called.
"""
raise AssertionError("Expected code to be unreachable")
class MathError(Enum):
DivisionByZero = auto()
NonPositiveLogarithm = auto()
MathResult = Result[float, MathError]
def div(x: float, y: float) -> MathResult:
if y == 0.0:
return Failure(MathError.DivisionByZero)
return Success(x / y)
def ln(x: float) -> MathResult:
if x <= 0.0:
return Failure(MathError.NonPositiveLogarithm)
return Success(math.log(x))
def op_(x: float, y: float) -> MathResult:
z = div(x, y)
match z:
case Success(ratio):
return ln(ratio)
case Failure(_):
return z
case _ as u:
assert_never(u) This reveals the type that is "slipping through" the
When using An example I was using: johnthagen/sealed-typing-pep#4 (comment) |
I guess we can refactor |
One problem with the union approach, I found, was that you can't have nice classmethods on the union. Something like Regarding refactoring to |
At least this works in mypy (latest): from typing import Union, TypeAlias
class A:
@classmethod
def from_some(cls) -> A:
return A()
class B:
@classmethod
def from_some(cls) -> B:
return B()
Result: Union[A, B]
reveal_type(Result.from_some()) # N: Revealed type is "Union[ex.A, ex.B]" The runtime part is always easier 😉 |
Oh, I see one more problem: |
@ariebovenberg Funny you should bring up There is some initial discussion on the typing-sig about this: https://mail.python.org/archives/list/typing-sig@python.org/thread/7TB36OWSWRUIHUG36F4FHE3PVKVM3RSC/ Having more people voice support for an ADT in which methods and state can be added to the base type could be helpful. |
You totally have my support on this! Where should I sign? 😆 |
I am already there, just not very active 😉 |
This does not look possible with the current way of doing things: from typing import Union
class S:
def method(self) -> int:
...
class F:
def method(self) -> int:
...
Result1 = Union[S, F]
reveal_type(Result1)
# note: Revealed type is "builtins.object"
reveal_type(Result1.method)
# error: "object" has no attribute "method"
# note: Revealed type is "Any"
Result2: Union[S, F]
# error: Variable "ex.Result2" is not valid as a type
# note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
def some() -> Result2:
... So, we need |
Okay, good to know. We are nearing the completion of the PEP and will ping you when there is a draft ready for you to review. |
This comment was marked as outdated.
This comment was marked as outdated.
@sobolevn We have revived and resubmitted the |
Bug report
What's wrong
Consider the following code:
mypy
configuration inpyproject.toml
Running:
Related to #1090
How is that should be
As far as I can tell (new to
returns
), I'm matching exhaustively here, so I would not expect amypy
error.mypy
seems to understand exhaustive matching in general.mypy
does not throw a type checking error in the following snippet.System information
python
version: 3.10.2returns
version: 0.19.0mypy
version: 0.942The text was updated successfully, but these errors were encountered: