MCPcopy Index your code
hub / github.com/python/mypy / _analyze_class

Function _analyze_class

mypy/plugins/attrs.py:425–502  ·  view source on GitHub ↗

Analyze the class body of an attr maker, its parents, and return the Attributes found. auto_attribs=True means we'll generate attributes from type annotations also. auto_attribs=None means we'll detect which mode to use. class_kw_only=True means that all attributes created here will be

(
    ctx: mypy.plugin.ClassDefContext, auto_attribs: bool | None, class_kw_only: bool
)

Source from the content-addressed store, hash-verified

423
424
425def _analyze_class(
426 ctx: mypy.plugin.ClassDefContext, auto_attribs: bool | None, class_kw_only: bool
427) -> list[Attribute]:
428 """Analyze the class body of an attr maker, its parents, and return the Attributes found.
429
430 auto_attribs=True means we'll generate attributes from type annotations also.
431 auto_attribs=None means we'll detect which mode to use.
432 class_kw_only=True means that all attributes created here will be keyword only args by
433 default in __init__.
434 """
435 own_attrs: dict[str, Attribute] = {}
436 if auto_attribs is None:
437 auto_attribs = _detect_auto_attribs(ctx)
438
439 # Walk the body looking for assignments and decorators.
440 for stmt in ctx.cls.defs.body:
441 if isinstance(stmt, AssignmentStmt):
442 for attr in _attributes_from_assignment(ctx, stmt, auto_attribs, class_kw_only):
443 # When attrs are defined twice in the same body we want to use the 2nd definition
444 # in the 2nd location. So remove it from the OrderedDict.
445 # Unless it's auto_attribs in which case we want the 2nd definition in the
446 # 1st location.
447 if not auto_attribs and attr.name in own_attrs:
448 del own_attrs[attr.name]
449 own_attrs[attr.name] = attr
450 elif isinstance(stmt, Decorator):
451 _cleanup_decorator(stmt, own_attrs)
452
453 for attribute in own_attrs.values():
454 # Even though these look like class level assignments we want them to look like
455 # instance level assignments.
456 if attribute.name in ctx.cls.info.names:
457 node = ctx.cls.info.names[attribute.name].node
458 if isinstance(node, PlaceholderNode):
459 # This node is not ready yet.
460 continue
461 assert isinstance(node, Var), node
462 node.is_initialized_in_class = False
463
464 # Traverse the MRO and collect attributes from the parents.
465 taken_attr_names = set(own_attrs)
466 super_attrs = []
467 for super_info in ctx.cls.info.mro[1:-1]:
468 if "attrs" in super_info.metadata:
469 # Each class depends on the set of attributes in its attrs ancestors.
470 ctx.api.add_plugin_dependency(make_wildcard_trigger(super_info.fullname))
471
472 for data in super_info.metadata["attrs"]["attributes"]:
473 # Only add an attribute if it hasn't been defined before. This
474 # allows for overwriting attribute definitions by subclassing.
475 if data["name"] not in taken_attr_names:
476 a = Attribute.deserialize(super_info, data, ctx.api)
477 a.expand_typevar_from_subtype(ctx.cls.info)
478 super_attrs.append(a)
479 taken_attr_names.add(a.name)
480 attributes = super_attrs + list(own_attrs.values())
481
482 # Check the init args for correct default-ness. Note: This has to be done after all the

Callers 1

Calls 15

make_wildcard_triggerFunction · 0.90
_detect_auto_attribsFunction · 0.85
isinstanceFunction · 0.85
_cleanup_decoratorFunction · 0.85
setClass · 0.85
listClass · 0.85
enumerateFunction · 0.85
lenFunction · 0.85
valuesMethod · 0.80
appendMethod · 0.80
add_plugin_dependencyMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…