Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitad76e16

Browse files
authored
Move self argument checks to a later phase - after decorator application, if any (#19490)
Fixes#19392.Fixes#18989.Fixes#18720.Fixes#13434 (correct support for `staticmethod` wrappers, but not forequivalent `classmethod`s reported in#18968).Deferring this check in presence of decorators allows decorators thatperform non-trivial transformations (such as making methods fromnon-methods and vice versa).
1 parentbd94bcb commitad76e16

File tree

5 files changed

+300
-59
lines changed

5 files changed

+300
-59
lines changed

‎mypy/checker.py‎

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,49 +1373,19 @@ def check_func_def(
13731373
)
13741374

13751375
# Store argument types.
1376+
found_self=False
1377+
ifisinstance(defn,FuncDef)andnotdefn.is_decorated:
1378+
found_self=self.require_correct_self_argument(typ,defn)
13761379
foriinrange(len(typ.arg_types)):
13771380
arg_type=typ.arg_types[i]
1378-
if (
1379-
isinstance(defn,FuncDef)
1380-
andref_typeisnotNone
1381-
andi==0
1382-
anddefn.has_self_or_cls_argument
1383-
andtyp.arg_kinds[0]notin [nodes.ARG_STAR,nodes.ARG_STAR2]
1384-
):
1385-
ifdefn.is_classordefn.name=="__new__":
1386-
ref_type=mypy.types.TypeType.make_normalized(ref_type)
1387-
ifnotis_same_type(arg_type,ref_type):
1388-
# This level of erasure matches the one in checkmember.check_self_arg(),
1389-
# better keep these two checks consistent.
1390-
erased=get_proper_type(erase_typevars(erase_to_bound(arg_type)))
1391-
ifnotis_subtype(ref_type,erased,ignore_type_params=True):
1392-
if (
1393-
isinstance(erased,Instance)
1394-
anderased.type.is_protocol
1395-
orisinstance(erased,TypeType)
1396-
andisinstance(erased.item,Instance)
1397-
anderased.item.type.is_protocol
1398-
):
1399-
# We allow the explicit self-type to be not a supertype of
1400-
# the current class if it is a protocol. For such cases
1401-
# the consistency check will be performed at call sites.
1402-
msg=None
1403-
eliftyp.arg_names[i]in {"self","cls"}:
1404-
msg=message_registry.ERASED_SELF_TYPE_NOT_SUPERTYPE.format(
1405-
erased.str_with_options(self.options),
1406-
ref_type.str_with_options(self.options),
1407-
)
1408-
else:
1409-
msg=message_registry.MISSING_OR_INVALID_SELF_TYPE
1410-
ifmsg:
1411-
self.fail(msg,defn)
1412-
elifisinstance(arg_type,TypeVarType):
1381+
ifisinstance(arg_type,TypeVarType):
14131382
# Refuse covariant parameter type variables
14141383
# TODO: check recursively for inner type variables
14151384
if (
14161385
arg_type.variance==COVARIANT
14171386
anddefn.namenotin ("__init__","__new__","__post_init__")
14181387
andnotis_private(defn.name)# private methods are not inherited
1388+
and (i!=0ornotfound_self)
14191389
):
14201390
ctx:Context=arg_type
14211391
ifctx.line<0:
@@ -1565,6 +1535,69 @@ def check_func_def(
15651535

15661536
self.binder=old_binder
15671537

1538+
defrequire_correct_self_argument(self,func:Type,defn:FuncDef)->bool:
1539+
func=get_proper_type(func)
1540+
ifnotisinstance(func,CallableType):
1541+
returnFalse
1542+
1543+
# Do not report errors for untyped methods in classes nested in untyped funcs.
1544+
ifnot (
1545+
self.options.check_untyped_defs
1546+
orlen(self.dynamic_funcs)<2
1547+
ornotself.dynamic_funcs[-2]
1548+
ornotdefn.is_dynamic()
1549+
):
1550+
returnbool(func.arg_types)
1551+
1552+
withself.scope.push_function(defn):
1553+
# We temporary push the definition to get the self type as
1554+
# visible from *inside* of this function/method.
1555+
ref_type:Type|None=self.scope.active_self_type()
1556+
ifref_typeisNone:
1557+
returnFalse
1558+
1559+
ifnotdefn.has_self_or_cls_argumentor (
1560+
func.arg_kindsandfunc.arg_kinds[0]in [nodes.ARG_STAR,nodes.ARG_STAR2]
1561+
):
1562+
returnFalse
1563+
1564+
ifnotfunc.arg_types:
1565+
self.fail(
1566+
'Method must have at least one argument. Did you forget the "self" argument?',defn
1567+
)
1568+
returnFalse
1569+
1570+
arg_type=func.arg_types[0]
1571+
ifdefn.is_classordefn.name=="__new__":
1572+
ref_type=mypy.types.TypeType.make_normalized(ref_type)
1573+
ifis_same_type(arg_type,ref_type):
1574+
returnTrue
1575+
1576+
# This level of erasure matches the one in checkmember.check_self_arg(),
1577+
# better keep these two checks consistent.
1578+
erased=get_proper_type(erase_typevars(erase_to_bound(arg_type)))
1579+
ifnotis_subtype(ref_type,erased,ignore_type_params=True):
1580+
if (
1581+
isinstance(erased,Instance)
1582+
anderased.type.is_protocol
1583+
orisinstance(erased,TypeType)
1584+
andisinstance(erased.item,Instance)
1585+
anderased.item.type.is_protocol
1586+
):
1587+
# We allow the explicit self-type to be not a supertype of
1588+
# the current class if it is a protocol. For such cases
1589+
# the consistency check will be performed at call sites.
1590+
msg=None
1591+
eliffunc.arg_names[0]in {"self","cls"}:
1592+
msg=message_registry.ERASED_SELF_TYPE_NOT_SUPERTYPE.format(
1593+
erased.str_with_options(self.options),ref_type.str_with_options(self.options)
1594+
)
1595+
else:
1596+
msg=message_registry.MISSING_OR_INVALID_SELF_TYPE
1597+
ifmsg:
1598+
self.fail(msg,defn)
1599+
returnTrue
1600+
15681601
defis_var_redefined_in_outer_context(self,v:Var,after_line:int)->bool:
15691602
"""Can the variable be assigned to at module top level or outer function?
15701603
@@ -5306,6 +5339,7 @@ def visit_decorator_inner(
53065339
)
53075340
ifnon_trivial_decorator:
53085341
self.check_untyped_after_decorator(sig,e.func)
5342+
self.require_correct_self_argument(sig,e.func)
53095343
sig=set_callable_name(sig,e.func)
53105344
e.var.type=sig
53115345
e.var.is_ready=True

‎mypy/semanal.py‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,12 +1072,7 @@ def prepare_method_signature(self, func: FuncDef, info: TypeInfo, has_self_type:
10721072
iffunc.has_self_or_cls_argument:
10731073
iffunc.namein ["__init_subclass__","__class_getitem__"]:
10741074
func.is_class=True
1075-
ifnotfunc.arguments:
1076-
self.fail(
1077-
'Method must have at least one argument. Did you forget the "self" argument?',
1078-
func,
1079-
)
1080-
elifisinstance(functype,CallableType):
1075+
iffunc.argumentsandisinstance(functype,CallableType):
10811076
self_type=get_proper_type(functype.arg_types[0])
10821077
ifisinstance(self_type,AnyType):
10831078
ifhas_self_type:

‎test-data/unit/check-classes.test‎

Lines changed: 229 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3261,7 +3261,10 @@ b.bad = 'a' # E: Incompatible types in assignment (expression has type "str", v
32613261
from typing import Any
32623262

32633263
class Test:
3264-
def __setattr__() -> None: ... # E: Method must have at least one argument. Did you forget the "self" argument? # E: Invalid signature "Callable[[], None]" for "__setattr__"
3264+
def __setattr__() -> None: ... \
3265+
# E: Invalid signature "Callable[[], None]" for "__setattr__" \
3266+
# E: Method must have at least one argument. Did you forget the "self" argument?
3267+
32653268
t = Test()
32663269
t.crash = 'test' # E: Attribute function "__setattr__" with type "Callable[[], None]" does not accept self argument \
32673270
# E: "Test" has no attribute "crash"
@@ -7742,6 +7745,231 @@ class Foo:
77427745
def bad(): # E: Method must have at least one argument. Did you forget the "self" argument?
77437746
self.x = 0 # E: Name "self" is not defined
77447747

7748+
[case testMethodSelfArgumentChecks]
7749+
from typing import Callable, ParamSpec, TypeVar
7750+
7751+
T = TypeVar("T")
7752+
P = ParamSpec("P")
7753+
7754+
def to_number_1(fn: Callable[[], int]) -> int:
7755+
return 0
7756+
7757+
def to_number_2(fn: Callable[[int], int]) -> int:
7758+
return 0
7759+
7760+
def to_same_callable(fn: Callable[P, T]) -> Callable[P, T]:
7761+
return fn
7762+
7763+
class A:
7764+
def undecorated() -> None: ... # E: Method must have at least one argument. Did you forget the "self" argument?
7765+
7766+
def undecorated_not_self(x: int) -> None: ... # E: Self argument missing for a non-static method (or an invalid type for self)
7767+
7768+
def undecorated_not_self_2(self: int) -> None: ... # E: The erased type of self "builtins.int" is not a supertype of its class "__main__.A"
7769+
7770+
@to_number_1
7771+
def fn1() -> int:
7772+
return 0
7773+
7774+
@to_number_1 # E: Argument 1 to "to_number_1" has incompatible type "Callable[[int], int]"; expected "Callable[[], int]"
7775+
def fn2(_x: int) -> int:
7776+
return 0
7777+
7778+
@to_number_2 # E: Argument 1 to "to_number_2" has incompatible type "Callable[[], int]"; expected "Callable[[int], int]"
7779+
def fn3() -> int:
7780+
return 0
7781+
7782+
@to_number_2
7783+
def fn4(_x: int) -> int:
7784+
return 0
7785+
7786+
@to_number_2 # E: Argument 1 to "to_number_2" has incompatible type "Callable[[str], int]"; expected "Callable[[int], int]"
7787+
def fn5(_x: str) -> int:
7788+
return 0
7789+
7790+
@to_same_callable
7791+
def g1() -> None: ... # E: Method must have at least one argument. Did you forget the "self" argument?
7792+
7793+
@to_same_callable
7794+
def g2(x: int) -> None: ... # E: Self argument missing for a non-static method (or an invalid type for self)
7795+
7796+
@to_same_callable
7797+
def g3(self: int) -> None: ... # E: The erased type of self "builtins.int" is not a supertype of its class "__main__.A"
7798+
7799+
reveal_type(A().fn1) # N: Revealed type is "builtins.int"
7800+
reveal_type(A().fn2) # N: Revealed type is "builtins.int"
7801+
reveal_type(A().fn3) # N: Revealed type is "builtins.int"
7802+
reveal_type(A().fn4) # N: Revealed type is "builtins.int"
7803+
reveal_type(A().fn5) # N: Revealed type is "builtins.int"
7804+
7805+
reveal_type(A().g1) # E: Attribute function "g1" with type "Callable[[], None]" does not accept self argument \
7806+
# N: Revealed type is "def ()"
7807+
reveal_type(A().g2) # E: Invalid self argument "A" to attribute function "g2" with type "Callable[[int], None]" \
7808+
# N: Revealed type is "def ()"
7809+
reveal_type(A().g3) # E: Invalid self argument "A" to attribute function "g3" with type "Callable[[int], None]" \
7810+
# N: Revealed type is "def ()"
7811+
[builtins fixtures/tuple.pyi]
7812+
7813+
[case testMethodSelfArgumentChecksConcatenate]
7814+
from typing import Callable, ParamSpec, TypeVar
7815+
from typing_extensions import Concatenate
7816+
7817+
T = TypeVar("T")
7818+
P = ParamSpec("P")
7819+
R = TypeVar("R")
7820+
7821+
def to_same_callable(fn: Callable[Concatenate[T, P], R]) -> Callable[Concatenate[T, P], R]:
7822+
return fn
7823+
7824+
def remove_first(fn: Callable[Concatenate[T, P], R]) -> Callable[P, R]:
7825+
...
7826+
7827+
def add_correct_first(fn: Callable[P, R]) -> Callable[Concatenate["C", P], R]:
7828+
...
7829+
7830+
def add_wrong_first(fn: Callable[P, R]) -> Callable[Concatenate[int, P], R]:
7831+
...
7832+
7833+
class A:
7834+
@to_same_callable # E: Argument 1 to "to_same_callable" has incompatible type "Callable[[], int]"; expected "Callable[[T], int]"
7835+
def fn1() -> int:
7836+
return 0
7837+
7838+
@to_same_callable
7839+
def fn2(_x: int) -> int: # E: Self argument missing for a non-static method (or an invalid type for self)
7840+
return 0
7841+
7842+
@to_same_callable
7843+
def fn3(self, _x: int) -> int:
7844+
return 0
7845+
7846+
reveal_type(A().fn1) # N: Revealed type is "def () -> builtins.int"
7847+
reveal_type(A().fn2) # E: Invalid self argument "A" to attribute function "fn2" with type "Callable[[int], int]" \
7848+
# N: Revealed type is "def () -> builtins.int"
7849+
reveal_type(A().fn3) # N: Revealed type is "def (_x: builtins.int) -> builtins.int"
7850+
7851+
class B:
7852+
@remove_first # E: Argument 1 to "remove_first" has incompatible type "Callable[[], int]"; expected "Callable[[T], int]"
7853+
def fn1() -> int: # E: Method must have at least one argument. Did you forget the "self" argument?
7854+
return 0
7855+
7856+
@remove_first
7857+
def fn2(_x: int) -> int: # E: Method must have at least one argument. Did you forget the "self" argument?
7858+
return 0
7859+
7860+
@remove_first
7861+
def fn3(self, _x: int) -> int: # E: Self argument missing for a non-static method (or an invalid type for self)
7862+
return 0
7863+
7864+
@remove_first
7865+
def fn4(self, new_self: 'B') -> int:
7866+
return 0
7867+
7868+
reveal_type(B().fn1) # E: Attribute function "fn1" with type "Callable[[], int]" does not accept self argument \
7869+
# N: Revealed type is "def () -> builtins.int"
7870+
reveal_type(B().fn2) # E: Attribute function "fn2" with type "Callable[[], int]" does not accept self argument \
7871+
# N: Revealed type is "def () -> builtins.int"
7872+
reveal_type(B().fn3) # E: Invalid self argument "B" to attribute function "fn3" with type "Callable[[int], int]" \
7873+
# N: Revealed type is "def () -> builtins.int"
7874+
reveal_type(B().fn4) # N: Revealed type is "def () -> builtins.int"
7875+
7876+
class C:
7877+
@add_correct_first
7878+
def fn1() -> int:
7879+
return 0
7880+
7881+
@add_correct_first
7882+
def fn2(_x: int) -> int:
7883+
return 0
7884+
7885+
@add_correct_first
7886+
def fn3(self, _x: int) -> int:
7887+
return 0
7888+
7889+
reveal_type(C().fn1) # N: Revealed type is "def () -> builtins.int"
7890+
reveal_type(C().fn2) # N: Revealed type is "def (_x: builtins.int) -> builtins.int"
7891+
reveal_type(C().fn3) # N: Revealed type is "def (self: __main__.C, _x: builtins.int) -> builtins.int"
7892+
7893+
class D:
7894+
@add_wrong_first
7895+
def fn1() -> int: # E: Self argument missing for a non-static method (or an invalid type for self)
7896+
return 0
7897+
7898+
@add_wrong_first
7899+
def fn2(_x: int) -> int: # E: Self argument missing for a non-static method (or an invalid type for self)
7900+
return 0
7901+
7902+
@add_wrong_first
7903+
def fn3(self, _x: int) -> int: # E: Self argument missing for a non-static method (or an invalid type for self)
7904+
return 0
7905+
7906+
reveal_type(D().fn1) # E: Invalid self argument "D" to attribute function "fn1" with type "Callable[[int], int]" \
7907+
# N: Revealed type is "def () -> builtins.int"
7908+
reveal_type(D().fn2) # E: Invalid self argument "D" to attribute function "fn2" with type "Callable[[int, int], int]" \
7909+
# N: Revealed type is "def (_x: builtins.int) -> builtins.int"
7910+
reveal_type(D().fn3) # E: Invalid self argument "D" to attribute function "fn3" with type "Callable[[int, D, int], int]" \
7911+
# N: Revealed type is "def (self: __main__.D, _x: builtins.int) -> builtins.int"
7912+
[builtins fixtures/tuple.pyi]
7913+
7914+
[case testMethodSelfArgumentChecksInUntyped]
7915+
from typing import Callable, ParamSpec, TypeVar
7916+
7917+
T = TypeVar("T")
7918+
P = ParamSpec("P")
7919+
7920+
def to_same_callable(fn: Callable[P, T]) -> Callable[P, T]:
7921+
return fn
7922+
7923+
def unchecked():
7924+
class Bad:
7925+
def fn() -> None: ... # E: Method must have at least one argument. Did you forget the "self" argument?
7926+
def fn2(x: int) -> None: ... # E: Self argument missing for a non-static method (or an invalid type for self)
7927+
7928+
# TODO: would be nice to make this error, but now we see the func
7929+
# being decorated as Any, not as a callable
7930+
@to_same_callable
7931+
def gaaa() -> None: ...
7932+
@to_same_callable
7933+
def gaaa2(x: int) -> None: ...
7934+
7935+
class Ok:
7936+
def fn(): ...
7937+
def fn2(x): ...
7938+
7939+
@to_same_callable
7940+
def g(): ...
7941+
@to_same_callable
7942+
def g2(x): ...
7943+
7944+
def checked() -> None:
7945+
class Bad:
7946+
def fn() -> None: ... # E: Method must have at least one argument. Did you forget the "self" argument?
7947+
def fn2(x: int) -> None: ... # E: Self argument missing for a non-static method (or an invalid type for self)
7948+
7949+
@to_same_callable
7950+
def g() -> None: ... # E: Method must have at least one argument. Did you forget the "self" argument?
7951+
@to_same_callable
7952+
def g2(x: int) -> None: ... # E: Self argument missing for a non-static method (or an invalid type for self)
7953+
7954+
class AlsoBad:
7955+
def fn(): ... # E: Method must have at least one argument. Did you forget the "self" argument?
7956+
def fn2(x): ...
7957+
7958+
@to_same_callable
7959+
def g(): ... # E: Method must have at least one argument. Did you forget the "self" argument?
7960+
@to_same_callable
7961+
def g2(x): ...
7962+
7963+
class Ok:
7964+
def fn(): ... # E: Method must have at least one argument. Did you forget the "self" argument?
7965+
def fn2(x): ...
7966+
7967+
@to_same_callable
7968+
def g(): ... # E: Method must have at least one argument. Did you forget the "self" argument?
7969+
@to_same_callable
7970+
def g2(x): ...
7971+
[builtins fixtures/tuple.pyi]
7972+
77457973
[case testTypeAfterAttributeAccessWithDisallowAnyExpr]
77467974
# flags: --disallow-any-expr
77477975

‎test-data/unit/fine-grained.test‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1720,7 +1720,7 @@ from typing import Iterator, Callable, List, Optional
17201720
from a import f
17211721
import a
17221722

1723-
def dec(f: Callable[['A'], Optional[Iterator[int]]]) -> Callable[[int], int]: pass
1723+
def dec(f: Callable[['A'], Optional[Iterator[int]]]) -> Callable[['A',int], int]: pass
17241724

17251725
class A:
17261726
@dec

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp