Analyze access to an attribute on a class object. itype is the return type of the class object callable, original_type is the type of E in the expression E.var, original_vars are type variables of the class callable (for generic classes).
(
itype: Instance,
name: str,
mx: MemberContext,
*,
mcs_fallback: Instance,
override_info: TypeInfo | None = None,
original_vars: Sequence[TypeVarLikeType] | None = None,
)
| 1133 | |
| 1134 | |
| 1135 | def analyze_class_attribute_access( |
| 1136 | itype: Instance, |
| 1137 | name: str, |
| 1138 | mx: MemberContext, |
| 1139 | *, |
| 1140 | mcs_fallback: Instance, |
| 1141 | override_info: TypeInfo | None = None, |
| 1142 | original_vars: Sequence[TypeVarLikeType] | None = None, |
| 1143 | ) -> Type | None: |
| 1144 | """Analyze access to an attribute on a class object. |
| 1145 | |
| 1146 | itype is the return type of the class object callable, original_type is the type |
| 1147 | of E in the expression E.var, original_vars are type variables of the class callable |
| 1148 | (for generic classes). |
| 1149 | """ |
| 1150 | info = itype.type |
| 1151 | if override_info: |
| 1152 | info = override_info |
| 1153 | |
| 1154 | fullname = f"{info.fullname}.{name}" |
| 1155 | hook = mx.chk.plugin.get_class_attribute_hook(fullname) |
| 1156 | |
| 1157 | node = info.get(name) |
| 1158 | if not node: |
| 1159 | if itype.extra_attrs and name in itype.extra_attrs.attrs: |
| 1160 | # For modules use direct symbol table lookup. |
| 1161 | if not itype.extra_attrs.mod_name: |
| 1162 | return itype.extra_attrs.attrs[name] |
| 1163 | if info.fallback_to_any or info.meta_fallback_to_any: |
| 1164 | return apply_class_attr_hook(mx, hook, AnyType(TypeOfAny.special_form)) |
| 1165 | return None |
| 1166 | |
| 1167 | if ( |
| 1168 | isinstance(node.node, Var) |
| 1169 | and not node.node.is_classvar |
| 1170 | and not hook |
| 1171 | and mcs_fallback.type.get(name) |
| 1172 | ): |
| 1173 | # If the same attribute is declared on the metaclass and the class but with different types, |
| 1174 | # and the attribute on the class is not a ClassVar, |
| 1175 | # the type of the attribute on the metaclass should take priority |
| 1176 | # over the type of the attribute on the class, |
| 1177 | # when the attribute is being accessed from the class object itself. |
| 1178 | # |
| 1179 | # Return `None` here to signify that the name should be looked up |
| 1180 | # on the class object itself rather than the instance. |
| 1181 | return None |
| 1182 | |
| 1183 | mx.chk.warn_deprecated(node.node, mx.context) |
| 1184 | |
| 1185 | is_decorated = isinstance(node.node, Decorator) |
| 1186 | is_method = is_decorated or isinstance(node.node, FuncBase) |
| 1187 | if mx.is_lvalue and not mx.suppress_errors: |
| 1188 | if is_method: |
| 1189 | mx.msg.cant_assign_to_method(mx.context) |
| 1190 | if isinstance(node.node, TypeInfo): |
| 1191 | mx.fail(message_registry.CANNOT_ASSIGN_TO_TYPE) |
| 1192 |
no test coverage detected
searching dependent graphs…