(
stub: Signature[nodes.Argument],
runtime: Signature[inspect.Parameter],
function_name: str,
warn_runtime_is_object_init: bool = False,
)
| 1106 | |
| 1107 | |
| 1108 | def _verify_signature( |
| 1109 | stub: Signature[nodes.Argument], |
| 1110 | runtime: Signature[inspect.Parameter], |
| 1111 | function_name: str, |
| 1112 | warn_runtime_is_object_init: bool = False, |
| 1113 | ) -> Iterator[str]: |
| 1114 | # Check positional arguments match up |
| 1115 | for stub_arg, runtime_arg in zip(stub.pos, runtime.pos): |
| 1116 | yield from _verify_arg_name(stub_arg, runtime_arg, function_name) |
| 1117 | yield from _verify_arg_default_value(stub_arg, runtime_arg) |
| 1118 | if ( |
| 1119 | runtime_arg.kind == inspect.Parameter.POSITIONAL_ONLY |
| 1120 | and not stub_arg.pos_only |
| 1121 | and not stub_arg.variable.name.startswith("__") |
| 1122 | and stub_arg.variable.name.strip("_") != "self" |
| 1123 | and stub_arg.variable.name.strip("_") != "cls" |
| 1124 | ): |
| 1125 | yield ( |
| 1126 | f'stub parameter "{stub_arg.variable.name}" should be positional-only ' |
| 1127 | f'(add "/", e.g. "{runtime_arg.name}, /")' |
| 1128 | ) |
| 1129 | if ( |
| 1130 | runtime_arg.kind != inspect.Parameter.POSITIONAL_ONLY |
| 1131 | and (stub_arg.pos_only or stub_arg.variable.name.startswith("__")) |
| 1132 | and not runtime_arg.name.startswith("__") |
| 1133 | and stub_arg.variable.name.strip("_") != "self" |
| 1134 | and stub_arg.variable.name.strip("_") != "cls" |
| 1135 | and not is_dunder(function_name, exclude_special=True) # noisy for dunder methods |
| 1136 | ): |
| 1137 | yield ( |
| 1138 | f'stub parameter "{stub_arg.variable.name}" should be positional or keyword ' |
| 1139 | '(remove "/")' |
| 1140 | ) |
| 1141 | |
| 1142 | # Check unmatched positional args |
| 1143 | if len(stub.pos) > len(runtime.pos): |
| 1144 | # There are cases where the stub exhaustively lists out the extra parameters the function |
| 1145 | # would take through *args. Hence, a) if runtime accepts *args, we don't check whether the |
| 1146 | # runtime has all of the stub's parameters, b) below, we don't enforce that the stub takes |
| 1147 | # *args, since runtime logic may prevent arbitrary arguments from actually being accepted. |
| 1148 | if runtime.varpos is None: |
| 1149 | for stub_arg in stub.pos[len(runtime.pos) :]: |
| 1150 | # If the variable is in runtime.kwonly, it's just mislabelled as not a |
| 1151 | # keyword-only argument |
| 1152 | if stub_arg.variable.name not in runtime.kwonly: |
| 1153 | msg = f'runtime does not have parameter "{stub_arg.variable.name}"' |
| 1154 | if runtime.varkw is not None: |
| 1155 | msg += ". Maybe you forgot to make it keyword-only in the stub?" |
| 1156 | elif warn_runtime_is_object_init: |
| 1157 | msg += ". You may need to write stubs for __new__ instead of __init__." |
| 1158 | yield msg |
| 1159 | else: |
| 1160 | yield f'stub parameter "{stub_arg.variable.name}" is not keyword-only' |
| 1161 | if stub.varpos is not None: |
| 1162 | yield f'runtime does not have *args parameter "{stub.varpos.variable.name}"' |
| 1163 | elif len(stub.pos) < len(runtime.pos): |
| 1164 | for runtime_arg in runtime.pos[len(stub.pos) :]: |
| 1165 | if runtime_arg.name not in stub.kwonly: |
no test coverage detected
searching dependent graphs…