Hello everyone!
Using VSCode:
Python 3.12.7
Pylance v2024.11.1
pyright v1.1.386 (from how I understand it Pylance CHANGELOG)
**EDIT: simplified question and example code
Trying to get correct type-hinting results for prepending a function signature with new parameters.
Example setup (simplified as much as I could):
from typing import cast, Callable
class MyBase: ...
class MyClass_1(MyBase): ...
class MyClass_2(MyBase): ...
def my_func(p: int) -> str: ...
The idea is to be able to call my_func
with some predefined count and type of instances of subclasses of MyBase
.
What I’m trying is to define a “decorator” that accepts at least one and var-count more types:
def my_wrapper[**P, R, B](
a: Callable[P, R],
b: type[B],
*args: type[B],
):
def wrapper(a: Callable[P, R], b: type[B]):
def wrapped(b: B | None = None, /, *args: P.args, **kwargs: P.kwargs) -> R:
# do something ...
return cast(R, "some result")
return wrapped
all_args = [b, *args]
all_args.reverse()
res = wrapper(a, all_args[0])
for arg in all_args[1:]:
res = wrapper(res, arg) # type: ignore
return res
Expectation is having to call the “decorator” once with as many types for additional params as needed:
wrapped = my_wrapper(my_func, MyClass_1, MyClass_2)
wrapped(MyClass_1(), MyClass_2(), ... other args for my_func)
Works as expected, but type-hinting gets totally broken.
Is there any way of doing that, while preserving the correct and useful type-hinting?
I guess the issue is that every time the decorator is called, it appends a new param with a duplicate name of an existing param? Tried figuring out how to do that insane thing as well (dynamic name of a function parameter) but couldn’t figure out how to make it work, not to mention type it…
Any ideas, comments, suggestions how this or something similar can be achieved?
I don’t have issues with using any hacks inside the my_wrapper
function, or # type: ignore
s etc.