Returns a Signature from an OverloadedFuncDef. If life were simple, to verify_overloadedfuncdef, we'd just verify_funcitem for each of its items. Unfortunately, life isn't simple and overloads are pretty deceitful. So instead, we try and combine the overload's items into a s
(stub: nodes.OverloadedFuncDef)
| 1008 | |
| 1009 | @staticmethod |
| 1010 | def from_overloadedfuncdef(stub: nodes.OverloadedFuncDef) -> Signature[nodes.Argument]: |
| 1011 | """Returns a Signature from an OverloadedFuncDef. |
| 1012 | |
| 1013 | If life were simple, to verify_overloadedfuncdef, we'd just verify_funcitem for each of its |
| 1014 | items. Unfortunately, life isn't simple and overloads are pretty deceitful. So instead, we |
| 1015 | try and combine the overload's items into a single signature that is compatible with any |
| 1016 | lies it might try to tell. |
| 1017 | |
| 1018 | """ |
| 1019 | # For most dunder methods, just assume all args are positional-only |
| 1020 | assume_positional_only = is_dunder(stub.name, exclude_special=True) |
| 1021 | |
| 1022 | is_arg_pos_only: defaultdict[str, set[bool]] = defaultdict(set) |
| 1023 | for func in map(_resolve_funcitem_from_decorator, stub.items): |
| 1024 | assert func is not None, f"Failed to resolve decorated overload of {stub.fullname!r}" |
| 1025 | args = maybe_strip_cls(stub.name, func.arguments) |
| 1026 | for index, arg in enumerate(args): |
| 1027 | if ( |
| 1028 | arg.variable.name.startswith("__") |
| 1029 | or arg.pos_only |
| 1030 | or assume_positional_only |
| 1031 | or arg.variable.name.strip("_") == "self" |
| 1032 | or (index == 0 and arg.variable.name.strip("_") == "cls") |
| 1033 | ): |
| 1034 | is_arg_pos_only[arg.variable.name].add(True) |
| 1035 | else: |
| 1036 | is_arg_pos_only[arg.variable.name].add(False) |
| 1037 | |
| 1038 | all_args: dict[str, list[tuple[nodes.Argument, int]]] = {} |
| 1039 | for func in map(_resolve_funcitem_from_decorator, stub.items): |
| 1040 | assert func is not None, f"Failed to resolve decorated overload of {stub.fullname!r}" |
| 1041 | args = maybe_strip_cls(stub.name, func.arguments) |
| 1042 | for index, arg in enumerate(args): |
| 1043 | # For positional-only args, we allow overloads to have different names for the same |
| 1044 | # argument. To accomplish this, we just make up a fake index-based name. |
| 1045 | # We can only use the index-based name if the argument is always |
| 1046 | # positional only. Sometimes overloads have an arg as positional-only |
| 1047 | # in some but not all branches of the overload. |
| 1048 | name = arg.variable.name |
| 1049 | if is_arg_pos_only[name] == {True}: |
| 1050 | name = f"__{index}" |
| 1051 | |
| 1052 | all_args.setdefault(name, []).append((arg, index)) |
| 1053 | |
| 1054 | def get_position(arg_name: str) -> int: |
| 1055 | # We just need this to return the positional args in the correct order. |
| 1056 | return max(index for _, index in all_args[arg_name]) |
| 1057 | |
| 1058 | def get_type(arg_name: str) -> mypy.types.ProperType: |
| 1059 | with mypy.state.state.strict_optional_set(True): |
| 1060 | all_types = [ |
| 1061 | arg.variable.type or arg.type_annotation for arg, _ in all_args[arg_name] |
| 1062 | ] |
| 1063 | return mypy.typeops.make_simplified_union([t for t in all_types if t]) |
| 1064 | |
| 1065 | def get_kind(arg_name: str) -> nodes.ArgKind: |
| 1066 | kinds = {arg.kind for arg, _ in all_args[arg_name]} |
| 1067 | if nodes.ARG_STAR in kinds: |
no test coverage detected