Commit 44fd9dc1 authored by Igor Ponomarev's avatar Igor Ponomarev Committed by John Villalovos
Browse files

feat(api): Narrow down return type of download methods using typing.overload



Currently the download methods such as `ProjectJob.artifacts` have
return type set to `Optional[Union[bytes, Iterator[Any]]]` which
means they return either `None` or `bytes` or `Iterator[Any]`.

However, the actual return type is determined by the passed
`streamed` and `iterator` arguments. Using `@typing.overload`
decorator it is possible to return a single type based on the
passed arguments.

Add overloads in the following order to all download methods:

1. If `streamed=False` and `iterator=False` return `bytes`. This
   is the default argument values therefore it should be first as
   it will be used to lookup default arguments.
2. If `iterator=True` return `Iterator[Any]`. This can be combined
   with both `streamed=True` and `streamed=False`.
3. If `streamed=True` and `iterator=False` return `None`. In this
   case `action` argument can be set to a callable that accepts
   `bytes`.

Signed-off-by: default avatarIgor Ponomarev <igor.ponomarev@collabora.com>
parent e4c5c74f
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -6,7 +6,9 @@ from typing import (
    Dict,
    Iterator,
    List,
    Literal,
    Optional,
    overload,
    Tuple,
    Type,
    TYPE_CHECKING,
@@ -612,6 +614,39 @@ class DownloadMixin(_RestObjectBase):
    _updated_attrs: Dict[str, Any]
    manager: base.RESTManager

    @overload
    def download(
        self,
        streamed: Literal[False] = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> bytes: ...

    @overload
    def download(
        self,
        streamed: bool = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[True] = True,
        **kwargs: Any,
    ) -> Iterator[Any]: ...

    @overload
    def download(
        self,
        streamed: Literal[True] = True,
        action: Optional[Callable[[bytes], None]] = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> None: ...

    @cli.register_custom_action(cls_names=("GroupExport", "ProjectExport"))
    @exc.on_http_error(exc.GitlabGetError)
    def download(
+91 −1
Original line number Diff line number Diff line
@@ -3,7 +3,16 @@ GitLab API:
https://docs.gitlab.com/ee/api/job_artifacts.html
"""

from typing import Any, Callable, Iterator, Optional, TYPE_CHECKING, Union
from typing import (
    Any,
    Callable,
    Iterator,
    Literal,
    Optional,
    overload,
    TYPE_CHECKING,
    Union,
)

import requests

@@ -43,6 +52,45 @@ class ProjectArtifactManager(RESTManager):
            assert path is not None
        self.gitlab.http_delete(path, **kwargs)

    @overload
    def download(
        self,
        ref_name: str,
        job: str,
        streamed: Literal[False] = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> bytes: ...

    @overload
    def download(
        self,
        ref_name: str,
        job: str,
        streamed: bool = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[True] = True,
        **kwargs: Any,
    ) -> Iterator[Any]: ...

    @overload
    def download(
        self,
        ref_name: str,
        job: str,
        streamed: Literal[True] = True,
        action: Optional[Callable[[bytes], None]] = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> None: ...

    @cli.register_custom_action(
        cls_names="ProjectArtifactManager",
        required=("ref_name", "job"),
@@ -94,6 +142,48 @@ class ProjectArtifactManager(RESTManager):
            result, streamed, action, chunk_size, iterator=iterator
        )

    @overload
    def raw(
        self,
        ref_name: str,
        artifact_path: str,
        job: str,
        streamed: Literal[False] = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> bytes: ...

    @overload
    def raw(
        self,
        ref_name: str,
        artifact_path: str,
        job: str,
        streamed: bool = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[True] = True,
        **kwargs: Any,
    ) -> Iterator[Any]: ...

    @overload
    def raw(
        self,
        ref_name: str,
        artifact_path: str,
        job: str,
        streamed: Literal[True] = True,
        action: Optional[Callable[[bytes], None]] = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> None: ...

    @cli.register_custom_action(
        cls_names="ProjectArtifactManager",
        required=("ref_name", "artifact_path", "job"),
+114 −1
Original line number Diff line number Diff line
from typing import Any, Callable, cast, Dict, Iterator, Optional, TYPE_CHECKING, Union
from typing import (
    Any,
    Callable,
    cast,
    Dict,
    Iterator,
    Literal,
    Optional,
    overload,
    TYPE_CHECKING,
    Union,
)

import requests

@@ -115,6 +126,39 @@ class ProjectJob(RefreshMixin, RESTObject):
        path = f"{self.manager.path}/{self.encoded_id}/artifacts"
        self.manager.gitlab.http_delete(path, **kwargs)

    @overload
    def artifacts(
        self,
        streamed: Literal[False] = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> bytes: ...

    @overload
    def artifacts(
        self,
        streamed: bool = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[True] = True,
        **kwargs: Any,
    ) -> Iterator[Any]: ...

    @overload
    def artifacts(
        self,
        streamed: Literal[True] = True,
        action: Optional[Callable[[bytes], None]] = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> None: ...

    @cli.register_custom_action(cls_names="ProjectJob")
    @exc.on_http_error(exc.GitlabGetError)
    def artifacts(
@@ -156,6 +200,42 @@ class ProjectJob(RefreshMixin, RESTObject):
            result, streamed, action, chunk_size, iterator=iterator
        )

    @overload
    def artifact(
        self,
        path: str,
        streamed: Literal[False] = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> bytes: ...

    @overload
    def artifact(
        self,
        path: str,
        streamed: bool = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[True] = True,
        **kwargs: Any,
    ) -> Iterator[Any]: ...

    @overload
    def artifact(
        self,
        path: str,
        streamed: Literal[True] = True,
        action: Optional[Callable[[bytes], None]] = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> None: ...

    @cli.register_custom_action(cls_names="ProjectJob")
    @exc.on_http_error(exc.GitlabGetError)
    def artifact(
@@ -199,6 +279,39 @@ class ProjectJob(RefreshMixin, RESTObject):
            result, streamed, action, chunk_size, iterator=iterator
        )

    @overload
    def trace(
        self,
        streamed: Literal[False] = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> bytes: ...

    @overload
    def trace(
        self,
        streamed: bool = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[True] = True,
        **kwargs: Any,
    ) -> Iterator[Any]: ...

    @overload
    def trace(
        self,
        streamed: Literal[True] = True,
        action: Optional[Callable[[bytes], None]] = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> None: ...

    @cli.register_custom_action(cls_names="ProjectJob")
    @exc.on_http_error(exc.GitlabGetError)
    def trace(
+44 −0
Original line number Diff line number Diff line
@@ -11,7 +11,9 @@ from typing import (
    Callable,
    cast,
    Iterator,
    Literal,
    Optional,
    overload,
    TYPE_CHECKING,
    Union,
)
@@ -122,6 +124,48 @@ class GenericPackageManager(RESTManager):
        attrs.update(server_data)
        return self._obj_cls(self, attrs=attrs)

    @overload
    def download(
        self,
        package_name: str,
        package_version: str,
        file_name: str,
        streamed: Literal[False] = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> bytes: ...

    @overload
    def download(
        self,
        package_name: str,
        package_version: str,
        file_name: str,
        streamed: bool = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[True] = True,
        **kwargs: Any,
    ) -> Iterator[Any]: ...

    @overload
    def download(
        self,
        package_name: str,
        package_version: str,
        file_name: str,
        streamed: Literal[True] = True,
        action: Optional[Callable[[bytes], None]] = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> None: ...

    @cli.register_custom_action(
        cls_names="GenericPackageManager",
        required=("package_name", "package_version", "file_name"),
+38 −0
Original line number Diff line number Diff line
@@ -11,7 +11,9 @@ from typing import (
    Dict,
    Iterator,
    List,
    Literal,
    Optional,
    overload,
    TYPE_CHECKING,
    Union,
)
@@ -487,6 +489,42 @@ class Project(
        path = f"/projects/{self.encoded_id}/restore"
        self.manager.gitlab.http_post(path, **kwargs)

    @overload
    def snapshot(
        self,
        wiki: bool = False,
        streamed: Literal[False] = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> bytes: ...

    @overload
    def snapshot(
        self,
        wiki: bool = False,
        streamed: bool = False,
        action: None = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[True] = True,
        **kwargs: Any,
    ) -> Iterator[Any]: ...

    @overload
    def snapshot(
        self,
        wiki: bool = False,
        streamed: Literal[True] = True,
        action: Optional[Callable[[bytes], None]] = None,
        chunk_size: int = 1024,
        *,
        iterator: Literal[False] = False,
        **kwargs: Any,
    ) -> None: ...

    @cli.register_custom_action(cls_names="Project", optional=("wiki",))
    @exc.on_http_error(exc.GitlabGetError)
    def snapshot(
Loading