(ctx: mypy.plugin.FunctionContext, callee: Type)
| 150 | |
| 151 | |
| 152 | def handle_partial_with_callee(ctx: mypy.plugin.FunctionContext, callee: Type) -> Type: |
| 153 | if not isinstance(ctx.api, mypy.checker.TypeChecker): # use internals |
| 154 | return ctx.default_return_type |
| 155 | |
| 156 | if isinstance(callee_proper := get_proper_type(callee), UnionType): |
| 157 | return UnionType.make_union( |
| 158 | [handle_partial_with_callee(ctx, item) for item in callee_proper.items] |
| 159 | ) |
| 160 | |
| 161 | fn_type = ctx.api.extract_callable_type(callee, ctx=ctx.default_return_type) |
| 162 | if fn_type is None: |
| 163 | return ctx.default_return_type |
| 164 | |
| 165 | # We must normalize from the start to have coherent view together with TypeChecker. |
| 166 | fn_type = fn_type.with_unpacked_kwargs().with_normalized_var_args() |
| 167 | |
| 168 | last_context = ctx.api.type_context[-1] |
| 169 | if not fn_type.is_type_obj(): |
| 170 | # We wrap the return type to get use of a possible type context provided by caller. |
| 171 | # We cannot do this in case of class objects, since otherwise the plugin may get |
| 172 | # falsely triggered when evaluating the constructed call itself. |
| 173 | ret_type: Type = ctx.api.named_generic_type(PARTIAL, [fn_type.ret_type]) |
| 174 | wrapped_return = True |
| 175 | else: |
| 176 | ret_type = fn_type.ret_type |
| 177 | # Instead, for class objects we ignore any type context to avoid spurious errors, |
| 178 | # since the type context will be partial[X] etc., not X. |
| 179 | ctx.api.type_context[-1] = None |
| 180 | wrapped_return = False |
| 181 | |
| 182 | # Flatten actual to formal mapping, since this is what check_call() expects. |
| 183 | actual_args = [] |
| 184 | actual_arg_kinds = [] |
| 185 | actual_arg_names = [] |
| 186 | actual_types = [] |
| 187 | seen_args = set() |
| 188 | for i, param in enumerate(ctx.args[1:], start=1): |
| 189 | for j, a in enumerate(param): |
| 190 | if a in seen_args: |
| 191 | # Same actual arg can map to multiple formals, but we need to include |
| 192 | # each one only once. |
| 193 | continue |
| 194 | # Here we rely on the fact that expressions are essentially immutable, so |
| 195 | # they can be compared by identity. |
| 196 | seen_args.add(a) |
| 197 | actual_args.append(a) |
| 198 | actual_arg_kinds.append(ctx.arg_kinds[i][j]) |
| 199 | actual_arg_names.append(ctx.arg_names[i][j]) |
| 200 | actual_types.append(ctx.arg_types[i][j]) |
| 201 | |
| 202 | formal_to_actual = map_actuals_to_formals( |
| 203 | actual_kinds=actual_arg_kinds, |
| 204 | actual_names=actual_arg_names, |
| 205 | formal_kinds=fn_type.arg_kinds, |
| 206 | formal_names=fn_type.arg_names, |
| 207 | actual_arg_type=lambda i: actual_types[i], |
| 208 | ) |
| 209 |
no test coverage detected
searching dependent graphs…