Checks whether argument default values are compatible.
(
stub_arg: nodes.Argument, runtime_arg: inspect.Parameter
)
| 829 | |
| 830 | |
| 831 | def _verify_arg_default_value( |
| 832 | stub_arg: nodes.Argument, runtime_arg: inspect.Parameter |
| 833 | ) -> Iterator[str]: |
| 834 | """Checks whether argument default values are compatible.""" |
| 835 | if runtime_arg.default is not inspect.Parameter.empty: |
| 836 | if stub_arg.kind.is_required(): |
| 837 | yield ( |
| 838 | f'runtime parameter "{runtime_arg.name}" ' |
| 839 | "has a default value but stub parameter does not" |
| 840 | ) |
| 841 | else: |
| 842 | type_context = stub_arg.variable.type |
| 843 | runtime_type = get_mypy_type_of_runtime_value( |
| 844 | runtime_arg.default, type_context=type_context |
| 845 | ) |
| 846 | |
| 847 | # Fallback to the type annotation type if var type is missing. The type annotation |
| 848 | # is an UnboundType, but I don't know enough to know what the pros and cons here are. |
| 849 | # UnboundTypes have ugly question marks following them, so default to var type. |
| 850 | # Note we do this same fallback when constructing signatures in from_overloadedfuncdef |
| 851 | stub_type = stub_arg.variable.type or stub_arg.type_annotation |
| 852 | if isinstance(stub_type, mypy.types.TypeVarType): |
| 853 | stub_type = stub_type.upper_bound |
| 854 | if ( |
| 855 | runtime_type is not None |
| 856 | and stub_type is not None |
| 857 | # Avoid false positives for marker objects |
| 858 | and type(runtime_arg.default) is not object |
| 859 | # And ellipsis |
| 860 | and runtime_arg.default is not ... |
| 861 | and not is_subtype_helper(runtime_type, stub_type) |
| 862 | ): |
| 863 | yield ( |
| 864 | f'runtime parameter "{runtime_arg.name}" ' |
| 865 | f"has a default value of type {runtime_type}, " |
| 866 | f"which is incompatible with stub parameter type {stub_type}" |
| 867 | ) |
| 868 | if stub_arg.initializer is not None: |
| 869 | stub_default = evaluate_expression(stub_arg.initializer) |
| 870 | if ( |
| 871 | stub_default is not UNKNOWN |
| 872 | and stub_default is not ... |
| 873 | and runtime_arg.default is not UNREPRESENTABLE |
| 874 | ): |
| 875 | defaults_match = True |
| 876 | # We want the types to match exactly, e.g. in case the stub has |
| 877 | # True and the runtime has 1 (or vice versa). |
| 878 | if type(stub_default) is not type(runtime_arg.default): |
| 879 | defaults_match = False |
| 880 | else: |
| 881 | try: |
| 882 | defaults_match = bool(stub_default == runtime_arg.default) |
| 883 | except Exception: |
| 884 | # Exception can be raised in bool dunder method (e.g. numpy arrays) |
| 885 | # At this point, consider the default to be different, it is probably |
| 886 | # too complex to put in a stub anyway. |
| 887 | defaults_match = False |
| 888 | if not defaults_match: |
no test coverage detected
searching dependent graphs…