Return the Converter object from an Expression.
(
ctx: mypy.plugin.ClassDefContext, converter_expr: Expression | None
)
| 699 | |
| 700 | |
| 701 | def _parse_converter( |
| 702 | ctx: mypy.plugin.ClassDefContext, converter_expr: Expression | None |
| 703 | ) -> Converter | None: |
| 704 | """Return the Converter object from an Expression.""" |
| 705 | # TODO: Support complex converters, e.g. lambdas, calls, etc. |
| 706 | if not converter_expr: |
| 707 | return None |
| 708 | converter_info = Converter() |
| 709 | if ( |
| 710 | isinstance(converter_expr, CallExpr) |
| 711 | and isinstance(converter_expr.callee, RefExpr) |
| 712 | and converter_expr.callee.fullname in attr_optional_converters |
| 713 | and converter_expr.args |
| 714 | and converter_expr.args[0] |
| 715 | ): |
| 716 | # Special handling for attr.converters.optional(type) |
| 717 | # We extract the type and add make the init_args Optional in Attribute.argument |
| 718 | converter_expr = converter_expr.args[0] |
| 719 | is_attr_converters_optional = True |
| 720 | else: |
| 721 | is_attr_converters_optional = False |
| 722 | |
| 723 | converter_type: Type | None = None |
| 724 | if isinstance(converter_expr, RefExpr) and converter_expr.node: |
| 725 | if isinstance(converter_expr.node, FuncDef): |
| 726 | if converter_expr.node.type and isinstance(converter_expr.node.type, FunctionLike): |
| 727 | converter_type = converter_expr.node.type |
| 728 | else: # The converter is an unannotated function. |
| 729 | converter_info.init_type = AnyType(TypeOfAny.unannotated) |
| 730 | return converter_info |
| 731 | elif isinstance(converter_expr.node, OverloadedFuncDef) and is_valid_overloaded_converter( |
| 732 | converter_expr.node |
| 733 | ): |
| 734 | converter_type = converter_expr.node.type |
| 735 | elif isinstance(converter_expr.node, TypeInfo): |
| 736 | converter_type = type_object_type(converter_expr.node) |
| 737 | elif ( |
| 738 | isinstance(converter_expr, IndexExpr) |
| 739 | and isinstance(converter_expr.analyzed, TypeApplication) |
| 740 | and isinstance(converter_expr.base, RefExpr) |
| 741 | and isinstance(converter_expr.base.node, TypeInfo) |
| 742 | ): |
| 743 | # The converter is a generic type. |
| 744 | converter_type = type_object_type(converter_expr.base.node) |
| 745 | if isinstance(converter_type, CallableType): |
| 746 | converter_type = apply_generic_arguments( |
| 747 | converter_type, |
| 748 | converter_expr.analyzed.types, |
| 749 | ctx.api.msg.incompatible_typevar_value, |
| 750 | converter_type, |
| 751 | ) |
| 752 | else: |
| 753 | converter_type = None |
| 754 | |
| 755 | if isinstance(converter_expr, LambdaExpr): |
| 756 | # TODO: should we send a fail if converter_expr.min_args > 1? |
| 757 | converter_info.init_type = AnyType(TypeOfAny.unannotated) |
| 758 | return converter_info |
no test coverage detected
searching dependent graphs…