@@ -1981,22 +1981,26 @@ def check_method_override(
19811981 "__post_init__" ,
19821982 ) and (self .options .check_untyped_defs or not defn .is_dynamic ())
19831983 found_method_base_classes : list [TypeInfo ] = []
1984- for base in defn .info .mro [1 :]:
1985- result = self .check_method_or_accessor_override_for_base (
1986- defn , base , check_override_compatibility
1987- )
1988- if result is None :
1989- # Node was deferred, we will have another attempt later.
1990- return None
1991- if result :
1992- found_method_base_classes .append (base )
1984+ for directbase in defn .info .bases :
1985+ first_baseclass = True
1986+ for base in directbase .type .mro :
1987+ result = self .check_method_or_accessor_override_for_base (
1988+ defn , base , check_override_compatibility , first_baseclass
1989+ )
1990+ if result is None :
1991+ # Node was deferred, we will have another attempt later.
1992+ return None
1993+ if result :
1994+ found_method_base_classes .append (base )
1995+ first_baseclass = False
19931996 return found_method_base_classes
19941997
19951998 def check_method_or_accessor_override_for_base (
19961999 self ,
19972000 defn : FuncDef | OverloadedFuncDef | Decorator ,
19982001 base : TypeInfo ,
19992002 check_override_compatibility : bool ,
2003+ first_baseclass : bool ,
20002004 ) -> bool | None :
20012005 """Check if method definition is compatible with a base class.
20022006
@@ -2020,7 +2024,7 @@ def check_method_or_accessor_override_for_base(
20202024 if check_override_compatibility :
20212025 # Check compatibility of the override signature
20222026 # (__init__, __new__, __init_subclass__ are special).
2023- if self .check_method_override_for_base_with_name (defn , name , base ):
2027+ if self .check_method_override_for_base_with_name (defn , name , base , first_baseclass ):
20242028 return None
20252029 if name in operators .inplace_operator_methods :
20262030 # Figure out the name of the corresponding operator method.
@@ -2029,12 +2033,12 @@ def check_method_or_accessor_override_for_base(
20292033 # always introduced safely if a base class defined __add__.
20302034 # TODO can't come up with an example where this is
20312035 # necessary; now it's "just in case"
2032- if self .check_method_override_for_base_with_name (defn , method , base ):
2036+ if self .check_method_override_for_base_with_name (defn , method , base , first_baseclass ):
20332037 return None
20342038 return found_base_method
20352039
20362040 def check_method_override_for_base_with_name (
2037- self , defn : FuncDef | OverloadedFuncDef | Decorator , name : str , base : TypeInfo
2041+ self , defn : FuncDef | OverloadedFuncDef | Decorator , name : str , base : TypeInfo , first_baseclass : bool
20382042 ) -> bool :
20392043 """Check if overriding an attribute `name` of `base` with `defn` is valid.
20402044
@@ -2135,33 +2139,43 @@ def check_method_override_for_base_with_name(
21352139 if isinstance (original_type , AnyType ) or isinstance (typ , AnyType ):
21362140 pass
21372141 elif isinstance (original_type , FunctionLike ) and isinstance (typ , FunctionLike ):
2138- # Check that the types are compatible.
2139- ok = self .check_override (
2140- typ ,
2141- original_type ,
2142- defn .name ,
2143- name ,
2144- base .name ,
2145- original_class_or_static ,
2146- override_class_or_static ,
2147- context ,
2148- )
2149- # Check if this override is covariant.
2150- if (
2151- ok
2152- and original_node
2153- and codes .MUTABLE_OVERRIDE in self .options .enabled_error_codes
2154- and self .is_writable_attribute (original_node )
2155- and not is_subtype (original_type , typ , ignore_pos_arg_names = True )
2156- ):
2157- base_str , override_str = format_type_distinctly (
2158- original_type , typ , options = self .options
2159- )
2160- msg = message_registry .COVARIANT_OVERRIDE_OF_MUTABLE_ATTRIBUTE .with_additional_msg (
2161- f' (base class "{ base .name } " defined the type as { base_str } ,'
2162- f" override has type { override_str } )"
2142+ if isinstance (original_node , Decorator ):
2143+ deprecated = original_node .func .deprecated
2144+ elif isinstance (original_node , OverloadedFuncDef ):
2145+ deprecated = original_node .deprecated
2146+ else :
2147+ deprecated = None
2148+ if deprecated is None :
2149+ # Check that the types are compatible.
2150+ ok = self .check_override (
2151+ typ ,
2152+ original_type ,
2153+ defn .name ,
2154+ name ,
2155+ base .name ,
2156+ original_class_or_static ,
2157+ override_class_or_static ,
2158+ context ,
21632159 )
2164- self .fail (msg , context )
2160+ # Check if this override is covariant.
2161+ if (
2162+ ok
2163+ and original_node
2164+ and codes .MUTABLE_OVERRIDE in self .options .enabled_error_codes
2165+ and self .is_writable_attribute (original_node )
2166+ and not is_subtype (original_type , typ , ignore_pos_arg_names = True )
2167+ ):
2168+ base_str , override_str = format_type_distinctly (
2169+ original_type , typ , options = self .options
2170+ )
2171+ msg = message_registry .COVARIANT_OVERRIDE_OF_MUTABLE_ATTRIBUTE .with_additional_msg (
2172+ f' (base class "{ base .name } " defined the type as { base_str } ,'
2173+ f" override has type { override_str } )"
2174+ )
2175+ self .fail (msg , context )
2176+ elif context .is_explicit_override and first_baseclass and not is_private (context .name ):
2177+ warn = self .fail if self .options .report_deprecated_as_error else self .note
2178+ warn (deprecated , context , code = codes .DEPRECATED )
21652179 elif isinstance (original_type , UnionType ) and any (
21662180 is_subtype (typ , orig_typ , ignore_pos_arg_names = True )
21672181 for orig_typ in original_type .items
0 commit comments