Skip to content

Commit

Permalink
Fix "attribute 'arguments' of 'FuncDef' undefined" incremental crash (p…
Browse files Browse the repository at this point in the history
…ython#12324)

When deserializing from cache, FuncDef.arguments is not set, so
check before use.
  • Loading branch information
fperrin authored and Gobot1234 committed Aug 12, 2022
1 parent 38d78e8 commit 83b3b34
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 12 deletions.
4 changes: 3 additions & 1 deletion mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -1978,7 +1978,9 @@ def [T <: int] f(self, x: int, y: T) -> None
s += ' = ...'

# If we got a "special arg" (i.e: self, cls, etc...), prepend it to the arg list
if isinstance(tp.definition, FuncDef) and tp.definition.name is not None:
if (isinstance(tp.definition, FuncDef) and
tp.definition.name is not None and
hasattr(tp.definition, 'arguments')):
definition_args = [arg.variable.name for arg in tp.definition.arguments]
if definition_args and tp.arg_names != definition_args \
and len(definition_args) > 0 and definition_args[0]:
Expand Down
2 changes: 1 addition & 1 deletion mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ def set_line(self,
class FuncItem(FuncBase):
"""Base class for nodes usable as overloaded function items."""

__slots__ = ('arguments', # Note that can be None if deserialized (type is a lie!)
__slots__ = ('arguments', # Note that can be unset if deserialized (type is a lie!)
'arg_names', # Names of arguments
'arg_kinds', # Kinds of arguments
'min_args', # Minimum number of arguments
Expand Down
19 changes: 9 additions & 10 deletions mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1524,16 +1524,15 @@ def __init__(self,
# after serialization, but it is useful in error messages.
# TODO: decide how to add more info here (file, line, column)
# without changing interface hash.
self.def_extras = {
'first_arg': (
definition.arguments[0].variable.name
if (getattr(definition, 'arguments', None)
and definition.arg_names
and definition.info
and not definition.is_static)
else None
),
}
first_arg: Optional[str] = None
if (definition.arg_names and
definition.info and
not definition.is_static):
if getattr(definition, 'arguments', None):
first_arg = definition.arguments[0].variable.name
else:
first_arg = definition.arg_names[0]
self.def_extras = {'first_arg': first_arg}
else:
self.def_extras = {}
self.type_guard = type_guard
Expand Down
32 changes: 32 additions & 0 deletions test-data/unit/check-modules.test
Original file line number Diff line number Diff line change
Expand Up @@ -3212,3 +3212,35 @@ from dir1 import *
from .test2 import *
[file dir1/test2.py]
from test1 import aaaa # E: Module "test1" has no attribute "aaaa"

[case testIncompatibleOverrideFromCachedModuleIncremental]
import b
[file a.py]
class Foo:
def frobnicate(self, *args, **kwargs): pass
[file b.py]
from a import Foo
class Bar(Foo):
def frobnicate(self) -> None: pass
[file b.py.2]
from a import Foo
class Bar(Foo):
def frobnicate(self, *args) -> None: pass
[file b.py.3]
from a import Foo
class Bar(Foo):
def frobnicate(self, *args) -> None: pass # type: ignore[override] # I know
[builtins fixtures/tuple.pyi]
[builtins fixtures/dict.pyi]
[out1]
tmp/b.py:3: error: Signature of "frobnicate" incompatible with supertype "Foo"
tmp/b.py:3: note: Superclass:
tmp/b.py:3: note: def frobnicate(self, *args: Any, **kwargs: Any) -> Any
tmp/b.py:3: note: Subclass:
tmp/b.py:3: note: def frobnicate(self) -> None
[out2]
tmp/b.py:3: error: Signature of "frobnicate" incompatible with supertype "Foo"
tmp/b.py:3: note: Superclass:
tmp/b.py:3: note: def frobnicate(self, *args: Any, **kwargs: Any) -> Any
tmp/b.py:3: note: Subclass:
tmp/b.py:3: note: def frobnicate(self, *args: Any) -> None

0 comments on commit 83b3b34

Please sign in to comment.