-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
mypy crashes with overloads of functools.singledispatch #8356
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
Comments
Same here: Trying to combine Using Python 3.7 with mypy 0.750 Python code: from datetime import datetime, date
import typing
from typing import Union
from functools import singledispatch
from typing_extensions import Literal
DateInType = Union[date, str]
@typing.overload # <---- THIS IS ***line 50*** of td.py raising mypy internal error
def date2str(t: DateInType, out_format: Literal['str']) -> str: ...
@typing.overload
def date2str(t: DateInType, out_format: Literal['date']) -> date: ...
@singledispatch
def date2str(t, out_format):
''' Converts:
- datetime.date to string (YYYY-MM-DD)
- string (YYYY-MM-DD, YYYY/MM/DD, DD-MM-YYYY, ...) to datetime.date
Second argument = 'out_format' can be 'str' or 'date'.
If specified, returns output in string (YYYY-MM-DD) ['str'] or datetime.date format ['date'].
'''
@date2str.register(date)
def _date2str_date(t, out_format='str'):
''' Input format = datetime.date.
Output format, if string = YYYY-MM-DD'''
if out_format == 'str':
return t.strftime('%Y-%m-%d')
elif isinstance(t, datetime):
return t.date()
else:
return t
@date2str.register(str)
def _date2str_str(t, out_format='date'):
''' Input format = string (YYYY-MM-DD, DD-MM-YYYY, ...)'''
dformats = ('%Y-%m-%d', '%Y/%m/%d', '%d-%m-%Y', '%d/%m/%Y', '%Y%m%d')
for i, dformat in enumerate(dformats, start=1):
try:
d = datetime.strptime(t, dformat).date()
break
except ValueError:
if i == len(dformats):
raise
if out_format == 'date':
return d
else:
return date2str(d, out_format=out_format)
dt = datetime.now()
res = date2str(dt, out_format='date')
print(res, type(res))
assert type(res) == date
res2 = date2str(dt.date(), out_format='str')
print(res2, type(res2))
assert type(res2) == str
res3 = date2str('20061005', out_format='date')
print(res3, type(res3))
assert type(res3) == date mypy traceback:
Am I doing something wrong? |
Hello, I am an open source noob and would like to try and tackle this issue. Is that possible? |
Yes, of course! Welcome. If you get stuck, feel free to ask questions here. |
I couldn't replicate the bug on my machine. Using Python 3.8.2 and using my forked version of mypy (v0.770 I believe), copying @jeanmonet's code yielded the following output:
I also tried replicating the error using your (@hauntsaninja ) code but I admit I didn't really understand what was going on there (what does the lambda mean?) cheers |
My repro continues to repro for me (against mypy master). Note it contains the exact command I ran. The output you copied looks like it would be the result of running the program (with the Python interpreter), which is expected to work — this is a bug in mypy, not in Python itself. Remember mypy is a static checker, it doesn't actually run your code. If you still can't get it to repro, try sharing the exact commands you're running here. I assume by lambda you mean the def function named If you need a reference for what overload does (and to understand the code better, since the mypy crash occurs while running some overload checking related code) , I recommend https://mypy.readthedocs.io/en/stable/more_types.html#function-overloading. In general, I've found the mypy docs really helpful. |
see #2904 |
I encountered this issue as well when I added from functools import singledispatch
from typing import Callable, overload
@overload
def overloaded_function(func: Callable):
...
@overload
def overloaded_function(format_string: str):
...
@singledispatch
def overloaded_function(func: Callable):
pass
@overloaded_function.register
def _overloaded_function_for_strings(format_string: str):
pass |
Is this issue still available? I would like to take this up. |
Still happens with python 3.8.10 + mypy-0.920+dev.2a332e79e9. Minimal example: from functools import singledispatch
from typing import Union, overload
@overload
def f(x: None) -> None:
...
@overload
def f(x: object) -> None:
...
@singledispatch
def f(x: Union[None, object]) -> None:
pass Run
|
@pranavrajpal thanks for all your great work on singledispatch so far! Any interest in looking into this one? |
A workaround is to separate overload declaration from singledispatch implementation: @overload
def decl(x: None) -> None:
...
@overload
def decl(x: int) -> int:
...
def decl(x: Union[None, int]) -> Union[None, int]:
return _impl(x)
@singledispatch
def _impl(x: Union[None,int]) -> Union[None,int]:
raise TypeError(type(x))
@_impl.register
def _(x: None) -> None:
return x
@_impl.register
def _(x: int) -> int:
return x+1 |
Actually, in an attempt to simplify the workaround I think I found a better way overall? It's compact, minimally redundant, and passes mypy --strict: @singledispatch
def _foo(x: Union[None,int]) -> Union[None,int]:
raise TypeError(type(x))
@overload
@_foo.register
def foo(x: None) -> None:
return x
@overload
@_foo.register
def foo(x: int) -> int:
return x+1
def foo(x: Union[None,int]) -> Union[None,int]:
return _foo(x) |
Sure, I can look into this. This seems to be a problem with mypy not handling callable objects as overload implementations, because it's expecting a regular function. For example, this: from typing import Callable, Any, overload
class A:
def __call__(self, *args, **kwargs):
pass
def dec(f: Callable[..., Any]) -> A:
return A()
@overload
def f(arg: int) -> None:
pass
@overload
def f(arg: str) -> None:
pass
@dec
def f(arg):
pass results in the same crash. |
It crashes even when the overload implementation is a regular function: from typing import *
C = Callable[..., Any]
T = TypeVar("T", bound=C)
def dec(f: C) -> T:
return cast(T, f)
@overload
def f(x: int) -> None: ...
@overload
def f(x: str) -> None: ...
@dec
def f(x: Union[int, str]) -> None:
pass In this case, at the site of the crash the type of inner_type is mypy.types.UninhabitedType. Note that changing the signature of dec to any of (C)->C, (T)->T, or (T)->C (and removing the cast in all cases) does not crash. |
Maybe the title of this issue should be changed to "mypy crashes with overloads of some decorated functions". |
Fixes the crash in python#8356, as identified by @pranavrajpal Note that we still don't support the singledispatch in that issue, since we get 'overloaded function has no attribute "register"', but that's much easier to work around than a crash.
Fixes the crash in python#8356, as identified by @pranavrajpal Note that we still don't support the singledispatch in that issue, since we get 'overloaded function has no attribute "register"', but that's much easier to work around than a crash.
Fixes #8356, as identified by @pranavrajpal Fixes #9112 Fixes #9967 Note that we still don't fully support the singledispatch pattern in #8356, since we get 'overloaded function has no attribute "register"', but that's much easier to work around than a crash. Co-authored-by: hauntsaninja <>
Hmm... the patch fixes the crash, but the note says "still doesn't fully support" ... should this be closed, really? Or perhaps there should be another issue opened to track the problem? |
Sure, feel free to open another issue, although note the error that you get can be safely type ignored without negative consequence. |
Thanks! ... well I'll try on my code and see! :) |
Fixes #8356, as identified by @pranavrajpal Fixes #9112 Fixes #9967 Note that we still don't fully support the singledispatch pattern in #8356, since we get 'overloaded function has no attribute "register"', but that's much easier to work around than a crash. Co-authored-by: hauntsaninja <>
Fixes python#8356, as identified by @pranavrajpal Fixes python#9112 Fixes python#9967 Note that we still don't fully support the singledispatch pattern in python#8356, since we get 'overloaded function has no attribute "register"', but that's much easier to work around than a crash. Co-authored-by: hauntsaninja <>
I was trying out the advice I gave in #8354, and encountered a mypy crash:
The text was updated successfully, but these errors were encountered: