hijodelsol14
hijodelsol14

Reputation: 47

Specify generic return type without relying on arguments in python

I'm working on adding python type annotations to an existing codebase. I have a function that takes in a set of database IDs, checks if the user has permissions to view the underlying models, and then returns the list of models. The existing type annotations look something like:

AuthorizeableModel = TypeVar["ModelType", lower=HasAuthMixin]

def bulk_load_and_check_auth(model_ids: List[str]) -> List[AuthorizeableModel]:
    # ...

This isn't wrapped in a class since this can be used to bulk fetch a heterogeneous list of models. However, the HasAuthMixin type is pretty thin and oftentimes I need to do more complicated stuff with the return value of that function.

In typescript I could create a function signature like:

function bulkLoadAndCheckAuth<T extends AuthorizeableModel>(dbIds: Array<str>): List<T> {
  // logic

and then I could specify the expected type of the function

const models = bulkLoadAndCheckAuth<MyModel>(idsList);

Is there any way to do something similar with python types?

Upvotes: 0

Views: 1151

Answers (1)

Paweł Rubin
Paweł Rubin

Reputation: 3439

In Python generic type argument can be applied only in the case of classes.

However, classes can be callable, hence there is the following hack to achieve what you want:

AuthorizeableModel = TypeVar("AuthorizeableModel", bound=HasAuthMixin)


class _bulkLoadAndCheckAuthType:
    def __call__(self, model_ids: list[str]) -> list[HasAuthMixin]:
        ...

    def __getitem__(
        self, _: type[AuthorizeableModel]
    ) -> Callable[[list[str]], list[AuthorizeableModel]]:
        return self  # type: ignore


bulk_load_and_check_type = _bulkLoadAndCheckAuthType()

models = bulk_load_and_check_type[MyModel](["id1", "id2"])

reveal_type(models) # Revealed type is "builtins.list[MyModel]

Upvotes: 1

Related Questions