| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 0f2a602 commit b644721
13 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -274,6 +274,19 @@ You can also directly stream the output into a file, and unzip it afterwards:: | |||
| 274 | 274 | subprocess.run(["unzip", "-bo", zipfn]) | |
| 275 | 275 | os.unlink(zipfn) | |
| 276 | 276 | ||
| 277 | + Or, you can also use the underlying response iterator directly:: | ||
| 278 | + | ||
| 279 | + artifact_bytes_iterator = build_or_job.artifacts(iterator=True) | ||
| 280 | + | ||
| 281 | + This can be used with frameworks that expect an iterator (such as FastAPI/Starlette's | ||
| 282 | + ``StreamingResponse``) to forward a download from GitLab without having to download | ||
| 283 | + the entire content server-side first:: | ||
| 284 | + | ||
| 285 | + @app.get("/download_artifact") | ||
| 286 | + def download_artifact(): | ||
| 287 | + artifact_bytes_iterator = build_or_job.artifacts(iterator=True) | ||
| 288 | + return StreamingResponse(artifact_bytes_iterator, media_type="application/zip") | ||
| 289 | + | ||
| 277 | 290 | Delete all artifacts of a project that can be deleted:: | |
| 278 | 291 | ||
| 279 | 292 | project.artifacts.delete() | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -20,6 +20,7 @@ | |||
| 20 | 20 | Any, | |
| 21 | 21 | Callable, | |
| 22 | 22 | Dict, | |
| 23 | + Iterator, | ||
| 23 | 24 | List, | |
| 24 | 25 | Optional, | |
| 25 | 26 | Tuple, | |
@@ -612,16 +613,19 @@ class DownloadMixin(_RestObjectBase): | |||
| 612 | 613 | def download( | |
| 613 | 614 | self, | |
| 614 | 615 | streamed: bool = False, | |
| 616 | + iterator: bool = False, | ||
| 615 | 617 | action: Optional[Callable] = None, | |
| 616 | 618 | chunk_size: int = 1024, | |
| 617 | 619 | **kwargs: Any, | |
| 618 | - ) -> Optional[bytes]: | ||
| 620 | + ) -> Optional[Union[bytes, Iterator[Any]]]: | ||
| 619 | 621 | """Download the archive of a resource export. | |
| 620 | 622 | ||
| 621 | 623 | Args: | |
| 622 | 624 | streamed: If True the data will be processed by chunks of | |
| 623 | 625 | `chunk_size` and each chunk is passed to `action` for | |
| 624 | 626 | treatment | |
| 627 | + iterator: If True directly return the underlying response | ||
| 628 | + iterator | ||
| 625 | 629 | action: Callable responsible of dealing with chunk of | |
| 626 | 630 | data | |
| 627 | 631 | chunk_size: Size of each chunk | |
@@ -640,7 +644,7 @@ def download( | |||
| 640 | 644 | ) | |
| 641 | 645 | if TYPE_CHECKING: | |
| 642 | 646 | assert isinstance(result, requests.Response) | |
| 643 | - return utils.response_content(result, streamed, action, chunk_size) | ||
| 647 | + return utils.response_content(result, streamed, iterator, action, chunk_size) | ||
| 644 | 648 | ||
| 645 | 649 | ||
| 646 | 650 | class SubscribableMixin(_RestObjectBase): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,7 +19,7 @@ | |||
| 19 | 19 | import traceback | |
| 20 | 20 | import urllib.parse | |
| 21 | 21 | import warnings | |
| 22 | - from typing import Any, Callable, Dict, Optional, Tuple, Type, Union | ||
| 22 | + from typing import Any, Callable, Dict, Iterator, Optional, Tuple, Type, Union | ||
| 23 | 23 | ||
| 24 | 24 | import requests | |
| 25 | 25 | ||
@@ -34,9 +34,13 @@ def __call__(self, chunk: Any) -> None: | |||
| 34 | 34 | def response_content( | |
| 35 | 35 | response: requests.Response, | |
| 36 | 36 | streamed: bool, | |
| 37 | + iterator: bool, | ||
| 37 | 38 | action: Optional[Callable], | |
| 38 | 39 | chunk_size: int, | |
| 39 | - ) -> Optional[bytes]: | ||
| 40 | + ) -> Optional[Union[bytes, Iterator[Any]]]: | ||
| 41 | + if iterator: | ||
| 42 | + return response.iter_content(chunk_size=chunk_size) | ||
| 43 | + | ||
| 40 | 44 | if streamed is False: | |
| 41 | 45 | return response.content | |
| 42 | 46 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -127,6 +127,7 @@ def do_project_export_download(self) -> None: | |||
| 127 | 127 | data = export_status.download() | |
| 128 | 128 | if TYPE_CHECKING: | |
| 129 | 129 | assert data is not None | |
| 130 | + assert isinstance(data, bytes) | ||
| 130 | 131 | sys.stdout.buffer.write(data) | |
| 131 | 132 | ||
| 132 | 133 | except Exception as e: # pragma: no cover, cli.die is unit-tested | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,7 +2,7 @@ | |||
| 2 | 2 | GitLab API: | |
| 3 | 3 | https://docs.gitlab.com/ee/api/job_artifacts.html | |
| 4 | 4 | """ | |
| 5 | - from typing import Any, Callable, Optional, TYPE_CHECKING | ||
| 5 | + from typing import Any, Callable, Iterator, Optional, TYPE_CHECKING, Union | ||
| 6 | 6 | ||
| 7 | 7 | import requests | |
| 8 | 8 | ||
@@ -40,10 +40,14 @@ def __call__( | |||
| 40 | 40 | ), | |
| 41 | 41 | category=DeprecationWarning, | |
| 42 | 42 | ) | |
| 43 | - return self.download( | ||
| 43 | + data = self.download( | ||
| 44 | 44 | *args, | |
| 45 | 45 | **kwargs, | |
| 46 | 46 | ) | |
| 47 | + if TYPE_CHECKING: | ||
| 48 | + assert data is not None | ||
| 49 | + assert isinstance(data, bytes) | ||
| 50 | + return data | ||
| 47 | 51 | ||
| 48 | 52 | @exc.on_http_error(exc.GitlabDeleteError) | |
| 49 | 53 | def delete(self, **kwargs: Any) -> None: | |
@@ -71,10 +75,11 @@ def download( | |||
| 71 | 75 | ref_name: str, | |
| 72 | 76 | job: str, | |
| 73 | 77 | streamed: bool = False, | |
| 78 | + iterator: bool = False, | ||
| 74 | 79 | action: Optional[Callable] = None, | |
| 75 | 80 | chunk_size: int = 1024, | |
| 76 | 81 | **kwargs: Any, | |
| 77 | - ) -> Optional[bytes]: | ||
| 82 | + ) -> Optional[Union[bytes, Iterator[Any]]]: | ||
| 78 | 83 | """Get the job artifacts archive from a specific tag or branch. | |
| 79 | 84 | ||
| 80 | 85 | Args: | |
@@ -85,6 +90,8 @@ def download( | |||
| 85 | 90 | streamed: If True the data will be processed by chunks of | |
| 86 | 91 | `chunk_size` and each chunk is passed to `action` for | |
| 87 | 92 | treatment | |
| 93 | + iterator: If True directly return the underlying response | ||
| 94 | + iterator | ||
| 88 | 95 | action: Callable responsible of dealing with chunk of | |
| 89 | 96 | data | |
| 90 | 97 | chunk_size: Size of each chunk | |
@@ -103,7 +110,7 @@ def download( | |||
| 103 | 110 | ) | |
| 104 | 111 | if TYPE_CHECKING: | |
| 105 | 112 | assert isinstance(result, requests.Response) | |
| 106 | - return utils.response_content(result, streamed, action, chunk_size) | ||
| 113 | + return utils.response_content(result, streamed, iterator, action, chunk_size) | ||
| 107 | 114 | ||
| 108 | 115 | @cli.register_custom_action( | |
| 109 | 116 | "ProjectArtifactManager", ("ref_name", "artifact_path", "job") | |
@@ -115,10 +122,11 @@ def raw( | |||
| 115 | 122 | artifact_path: str, | |
| 116 | 123 | job: str, | |
| 117 | 124 | streamed: bool = False, | |
| 125 | + iterator: bool = False, | ||
| 118 | 126 | action: Optional[Callable] = None, | |
| 119 | 127 | chunk_size: int = 1024, | |
| 120 | 128 | **kwargs: Any, | |
| 121 | - ) -> Optional[bytes]: | ||
| 129 | + ) -> Optional[Union[bytes, Iterator[Any]]]: | ||
| 122 | 130 | """Download a single artifact file from a specific tag or branch from | |
| 123 | 131 | within the job's artifacts archive. | |
| 124 | 132 | ||
@@ -130,6 +138,8 @@ def raw( | |||
| 130 | 138 | streamed: If True the data will be processed by chunks of | |
| 131 | 139 | `chunk_size` and each chunk is passed to `action` for | |
| 132 | 140 | treatment | |
| 141 | + iterator: If True directly return the underlying response | ||
| 142 | + iterator | ||
| 133 | 143 | action: Callable responsible of dealing with chunk of | |
| 134 | 144 | data | |
| 135 | 145 | chunk_size: Size of each chunk | |
@@ -148,4 +158,4 @@ def raw( | |||
| 148 | 158 | ) | |
| 149 | 159 | if TYPE_CHECKING: | |
| 150 | 160 | assert isinstance(result, requests.Response) | |
| 151 | - return utils.response_content(result, streamed, action, chunk_size) | ||
| 161 | + return utils.response_content(result, streamed, iterator, action, chunk_size) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,15 @@ | |||
| 1 | 1 | 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 | + Optional, | ||
| 10 | + TYPE_CHECKING, | ||
| 11 | + Union, | ||
| 12 | + ) | ||
| 3 | 13 | ||
| 4 | 14 | import requests | |
| 5 | 15 | ||
@@ -220,10 +230,11 @@ def raw( | |||
| 220 | 230 | file_path: str, | |
| 221 | 231 | ref: str, | |
| 222 | 232 | streamed: bool = False, | |
| 233 | + iterator: bool = False, | ||
| 223 | 234 | action: Optional[Callable[..., Any]] = None, | |
| 224 | 235 | chunk_size: int = 1024, | |
| 225 | 236 | **kwargs: Any, | |
| 226 | - ) -> Optional[bytes]: | ||
| 237 | + ) -> Optional[Union[bytes, Iterator[Any]]]: | ||
| 227 | 238 | """Return the content of a file for a commit. | |
| 228 | 239 | ||
| 229 | 240 | Args: | |
@@ -232,6 +243,8 @@ def raw( | |||
| 232 | 243 | streamed: If True the data will be processed by chunks of | |
| 233 | 244 | `chunk_size` and each chunk is passed to `action` for | |
| 234 | 245 | treatment | |
| 246 | + iterator: If True directly return the underlying response | ||
| 247 | + iterator | ||
| 235 | 248 | action: Callable responsible of dealing with chunk of | |
| 236 | 249 | data | |
| 237 | 250 | chunk_size: Size of each chunk | |
@@ -252,7 +265,7 @@ def raw( | |||
| 252 | 265 | ) | |
| 253 | 266 | if TYPE_CHECKING: | |
| 254 | 267 | assert isinstance(result, requests.Response) | |
| 255 | - return utils.response_content(result, streamed, action, chunk_size) | ||
| 268 | + return utils.response_content(result, streamed, iterator, action, chunk_size) | ||
| 256 | 269 | ||
| 257 | 270 | @cli.register_custom_action("ProjectFileManager", ("file_path", "ref")) | |
| 258 | 271 | @exc.on_http_error(exc.GitlabListError) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,4 @@ | |||
| 1 | - from typing import Any, Callable, cast, Dict, Optional, TYPE_CHECKING, Union | ||
| 1 | + from typing import Any, Callable, cast, Dict, Iterator, Optional, TYPE_CHECKING, Union | ||
| 2 | 2 | ||
| 3 | 3 | import requests | |
| 4 | 4 | ||
@@ -116,16 +116,19 @@ def delete_artifacts(self, **kwargs: Any) -> None: | |||
| 116 | 116 | def artifacts( | |
| 117 | 117 | self, | |
| 118 | 118 | streamed: bool = False, | |
| 119 | + iterator: bool = False, | ||
| 119 | 120 | action: Optional[Callable[..., Any]] = None, | |
| 120 | 121 | chunk_size: int = 1024, | |
| 121 | 122 | **kwargs: Any, | |
| 122 | - ) -> Optional[bytes]: | ||
| 123 | + ) -> Optional[Union[bytes, Iterator[Any]]]: | ||
| 123 | 124 | """Get the job artifacts. | |
| 124 | 125 | ||
| 125 | 126 | Args: | |
| 126 | 127 | streamed: If True the data will be processed by chunks of | |
| 127 | 128 | `chunk_size` and each chunk is passed to `action` for | |
| 128 | 129 | treatment | |
| 130 | + iterator: If True directly return the underlying response | ||
| 131 | + iterator | ||
| 129 | 132 | action: Callable responsible of dealing with chunk of | |
| 130 | 133 | data | |
| 131 | 134 | chunk_size: Size of each chunk | |
@@ -144,25 +147,28 @@ def artifacts( | |||
| 144 | 147 | ) | |
| 145 | 148 | if TYPE_CHECKING: | |
| 146 | 149 | assert isinstance(result, requests.Response) | |
| 147 | - return utils.response_content(result, streamed, action, chunk_size) | ||
| 150 | + return utils.response_content(result, streamed, iterator, action, chunk_size) | ||
| 148 | 151 | ||
| 149 | 152 | @cli.register_custom_action("ProjectJob") | |
| 150 | 153 | @exc.on_http_error(exc.GitlabGetError) | |
| 151 | 154 | def artifact( | |
| 152 | 155 | self, | |
| 153 | 156 | path: str, | |
| 154 | 157 | streamed: bool = False, | |
| 158 | + iterator: bool = False, | ||
| 155 | 159 | action: Optional[Callable[..., Any]] = None, | |
| 156 | 160 | chunk_size: int = 1024, | |
| 157 | 161 | **kwargs: Any, | |
| 158 | - ) -> Optional[bytes]: | ||
| 162 | + ) -> Optional[Union[bytes, Iterator[Any]]]: | ||
| 159 | 163 | """Get a single artifact file from within the job's artifacts archive. | |
| 160 | 164 | ||
| 161 | 165 | Args: | |
| 162 | 166 | path: Path of the artifact | |
| 163 | 167 | streamed: If True the data will be processed by chunks of | |
| 164 | 168 | `chunk_size` and each chunk is passed to `action` for | |
| 165 | 169 | treatment | |
| 170 | + iterator: If True directly return the underlying response | ||
| 171 | + iterator | ||
| 166 | 172 | action: Callable responsible of dealing with chunk of | |
| 167 | 173 | data | |
| 168 | 174 | chunk_size: Size of each chunk | |
@@ -181,13 +187,14 @@ def artifact( | |||
| 181 | 187 | ) | |
| 182 | 188 | if TYPE_CHECKING: | |
| 183 | 189 | assert isinstance(result, requests.Response) | |
| 184 | - return utils.response_content(result, streamed, action, chunk_size) | ||
| 190 | + return utils.response_content(result, streamed, iterator, action, chunk_size) | ||
| 185 | 191 | ||
| 186 | 192 | @cli.register_custom_action("ProjectJob") | |
| 187 | 193 | @exc.on_http_error(exc.GitlabGetError) | |
| 188 | 194 | def trace( | |
| 189 | 195 | self, | |
| 190 | 196 | streamed: bool = False, | |
| 197 | + iterator: bool = False, | ||
| 191 | 198 | action: Optional[Callable[..., Any]] = None, | |
| 192 | 199 | chunk_size: int = 1024, | |
| 193 | 200 | **kwargs: Any, | |
@@ -198,6 +205,8 @@ def trace( | |||
| 198 | 205 | streamed: If True the data will be processed by chunks of | |
| 199 | 206 | `chunk_size` and each chunk is passed to `action` for | |
| 200 | 207 | treatment | |
| 208 | + iterator: If True directly return the underlying response | ||
| 209 | + iterator | ||
| 201 | 210 | action: Callable responsible of dealing with chunk of | |
| 202 | 211 | data | |
| 203 | 212 | chunk_size: Size of each chunk | |
@@ -216,7 +225,9 @@ def trace( | |||
| 216 | 225 | ) | |
| 217 | 226 | if TYPE_CHECKING: | |
| 218 | 227 | assert isinstance(result, requests.Response) | |
| 219 | - return_value = utils.response_content(result, streamed, action, chunk_size) | ||
| 228 | + return_value = utils.response_content( | ||
| 229 | + result, streamed, iterator, action, chunk_size | ||
| 230 | + ) | ||
| 220 | 231 | if TYPE_CHECKING: | |
| 221 | 232 | assert isinstance(return_value, dict) | |
| 222 | 233 | return return_value | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,7 +5,7 @@ | |||
| 5 | 5 | """ | |
| 6 | 6 | ||
| 7 | 7 | from pathlib import Path | |
| 8 | - from typing import Any, Callable, cast, Optional, TYPE_CHECKING, Union | ||
| 8 | + from typing import Any, Callable, cast, Iterator, Optional, TYPE_CHECKING, Union | ||
| 9 | 9 | ||
| 10 | 10 | import requests | |
| 11 | 11 | ||
@@ -103,10 +103,11 @@ def download( | |||
| 103 | 103 | package_version: str, | |
| 104 | 104 | file_name: str, | |
| 105 | 105 | streamed: bool = False, | |
| 106 | + iterator: bool = False, | ||
| 106 | 107 | action: Optional[Callable] = None, | |
| 107 | 108 | chunk_size: int = 1024, | |
| 108 | 109 | **kwargs: Any, | |
| 109 | - ) -> Optional[bytes]: | ||
| 110 | + ) -> Optional[Union[bytes, Iterator[Any]]]: | ||
| 110 | 111 | """Download a generic package. | |
| 111 | 112 | ||
| 112 | 113 | Args: | |
@@ -116,6 +117,8 @@ def download( | |||
| 116 | 117 | streamed: If True the data will be processed by chunks of | |
| 117 | 118 | `chunk_size` and each chunk is passed to `action` for | |
| 118 | 119 | treatment | |
| 120 | + iterator: If True directly return the underlying response | ||
| 121 | + iterator | ||
| 119 | 122 | action: Callable responsible of dealing with chunk of | |
| 120 | 123 | data | |
| 121 | 124 | chunk_size: Size of each chunk | |
@@ -132,7 +135,7 @@ def download( | |||
| 132 | 135 | result = self.gitlab.http_get(path, streamed=streamed, raw=True, **kwargs) | |
| 133 | 136 | if TYPE_CHECKING: | |
| 134 | 137 | assert isinstance(result, requests.Response) | |
| 135 | - return utils.response_content(result, streamed, action, chunk_size) | ||
| 138 | + return utils.response_content(result, streamed, iterator, action, chunk_size) | ||
| 136 | 139 | ||
| 137 | 140 | ||
| 138 | 141 | class GroupPackage(RESTObject): | |
| Back | FazBrowse Home | New Git URL |
0 commit comments