Commit befba35a authored by Igor Ponomarev's avatar Igor Ponomarev Committed by Nejc Habjan
Browse files

feat(api)!: Make RESTObjectList typing generic



BREAKING CHANGE: Type narrowing of `list()` methods return objects
from RESTObject to a concrete subclass (for example `MergeRequest`)
can become redundant.

Currently the RESTObjectList type hints yielded objects
as base RESTObject. However, the ListMixin is now generic
and will return the RESTObject subclass based on the RESTManager
typing.

Using `typing.Generic` it is possible to make RESTObjectList
type hint a specific subclass of the RESTObject.

Iterating over `list()` call the ListMixin will now yield
the same object class because both `list` and `RESTObjectList`
will have the same type hinted subclass.

Signed-off-by: default avatarIgor Ponomarev <igor.ponomarev@collabora.com>
parent 9040dbe5
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -252,7 +252,10 @@ class RESTObject:
        return obj_id


class RESTObjectList:
TObjCls = TypeVar("TObjCls", bound=RESTObject)


class RESTObjectList(Generic[TObjCls]):
    """Generator object representing a list of RESTObject's.

    This generator uses the Gitlab pagination system to fetch new data when
@@ -268,7 +271,7 @@ class RESTObjectList:
    """

    def __init__(
        self, manager: RESTManager[Any], obj_cls: type[RESTObject], _list: GitlabList
        self, manager: RESTManager[TObjCls], obj_cls: type[TObjCls], _list: GitlabList
    ) -> None:
        """Creates an objects list from a GitlabList.

@@ -284,16 +287,16 @@ class RESTObjectList:
        self._obj_cls = obj_cls
        self._list = _list

    def __iter__(self) -> RESTObjectList:
    def __iter__(self) -> RESTObjectList[TObjCls]:
        return self

    def __len__(self) -> int:
        return len(self._list)

    def __next__(self) -> RESTObject:
    def __next__(self) -> TObjCls:
        return self.next()

    def next(self) -> RESTObject:
    def next(self) -> TObjCls:
        data = self._list.next()
        return self._obj_cls(self.manager, data, created_from_list=True)

@@ -334,9 +337,6 @@ class RESTObjectList:
        return self._list.total


TObjCls = TypeVar("TObjCls", bound=RESTObject)


class RESTManager(Generic[TObjCls]):
    """Base class for CRUD operations on objects.

+3 −1
Original line number Diff line number Diff line
@@ -162,7 +162,9 @@ class ListMixin(HeadMixin[base.TObjCls]):
    _list_filters: tuple[str, ...] = ()

    @exc.on_http_error(exc.GitlabListError)
    def list(self, **kwargs: Any) -> base.RESTObjectList | list[base.TObjCls]:
    def list(
        self, **kwargs: Any
    ) -> base.RESTObjectList[base.TObjCls] | list[base.TObjCls]:
        """Retrieve a list of objects.

        Args:
+6 −1
Original line number Diff line number Diff line
@@ -133,7 +133,12 @@ class GitlabCLI:
            cli.die("Impossible to create object", e)
        return result

    def do_list(self) -> gitlab.base.RESTObjectList | list[gitlab.base.RESTObject]:
    def do_list(
        self,
    ) -> (
        gitlab.base.RESTObjectList[gitlab.base.RESTObject]
        | list[gitlab.base.RESTObject]
    ):
        if TYPE_CHECKING:
            assert isinstance(self.mgr, gitlab.mixins.ListMixin)
        message_details = gitlab.utils.WarnMessageData(
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ class LDAPGroupManager(RESTManager[LDAPGroup]):
    _list_filters = ("search", "provider")

    @exc.on_http_error(exc.GitlabListError)
    def list(self, **kwargs: Any) -> list[LDAPGroup] | RESTObjectList:
    def list(self, **kwargs: Any) -> list[LDAPGroup] | RESTObjectList[LDAPGroup]:
        """Retrieve a list of objects.

        Args:
+3 −3
Original line number Diff line number Diff line
@@ -203,7 +203,7 @@ class ProjectMergeRequest(

    @cli.register_custom_action(cls_names="ProjectMergeRequest")
    @exc.on_http_error(exc.GitlabListError)
    def related_issues(self, **kwargs: Any) -> RESTObjectList:
    def related_issues(self, **kwargs: Any) -> RESTObjectList[ProjectIssue]:
        """List issues related to this merge request."

        Args:
@@ -232,7 +232,7 @@ class ProjectMergeRequest(

    @cli.register_custom_action(cls_names="ProjectMergeRequest")
    @exc.on_http_error(exc.GitlabListError)
    def closes_issues(self, **kwargs: Any) -> RESTObjectList:
    def closes_issues(self, **kwargs: Any) -> RESTObjectList[ProjectIssue]:
        """List issues that will close on merge."

        Args:
@@ -257,7 +257,7 @@ class ProjectMergeRequest(

    @cli.register_custom_action(cls_names="ProjectMergeRequest")
    @exc.on_http_error(exc.GitlabListError)
    def commits(self, **kwargs: Any) -> RESTObjectList:
    def commits(self, **kwargs: Any) -> RESTObjectList[ProjectCommit]:
        """List the merge request commits.

        Args:
Loading