Format attributes that are valid for a given expression. If expression type is not an Instance, try using fallback. Attributes are returned as a JSON (ordered by MRO) that maps base class name to list of attributes. Attributes may appear in multiple bases if overridden (we s
(self, expression: Expression)
| 311 | attrs_strs.append(f'"{cls_name}": [{", ".join(attrs)}]') |
| 312 | |
| 313 | def expr_attrs(self, expression: Expression) -> tuple[str, bool]: |
| 314 | """Format attributes that are valid for a given expression. |
| 315 | |
| 316 | If expression type is not an Instance, try using fallback. Attributes are |
| 317 | returned as a JSON (ordered by MRO) that maps base class name to list of |
| 318 | attributes. Attributes may appear in multiple bases if overridden (we simply |
| 319 | follow usual mypy logic for creating new Vars etc). |
| 320 | """ |
| 321 | expr_type = self.fg_manager.manager.all_types.get(expression) |
| 322 | if expr_type is None: |
| 323 | return self.missing_type(expression), False |
| 324 | |
| 325 | expr_type = get_proper_type(expr_type) |
| 326 | instances = get_instance_fallback(expr_type) |
| 327 | if not instances: |
| 328 | # Everything is an object in Python. |
| 329 | instances = [self.object_type()] |
| 330 | |
| 331 | attrs_dict = self.collect_attrs(instances) |
| 332 | |
| 333 | # Special case: modules have names apart from those from ModuleType. |
| 334 | if isinstance(expression, RefExpr) and isinstance(expression.node, MypyFile): |
| 335 | node = expression.node |
| 336 | names = sorted(node.names) |
| 337 | if "__builtins__" in names: |
| 338 | # This is just to make tests stable. No one will really need this name. |
| 339 | names.remove("__builtins__") |
| 340 | mod_dict = {f'"<{node.fullname}>"': [f'"{name}"' for name in names]} |
| 341 | else: |
| 342 | mod_dict = {} |
| 343 | |
| 344 | # Special case: for class callables, prepend with the class attributes. |
| 345 | # TODO: also handle cases when such callable appears in a union. |
| 346 | if isinstance(expr_type, FunctionLike) and expr_type.is_type_obj(): |
| 347 | template = fill_typevars_with_any(expr_type.type_object()) |
| 348 | class_dict = self.collect_attrs(get_instance_fallback(template)) |
| 349 | else: |
| 350 | class_dict = {} |
| 351 | |
| 352 | # We don't use JSON dump to be sure keys order is always preserved. |
| 353 | base_attrs = [] |
| 354 | if mod_dict: |
| 355 | for mod in mod_dict: |
| 356 | base_attrs.append(f'{mod}: [{", ".join(mod_dict[mod])}]') |
| 357 | self._fill_from_dict(base_attrs, class_dict) |
| 358 | self._fill_from_dict(base_attrs, attrs_dict) |
| 359 | return self.add_prefixes(f'{{{", ".join(base_attrs)}}}', expression), True |
| 360 | |
| 361 | def format_node(self, module: State, node: FuncBase | SymbolNode) -> str: |
| 362 | return f"{module.path}:{node.line}:{node.column + 1}:{node.name}" |
nothing calls this directly
no test coverage detected