How to use `Paramspec`

No matter how I try to use it, I get a mypy error. Essentially I have a function like:

def normalize(cls, data, *args, normalizer=None, **kwargs):
    if isinstance(cls, GenericAlias) and cls.__origin__ == list:
        if not isinstance(data, list):
            data = [data]
        if normalizer:
            return [normalizer(d, *args, **kwargs) for d in data]
        obj_cls = cls.__args__[0]
        return [obj_cls(d, *args, **kwargs) for d in data]
    if normalizer:
        return normalizer(data, *args, **kwargs)
    return cls(data, *args, **kwargs)

which does the following:

  • If cls is a class type, simply pass data, *args, **kwargs to cls constructor
  • If cls is a list[cls], then make sure data is also a list and pass the elements of it along with *args, **kwargs to cls constructor and return the list of those objects
  • If normalizer is passed then use that instead of the constructor

I think I’ve understood the syntax for when normalizer is passed to be like:

T = TypeVar('T')
P = ParamSpec('P')
Normalizer: TypeAlias = Callable[Concatenate[str, P], T]

@overload
def normalize(cls: type[T], data: str, *args: P.args,  # type: ignore
              normalizer: Normalizer[P, T],
              **kwargs: P.kwargs) -> T:
    ...

@overload
def normalize(cls: type[list[T]], data: str, *args: P.args,
              normalizer: Normalizer[P, T],
              **kwargs: P.kwargs) -> list[T]:
    ...

@overload
def normalize(cls: type[list[T]], data: list[str], *args: P.args,
              normalizer: Normalizer[P, T],
              **kwargs: P.kwargs) -> list[T]:

But then, how do I combine this with the case where normalizer = None? How do I get the P.args to originate from cls? I was thinking of switching cls to be the constructor, but that would not solve the case of passing list[cls].