Description
Bug Report
There are some scenarios where inheriting from MutableSequence
and built-in list
(in this exact order) is important. This is the case for atoml
and tomlkit
.
However this results in a typecheck error with mypy
: Cannot determine consistent method resolution order (MRO)
Please notice no runtime error is found.
To Reproduce
Consider the following simplified example (extracted from atoml/tomlkit
):
example.py
from typing import Optional
from collections.abc import MutableSequence
class Item:
def __init__(self, comment: Optional[str] = None):
self._comment = comment
class Array(Item, MutableSequence, list):
def __init__(self, values: list, comment: Optional[str] = None):
Item.__init__(self, comment)
list.__init__(self, values)
if __name__ == '__main__':
a = Array([0, 1, 2])
print([p.__name__ for p in a.__class__.__mro__])
Expected Behavior
I would expect the MRO detected by mypy is exactly the same one given in runtime, i.e.:
['Array', 'Item', 'MutableSequence', 'Sequence', 'Reversible', 'Collection', 'Sized', 'Iterable', 'Container', 'list', 'object']
Actual Behavior
During runtime the MRO is well defined and works as expected:
$ python3 example.py
['Array', 'Item', 'MutableSequence', 'Sequence', 'Reversible', 'Collection', 'Sized', 'Iterable', 'Container', 'list', 'object']
But mypy
fails to detect it and get completely lost when checking the Array
class.
$ mypy example.py
example.py: note: In class "Array":
example.py:10: error: Cannot determine consistent method resolution order (MRO) for "Array" [misc]
class Array(Item, MutableSequence, list):
^
example.py: note: In member "__init__" of class "Array":
example.py:12: error: Argument 1 to "__init__" of "Item" has incompatible type "Array"; expected "Item"
[arg-type]
Item.__init__(self, comment)
^
example.py:13: error: No overload variant of "__init__" of "list" matches argument types "Array",
"List[Any]" [call-overload]
list.__init__(self, values)
^
example.py:13: note: Possible overload variant:
example.py:13: note: def [_T] __init__(self, self: List[_T], iterable: Iterable[_T]) -> None
example.py:13: note: <1 more non-matching overload not shown>
Found 3 errors in 1 file (checked 1 source file)
Your Environment
- Mypy version used: 0.910
- Mypy command-line flags:
None
- Mypy configuration options from
mypy.ini
(and other config files):
mypy.ini
[mypy]
pretty = True
show_error_codes = True
show_error_context = True
show_traceback = True
ignore_missing_imports = True
warn_redundant_casts = True
warn_unused_ignores = True
- Python version used: 3.8.0
- Operating system and version: Ubuntu 18.04.5 LTS
Please notice that while this particular choice of inheritance is debatable, it is fundamental for the way atoml
/tomlkit
work. We need MutableSequence
as a mixin to implement the custom logic, but we also want the objects to be considered lists, so the users can use the API transparently as if they were dealing with built-in objects (this is an important aspect of the design).