Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python type checking return list base model #87

Open
Andrew-Chen-Wang opened this issue May 19, 2024 · 1 comment
Open

Python type checking return list base model #87

Andrew-Chen-Wang opened this issue May 19, 2024 · 1 comment

Comments

@Andrew-Chen-Wang
Copy link

Andrew-Chen-Wang commented May 19, 2024

Hi we're utilizing a helper class to parse over the paginated lists as so:

from typing import Any, Callable, ParamSpec, TypeVar

from merge.client import Merge
from merge.core import ApiError
from merge.resources.hris import Employee, Group

_T = ParamSpec("_T")
_R = TypeVar("_R", covariant=True)


class Middleware:
    def __init__(self, merge_client: Merge):
        self.merge_client = merge_client

    def _executor(self, func: Callable[_T, _R], *args: _T.args, **kwargs: _T.kwargs) -> list[Any]:
        """Exhausts a paginated API until all data is retrieved"""
        data = []

        cursor = ""
        while cursor is not None:
            try:
                next_page = func(*args, **kwargs, cursor=cursor)  # type: ignore[arg-type]

                for result in next_page.results:  # type: ignore[attr-defined]
                    data.append(result)

                cursor = next_page.next  # type: ignore[attr-defined]
            except Exception as e:
                logger.error(
                    f"Error while fetching users from Merge. Breaking pagination early: {e}"
                )
                break

        return data

    def get_users(self) -> list[Employee]:
        return self._executor(self.merge_client.hris.employees.list)

Noticing the mypy type ignores, we're having issues with the ParamSpec variable and the return type generic TypeVar covariant. It would be great if all return list return types could subclass from a base Pydantic model as all paginated pydantic models shown are like:

class PaginatedEmployeeList(pydantic.BaseModel):
    next: typing.Optional[str]
    previous: typing.Optional[str]
    results: typing.Optional[typing.List[Employee]]

where the only difference is the "Employee" model which could easily be made a template variable. This way, we can make the return type the base pagination list Pydantic model instead of a generic TypeVar and remove the type ignores.

Thanks:)

@Andrew-Chen-Wang Andrew-Chen-Wang changed the title Python type checking Python type checking return list base model May 19, 2024
@lucasgadams
Copy link

Agreed, i was just looking into doing the same thing and then saw that there is no paginated base class which makes the typing difficult.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants