Skip to content

Commit 4f9807f

Browse files
committed
feat(downloads): allow streaming downloads access to response iterator
Allow access to the underlying response iterator when downloading in streaming mode by specifying action="iterator" Update type annotations to support this change
1 parent 5370979 commit 4f9807f

File tree

10 files changed

+106
-38
lines changed

10 files changed

+106
-38
lines changed

gitlab/mixins.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
Any,
2121
Callable,
2222
Dict,
23+
Iterator,
2324
List,
25+
Literal,
2426
Optional,
2527
Tuple,
2628
Type,
@@ -657,10 +659,10 @@ class DownloadMixin(_RestObjectBase):
657659
def download(
658660
self,
659661
streamed: bool = False,
660-
action: Optional[Callable] = None,
662+
action: Optional[Union[Callable, Literal["iterator"]]] = None,
661663
chunk_size: int = 1024,
662664
**kwargs: Any,
663-
) -> Optional[bytes]:
665+
) -> Optional[Union[bytes, Iterator[Any]]]:
664666
"""Download the archive of a resource export.
665667
666668
Args:

gitlab/utils.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import traceback
2020
import urllib.parse
2121
import warnings
22-
from typing import Any, Callable, Dict, Optional, Type, Union
22+
from typing import Any, Callable, Dict, Iterator, Literal, Optional, Type, Union
2323

2424
import requests
2525

@@ -32,15 +32,18 @@ def __call__(self, chunk: Any) -> None:
3232
def response_content(
3333
response: requests.Response,
3434
streamed: bool,
35-
action: Optional[Callable],
35+
action: Optional[Union[Callable, Literal["iterator"]]],
3636
chunk_size: int,
37-
) -> Optional[bytes]:
37+
) -> Optional[Union[bytes, Iterator[Any]]]:
3838
if streamed is False:
3939
return response.content
4040

4141
if action is None:
4242
action = _StdoutStream()
4343

44+
if action == "iterator":
45+
return response.iter_content(chunk_size=chunk_size)
46+
4447
for chunk in response.iter_content(chunk_size=chunk_size):
4548
if chunk:
4649
action(chunk)

gitlab/v4/cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import argparse
2020
import operator
2121
import sys
22-
from typing import Any, Dict, List, Optional, Type, TYPE_CHECKING, Union
22+
from typing import Any, Dict, Iterator, List, Optional, Type, TYPE_CHECKING, Union
2323

2424
import gitlab
2525
import gitlab.base
@@ -123,6 +123,7 @@ def do_project_export_download(self) -> None:
123123
data = export_status.download()
124124
if TYPE_CHECKING:
125125
assert data is not None
126+
assert not isinstance(data, Iterator)
126127
sys.stdout.buffer.write(data)
127128

128129
except Exception as e:

gitlab/v4/objects/artifacts.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
GitLab API:
33
https://docs.gitlab.com/ee/api/job_artifacts.html
44
"""
5-
from typing import Any, Callable, Optional, TYPE_CHECKING
5+
from typing import Any, Callable, Iterator, Literal, Optional, TYPE_CHECKING, Union
66

77
import requests
88

@@ -32,7 +32,7 @@ def __call__(
3232
self,
3333
*args: Any,
3434
**kwargs: Any,
35-
) -> Optional[bytes]:
35+
) -> Optional[Union[bytes, Iterator[Any]]]:
3636
utils.warn(
3737
message=(
3838
"The project.artifacts() method is deprecated and will be removed in a "
@@ -71,10 +71,10 @@ def download(
7171
ref_name: str,
7272
job: str,
7373
streamed: bool = False,
74-
action: Optional[Callable] = None,
74+
action: Optional[Union[Callable, Literal["iterator"]]] = None,
7575
chunk_size: int = 1024,
7676
**kwargs: Any,
77-
) -> Optional[bytes]:
77+
) -> Optional[Union[bytes, Iterator[Any]]]:
7878
"""Get the job artifacts archive from a specific tag or branch.
7979
8080
Args:
@@ -86,7 +86,8 @@ def download(
8686
`chunk_size` and each chunk is passed to `action` for
8787
treatment
8888
action: Callable responsible of dealing with chunk of
89-
data
89+
data. May also be the string "iterator" to directly return
90+
the response iterator
9091
chunk_size: Size of each chunk
9192
**kwargs: Extra options to send to the server (e.g. sudo)
9293
@@ -115,10 +116,10 @@ def raw(
115116
artifact_path: str,
116117
job: str,
117118
streamed: bool = False,
118-
action: Optional[Callable] = None,
119+
action: Optional[Union[Callable, Literal["iterator"]]] = None,
119120
chunk_size: int = 1024,
120121
**kwargs: Any,
121-
) -> Optional[bytes]:
122+
) -> Optional[Union[bytes, Iterator[Any]]]:
122123
"""Download a single artifact file from a specific tag or branch from
123124
within the job's artifacts archive.
124125

gitlab/v4/objects/files.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
import base64
2-
from typing import Any, Callable, cast, Dict, List, Optional, TYPE_CHECKING
2+
from typing import (
3+
Any,
4+
Callable,
5+
cast,
6+
Dict,
7+
Iterator,
8+
List,
9+
Literal,
10+
Optional,
11+
TYPE_CHECKING,
12+
Union,
13+
)
314

415
import requests
516

@@ -217,10 +228,10 @@ def raw(
217228
file_path: str,
218229
ref: str,
219230
streamed: bool = False,
220-
action: Optional[Callable[..., Any]] = None,
231+
action: Optional[Union[Callable[..., Any], Literal["iterator"]]] = None,
221232
chunk_size: int = 1024,
222233
**kwargs: Any,
223-
) -> Optional[bytes]:
234+
) -> Optional[Union[bytes, Iterator[Any]]]:
224235
"""Return the content of a file for a commit.
225236
226237
Args:

gitlab/v4/objects/jobs.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
from typing import Any, Callable, cast, Dict, Optional, TYPE_CHECKING, Union
1+
from typing import (
2+
Any,
3+
Callable,
4+
cast,
5+
Dict,
6+
Iterator,
7+
Literal,
8+
Optional,
9+
TYPE_CHECKING,
10+
Union,
11+
)
212

313
import requests
414

@@ -116,10 +126,10 @@ def delete_artifacts(self, **kwargs: Any) -> None:
116126
def artifacts(
117127
self,
118128
streamed: bool = False,
119-
action: Optional[Callable[..., Any]] = None,
129+
action: Optional[Union[Callable[..., Any], Literal["iterator"]]] = None,
120130
chunk_size: int = 1024,
121131
**kwargs: Any,
122-
) -> Optional[bytes]:
132+
) -> Optional[Union[bytes, Iterator[Any]]]:
123133
"""Get the job artifacts.
124134
125135
Args:
@@ -152,10 +162,10 @@ def artifact(
152162
self,
153163
path: str,
154164
streamed: bool = False,
155-
action: Optional[Callable[..., Any]] = None,
165+
action: Optional[Union[Callable[..., Any], Literal["iterator"]]] = None,
156166
chunk_size: int = 1024,
157167
**kwargs: Any,
158-
) -> Optional[bytes]:
168+
) -> Optional[Union[bytes, Iterator[Any]]]:
159169
"""Get a single artifact file from within the job's artifacts archive.
160170
161171
Args:

gitlab/v4/objects/packages.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,16 @@
55
"""
66

77
from pathlib import Path
8-
from typing import Any, Callable, cast, Optional, TYPE_CHECKING, Union
8+
from typing import (
9+
Any,
10+
Callable,
11+
cast,
12+
Iterator,
13+
Literal,
14+
Optional,
15+
TYPE_CHECKING,
16+
Union,
17+
)
918

1019
import requests
1120

@@ -103,10 +112,10 @@ def download(
103112
package_version: str,
104113
file_name: str,
105114
streamed: bool = False,
106-
action: Optional[Callable] = None,
115+
action: Optional[Union[Callable, Literal["iterator"]]] = None,
107116
chunk_size: int = 1024,
108117
**kwargs: Any,
109-
) -> Optional[bytes]:
118+
) -> Optional[Union[bytes, Iterator[Any]]]:
110119
"""Download a generic package.
111120
112121
Args:

gitlab/v4/objects/projects.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
from typing import Any, Callable, cast, Dict, List, Optional, TYPE_CHECKING, Union
1+
from typing import (
2+
Any,
3+
Callable,
4+
cast,
5+
Dict,
6+
Iterator,
7+
List,
8+
Literal,
9+
Optional,
10+
TYPE_CHECKING,
11+
Union,
12+
)
213

314
import requests
415

@@ -457,10 +468,10 @@ def snapshot(
457468
self,
458469
wiki: bool = False,
459470
streamed: bool = False,
460-
action: Optional[Callable] = None,
471+
action: Optional[Union[Callable, Literal["iterator"]]] = None,
461472
chunk_size: int = 1024,
462473
**kwargs: Any,
463-
) -> Optional[bytes]:
474+
) -> Optional[Union[bytes, Iterator[Any]]]:
464475
"""Return a snapshot of the repository.
465476
466477
Args:
@@ -562,7 +573,7 @@ def artifact(
562573
self,
563574
*args: Any,
564575
**kwargs: Any,
565-
) -> Optional[bytes]:
576+
) -> Optional[Union[bytes, Iterator[Any]]]:
566577
utils.warn(
567578
message=(
568579
"The project.artifact() method is deprecated and will be "

gitlab/v4/objects/repositories.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,17 @@
33
44
Currently this module only contains repository-related methods for projects.
55
"""
6-
from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING, Union
6+
from typing import (
7+
Any,
8+
Callable,
9+
Dict,
10+
Iterator,
11+
List,
12+
Literal,
13+
Optional,
14+
TYPE_CHECKING,
15+
Union,
16+
)
717

818
import requests
919

@@ -107,10 +117,10 @@ def repository_raw_blob(
107117
self,
108118
sha: str,
109119
streamed: bool = False,
110-
action: Optional[Callable[..., Any]] = None,
120+
action: Optional[Union[Callable[..., Any], Literal["iterator"]]] = None,
111121
chunk_size: int = 1024,
112122
**kwargs: Any,
113-
) -> Optional[bytes]:
123+
) -> Optional[Union[bytes, Iterator[Any]]]:
114124
"""Return the raw file contents for a blob.
115125
116126
Args:
@@ -192,11 +202,11 @@ def repository_archive(
192202
self,
193203
sha: str = None,
194204
streamed: bool = False,
195-
action: Optional[Callable[..., Any]] = None,
205+
action: Optional[Union[Callable[..., Any], Literal["iterator"]]] = None,
196206
chunk_size: int = 1024,
197207
format: Optional[str] = None,
198208
**kwargs: Any,
199-
) -> Optional[bytes]:
209+
) -> Optional[Union[bytes, Iterator[Any]]]:
200210
"""Return an archive of the repository.
201211
202212
Args:

gitlab/v4/objects/snippets.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
from typing import Any, Callable, cast, List, Optional, TYPE_CHECKING, Union
1+
from typing import (
2+
Any,
3+
Callable,
4+
cast,
5+
Iterator,
6+
List,
7+
Literal,
8+
Optional,
9+
TYPE_CHECKING,
10+
Union,
11+
)
212

313
import requests
414

@@ -28,10 +38,10 @@ class Snippet(UserAgentDetailMixin, SaveMixin, ObjectDeleteMixin, RESTObject):
2838
def content(
2939
self,
3040
streamed: bool = False,
31-
action: Optional[Callable[..., Any]] = None,
41+
action: Optional[Union[Callable[..., Any], Literal["iterator"]]] = None,
3242
chunk_size: int = 1024,
3343
**kwargs: Any,
34-
) -> Optional[bytes]:
44+
) -> Optional[Union[bytes, Iterator[Any]]]:
3545
"""Return the content of a snippet.
3646
3747
Args:
@@ -102,10 +112,10 @@ class ProjectSnippet(UserAgentDetailMixin, SaveMixin, ObjectDeleteMixin, RESTObj
102112
def content(
103113
self,
104114
streamed: bool = False,
105-
action: Optional[Callable[..., Any]] = None,
115+
action: Optional[Union[Callable[..., Any], Literal["iterator"]]] = None,
106116
chunk_size: int = 1024,
107117
**kwargs: Any,
108-
) -> Optional[bytes]:
118+
) -> Optional[Union[bytes, Iterator[Any]]]:
109119
"""Return the content of a snippet.
110120
111121
Args:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy