Repository navigation
Crash when overriding partially typed attribute with partially typed property #11686
Description
Crash Report
I've been seeing mypy crashes with the released 0.910 and the current state of the dev branch. It appears to occur when a child class overrides a partially type instance attribute in its parent with a property that's also partially typed, but it also seems to matter that there's a second property in the parent that has at least a setter method.
I've cut it down as far as I could to the reproducer below the traceback.
Traceback
partial_list.py:15: error: INTERNAL ERROR -- Please try using mypy master on Github:
https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 0.920+dev.01e6aba30c787c664ac88d849b45f7d303316951
Traceback (most recent call last):
File "/Users/jake/.miniconda3/envs/tmp/bin/mypy", line 33, in <module>
sys.exit(load_entry_point('mypy', 'console_scripts', 'mypy')())
File "/Users/jake/code/mypy/mypy/__main__.py", line 12, in console_entry
main(None, sys.stdout, sys.stderr)
File "/Users/jake/code/mypy/mypy/main.py", line 96, in main
res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
File "/Users/jake/code/mypy/mypy/main.py", line 173, in run_build
res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
File "/Users/jake/code/mypy/mypy/build.py", line 180, in build
result = _build(
File "/Users/jake/code/mypy/mypy/build.py", line 256, in _build
graph = dispatch(sources, manager, stdout)
File "/Users/jake/code/mypy/mypy/build.py", line 2715, in dispatch
process_graph(graph, manager)
File "/Users/jake/code/mypy/mypy/build.py", line 3046, in process_graph
process_stale_scc(graph, scc, manager)
File "/Users/jake/code/mypy/mypy/build.py", line 3144, in process_stale_scc
graph[id].type_check_first_pass()
File "/Users/jake/code/mypy/mypy/build.py", line 2180, in type_check_first_pass
self.type_checker().check_first_pass()
File "/Users/jake/code/mypy/mypy/checker.py", line 319, in check_first_pass
self.accept(d)
File "/Users/jake/code/mypy/mypy/checker.py", line 425, in accept
stmt.accept(self)
File "/Users/jake/code/mypy/mypy/nodes.py", line 1000, in accept
return visitor.visit_class_def(self)
File "/Users/jake/code/mypy/mypy/checker.py", line 1790, in visit_class_def
self.accept(defn.defs)
File "/Users/jake/code/mypy/mypy/checker.py", line 425, in accept
stmt.accept(self)
File "/Users/jake/code/mypy/mypy/nodes.py", line 1069, in accept
return visitor.visit_block(self)
File "/Users/jake/code/mypy/mypy/checker.py", line 2052, in visit_block
self.accept(s)
File "/Users/jake/code/mypy/mypy/checker.py", line 425, in accept
stmt.accept(self)
File "/Users/jake/code/mypy/mypy/nodes.py", line 561, in accept
return visitor.visit_overloaded_func_def(self)
File "/Users/jake/code/mypy/mypy/checker.py", line 458, in visit_overloaded_func_def
self._visit_overloaded_func_def(defn)
File "/Users/jake/code/mypy/mypy/checker.py", line 482, in _visit_overloaded_func_def
self.check_method_override(defn)
File "/Users/jake/code/mypy/mypy/checker.py", line 1474, in check_method_override
if self.check_method_or_accessor_override_for_base(defn, base):
File "/Users/jake/code/mypy/mypy/checker.py", line 1502, in check_method_or_accessor_override_for_base
if self.check_method_override_for_base_with_name(defn, name, base):
File "/Users/jake/code/mypy/mypy/checker.py", line 1596, in check_method_override_for_base_with_name
elif is_equivalent(original_type, typ):
File "/Users/jake/code/mypy/mypy/subtypes.py", line 164, in is_equivalent
is_subtype(a, b, ignore_type_params=ignore_type_params,
File "/Users/jake/code/mypy/mypy/subtypes.py", line 93, in is_subtype
return _is_subtype(left, right,
File "/Users/jake/code/mypy/mypy/subtypes.py", line 147, in _is_subtype
return left.accept(SubtypeVisitor(orig_right,
File "/Users/jake/code/mypy/mypy/types.py", line 1967, in accept
return visitor.visit_partial_type(self)
File "/Users/jake/code/mypy/mypy/subtypes.py", line 515, in visit_partial_type
raise RuntimeError(f'Partial type "{left}" cannot be checked with "issubtype()"')
RuntimeError: Partial type "<partial list[?]>" cannot be checked with "issubtype()"
partial_list.py:15: : note: use --pdb to drop into pdb
To Reproduce
The traceback above was generated by the file partial_list.py:
class Parent:
# No error if there's no type hint in the constructor (type unimportant)
def __init__(self, args: int):
# The next line succeeds if it's a tuple, but fails on list.
self.var_a = []
# The type of this variable doesn't seem to matter at all, but it needs
# to exist and be trying to set a property.
self.var_b = None
# This needs to be a property, but the getter doesn't affect anything.
var_b = property(fset=lambda self, value: None)
class Child(Parent):
@property # Error reported on this line.
def var_a(self):
return self._var_a
@var_a.setter
def var_a(self, value):
self._var_a = []This was run with mypy --show-traceback partial_list.py in an empty venv, after deleting the .mypy-cache directory, and I don't think there's any other configuration being pulled from anywhere.
This was as small a reproducer as I could find. It seems to matter that there are two properties (although one of them only needs a setter), and the child class seems to need to be overriding a partially typed instance variable with a getter property that's also partially typed.
Your Environment
- Mypy version used: master: 0.920.dev @ 01e6aba
- Mypy command-line flags:
--show-traceback - Mypy configuration options from
mypy.ini(and other config files): none - Python version used: 3.9 and 3.10
- Operating system and version: macOS 11.6
Activity
sobolevn commentedon Dec 8, 2021
This small change fixes the crash. But, I am not sure it is correct:

Maybe you will be interested in creating a PR? You can add your case somewhere here: https://github.com/python/mypy/blob/master/test-data/unit/check-classes.test
jakelishman commentedon Dec 9, 2021
Thanks for the response! This change seems to solve this crash, but I'm not 100% it's not treating a symptom and not the cause - the inferred type of
var_aseems to depend on the presence of the otherpropertyin the class, and a type hint in the parent's constructor, where it seems like it shouldn't.If I remove all the
var_bproperty stuff, then the crash goes away andmypyreports the errors I expected to see, but to me, the type ofvar_bshouldn't have any impact on the type ofvar_a.I'd be happy to make a PR, but in this case I don't think I understand the underlying cause myself yet - if your solution is correct, I don't fully understand why - so I'd rather wait on that. I can try and have a look myself, to try and satisfy myself that I understand the solution completely, but it may take me a while.
AlexWaygood commentedon Mar 26, 2022
Similar traceback to #11981 and #12109
jakelishman commentedon Jun 5, 2022
This transpires to be more general than just
@propertydecorators - it's caused when any child method attempts to override a value whose type has only been partially inferred. The reproducer here can be done in several different ways, but this is probably the purest, most minimal example, touching the least number of different components:The
Base.__init__block will be deferred because of the multiple definitions offorce_deferral, which leavesBase.partial_typeinferred as<partial list[?]>after the first pass (thearg: intjust forces us to use complete type checking within the__init__). Analysis ofDerived.partial_typethen needs to check if the typesdef () -> intand<partial list[?]>are compatible, which fails with the "cannot check a partial type with issubtype" error in the main post.I think the correct solution to this is what's given above in #11686 (comment), since I now understand why the seemingly unrelated
force_deferralwas affecting whether the crash appeared. I've made a PR #12943 to that effect.Fix crash overriding partial-type attribute with method (#12943)
Fix crash overriding partial-type attribute with method (python#12943)