Skip to content

Commit 872dd6d

Browse files
chore: add type-hints to gitlab/v4/objects/projects.py
Adding type-hints to gitlab/v4/objects/projects.py
1 parent dc53556 commit 872dd6d

File tree

2 files changed

+115
-50
lines changed

2 files changed

+115
-50
lines changed

.mypy.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[mypy]
2-
files = gitlab/*.py,gitlab/v4/cli.py
2+
files = gitlab/*.py,gitlab/v4/cli.py,gitlab/v4/objects/projects.py
33

44
# disallow_incomplete_defs: This flag reports an error whenever it encounters a
55
# partly annotated function definition.

gitlab/v4/objects/projects.py

+114-49
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
from gitlab import cli
1+
from typing import Any, Callable, cast, Dict, List, Optional, TYPE_CHECKING, Union
2+
3+
import requests
4+
5+
from gitlab import cli, client
26
from gitlab import exceptions as exc
37
from gitlab import types, utils
48
from gitlab.base import RequiredOptional, RESTManager, RESTObject
@@ -163,7 +167,7 @@ class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTO
163167

164168
@cli.register_custom_action("Project", ("forked_from_id",))
165169
@exc.on_http_error(exc.GitlabCreateError)
166-
def create_fork_relation(self, forked_from_id, **kwargs):
170+
def create_fork_relation(self, forked_from_id: int, **kwargs: Any) -> None:
167171
"""Create a forked from/to relation between existing projects.
168172
169173
Args:
@@ -179,7 +183,7 @@ def create_fork_relation(self, forked_from_id, **kwargs):
179183

180184
@cli.register_custom_action("Project")
181185
@exc.on_http_error(exc.GitlabDeleteError)
182-
def delete_fork_relation(self, **kwargs):
186+
def delete_fork_relation(self, **kwargs: Any) -> None:
183187
"""Delete a forked relation between existing projects.
184188
185189
Args:
@@ -194,7 +198,7 @@ def delete_fork_relation(self, **kwargs):
194198

195199
@cli.register_custom_action("Project")
196200
@exc.on_http_error(exc.GitlabGetError)
197-
def languages(self, **kwargs):
201+
def languages(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]:
198202
"""Get languages used in the project with percentage value.
199203
200204
Args:
@@ -209,7 +213,7 @@ def languages(self, **kwargs):
209213

210214
@cli.register_custom_action("Project")
211215
@exc.on_http_error(exc.GitlabCreateError)
212-
def star(self, **kwargs):
216+
def star(self, **kwargs: Any) -> None:
213217
"""Star a project.
214218
215219
Args:
@@ -221,11 +225,13 @@ def star(self, **kwargs):
221225
"""
222226
path = "/projects/%s/star" % self.get_id()
223227
server_data = self.manager.gitlab.http_post(path, **kwargs)
228+
if TYPE_CHECKING:
229+
assert isinstance(server_data, dict)
224230
self._update_attrs(server_data)
225231

226232
@cli.register_custom_action("Project")
227233
@exc.on_http_error(exc.GitlabDeleteError)
228-
def unstar(self, **kwargs):
234+
def unstar(self, **kwargs: Any) -> None:
229235
"""Unstar a project.
230236
231237
Args:
@@ -237,11 +243,13 @@ def unstar(self, **kwargs):
237243
"""
238244
path = "/projects/%s/unstar" % self.get_id()
239245
server_data = self.manager.gitlab.http_post(path, **kwargs)
246+
if TYPE_CHECKING:
247+
assert isinstance(server_data, dict)
240248
self._update_attrs(server_data)
241249

242250
@cli.register_custom_action("Project")
243251
@exc.on_http_error(exc.GitlabCreateError)
244-
def archive(self, **kwargs):
252+
def archive(self, **kwargs: Any) -> None:
245253
"""Archive a project.
246254
247255
Args:
@@ -253,11 +261,13 @@ def archive(self, **kwargs):
253261
"""
254262
path = "/projects/%s/archive" % self.get_id()
255263
server_data = self.manager.gitlab.http_post(path, **kwargs)
264+
if TYPE_CHECKING:
265+
assert isinstance(server_data, dict)
256266
self._update_attrs(server_data)
257267

258268
@cli.register_custom_action("Project")
259269
@exc.on_http_error(exc.GitlabDeleteError)
260-
def unarchive(self, **kwargs):
270+
def unarchive(self, **kwargs: Any) -> None:
261271
"""Unarchive a project.
262272
263273
Args:
@@ -269,13 +279,21 @@ def unarchive(self, **kwargs):
269279
"""
270280
path = "/projects/%s/unarchive" % self.get_id()
271281
server_data = self.manager.gitlab.http_post(path, **kwargs)
282+
if TYPE_CHECKING:
283+
assert isinstance(server_data, dict)
272284
self._update_attrs(server_data)
273285

274286
@cli.register_custom_action(
275287
"Project", ("group_id", "group_access"), ("expires_at",)
276288
)
277289
@exc.on_http_error(exc.GitlabCreateError)
278-
def share(self, group_id, group_access, expires_at=None, **kwargs):
290+
def share(
291+
self,
292+
group_id: int,
293+
group_access: int,
294+
expires_at: Optional[str] = None,
295+
**kwargs: Any
296+
) -> None:
279297
"""Share the project with a group.
280298
281299
Args:
@@ -297,7 +315,7 @@ def share(self, group_id, group_access, expires_at=None, **kwargs):
297315

298316
@cli.register_custom_action("Project", ("group_id",))
299317
@exc.on_http_error(exc.GitlabDeleteError)
300-
def unshare(self, group_id, **kwargs):
318+
def unshare(self, group_id: int, **kwargs: Any) -> None:
301319
"""Delete a shared project link within a group.
302320
303321
Args:
@@ -314,7 +332,13 @@ def unshare(self, group_id, **kwargs):
314332
# variables not supported in CLI
315333
@cli.register_custom_action("Project", ("ref", "token"))
316334
@exc.on_http_error(exc.GitlabCreateError)
317-
def trigger_pipeline(self, ref, token, variables=None, **kwargs):
335+
def trigger_pipeline(
336+
self,
337+
ref: str,
338+
token: str,
339+
variables: Optional[Dict[str, Any]] = None,
340+
**kwargs: Any
341+
) -> ProjectPipeline:
318342
"""Trigger a CI build.
319343
320344
See https://gitlab.com/help/ci/triggers/README.md#trigger-a-build
@@ -333,11 +357,13 @@ def trigger_pipeline(self, ref, token, variables=None, **kwargs):
333357
path = "/projects/%s/trigger/pipeline" % self.get_id()
334358
post_data = {"ref": ref, "token": token, "variables": variables}
335359
attrs = self.manager.gitlab.http_post(path, post_data=post_data, **kwargs)
360+
if TYPE_CHECKING:
361+
assert isinstance(attrs, dict)
336362
return ProjectPipeline(self.pipelines, attrs)
337363

338364
@cli.register_custom_action("Project")
339365
@exc.on_http_error(exc.GitlabHousekeepingError)
340-
def housekeeping(self, **kwargs):
366+
def housekeeping(self, **kwargs: Any) -> None:
341367
"""Start the housekeeping task.
342368
343369
Args:
@@ -354,7 +380,13 @@ def housekeeping(self, **kwargs):
354380
# see #56 - add file attachment features
355381
@cli.register_custom_action("Project", ("filename", "filepath"))
356382
@exc.on_http_error(exc.GitlabUploadError)
357-
def upload(self, filename, filedata=None, filepath=None, **kwargs):
383+
def upload(
384+
self,
385+
filename: str,
386+
filedata: Optional[bytes] = None,
387+
filepath: Optional[str] = None,
388+
**kwargs: Any
389+
) -> Dict[str, Any]:
358390
"""Upload the specified file into the project.
359391
360392
.. note::
@@ -394,13 +426,20 @@ def upload(self, filename, filedata=None, filepath=None, **kwargs):
394426
file_info = {"file": (filename, filedata)}
395427
data = self.manager.gitlab.http_post(url, files=file_info)
396428

429+
if TYPE_CHECKING:
430+
assert isinstance(data, dict)
397431
return {"alt": data["alt"], "url": data["url"], "markdown": data["markdown"]}
398432

399433
@cli.register_custom_action("Project", optional=("wiki",))
400434
@exc.on_http_error(exc.GitlabGetError)
401435
def snapshot(
402-
self, wiki=False, streamed=False, action=None, chunk_size=1024, **kwargs
403-
):
436+
self,
437+
wiki: bool = False,
438+
streamed: bool = False,
439+
action: Optional[Callable] = None,
440+
chunk_size: int = 1024,
441+
**kwargs: Any
442+
) -> Optional[bytes]:
404443
"""Return a snapshot of the repository.
405444
406445
Args:
@@ -424,11 +463,15 @@ def snapshot(
424463
result = self.manager.gitlab.http_get(
425464
path, streamed=streamed, raw=True, **kwargs
426465
)
466+
if TYPE_CHECKING:
467+
assert isinstance(result, requests.Response)
427468
return utils.response_content(result, streamed, action, chunk_size)
428469

429470
@cli.register_custom_action("Project", ("scope", "search"))
430471
@exc.on_http_error(exc.GitlabSearchError)
431-
def search(self, scope, search, **kwargs):
472+
def search(
473+
self, scope: str, search: str, **kwargs: Any
474+
) -> Union[client.GitlabList, List[Dict[str, Any]]]:
432475
"""Search the project resources matching the provided string.'
433476
434477
Args:
@@ -449,7 +492,7 @@ def search(self, scope, search, **kwargs):
449492

450493
@cli.register_custom_action("Project")
451494
@exc.on_http_error(exc.GitlabCreateError)
452-
def mirror_pull(self, **kwargs):
495+
def mirror_pull(self, **kwargs: Any) -> None:
453496
"""Start the pull mirroring process for the project.
454497
455498
Args:
@@ -464,7 +507,7 @@ def mirror_pull(self, **kwargs):
464507

465508
@cli.register_custom_action("Project", ("to_namespace",))
466509
@exc.on_http_error(exc.GitlabTransferProjectError)
467-
def transfer_project(self, to_namespace, **kwargs):
510+
def transfer_project(self, to_namespace: str, **kwargs: Any) -> None:
468511
"""Transfer a project to the given namespace ID
469512
470513
Args:
@@ -484,8 +527,14 @@ def transfer_project(self, to_namespace, **kwargs):
484527
@cli.register_custom_action("Project", ("ref_name", "job"), ("job_token",))
485528
@exc.on_http_error(exc.GitlabGetError)
486529
def artifacts(
487-
self, ref_name, job, streamed=False, action=None, chunk_size=1024, **kwargs
488-
):
530+
self,
531+
ref_name: str,
532+
job: str,
533+
streamed: bool = False,
534+
action: Optional[Callable] = None,
535+
chunk_size: int = 1024,
536+
**kwargs: Any
537+
) -> Optional[bytes]:
489538
"""Get the job artifacts archive from a specific tag or branch.
490539
491540
Args:
@@ -513,20 +562,22 @@ def artifacts(
513562
result = self.manager.gitlab.http_get(
514563
path, job=job, streamed=streamed, raw=True, **kwargs
515564
)
565+
if TYPE_CHECKING:
566+
assert isinstance(result, requests.Response)
516567
return utils.response_content(result, streamed, action, chunk_size)
517568

518569
@cli.register_custom_action("Project", ("ref_name", "artifact_path", "job"))
519570
@exc.on_http_error(exc.GitlabGetError)
520571
def artifact(
521572
self,
522-
ref_name,
523-
artifact_path,
524-
job,
525-
streamed=False,
526-
action=None,
527-
chunk_size=1024,
528-
**kwargs
529-
):
573+
ref_name: str,
574+
artifact_path: str,
575+
job: str,
576+
streamed: bool = False,
577+
action: Optional[Callable] = None,
578+
chunk_size: int = 1024,
579+
**kwargs: Any
580+
) -> Optional[bytes]:
530581
"""Download a single artifact file from a specific tag or branch from within the job’s artifacts archive.
531582
532583
Args:
@@ -558,6 +609,8 @@ def artifact(
558609
result = self.manager.gitlab.http_get(
559610
path, streamed=streamed, raw=True, **kwargs
560611
)
612+
if TYPE_CHECKING:
613+
assert isinstance(result, requests.Response)
561614
return utils.response_content(result, streamed, action, chunk_size)
562615

563616

@@ -725,16 +778,19 @@ class ProjectManager(CRUDMixin, RESTManager):
725778
)
726779
_types = {"avatar": types.ImageAttribute, "topic": types.ListAttribute}
727780

781+
def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> Project:
782+
return cast(Project, super().get(id=id, lazy=lazy, **kwargs))
783+
728784
def import_project(
729785
self,
730-
file,
731-
path,
732-
name=None,
733-
namespace=None,
734-
overwrite=False,
735-
override_params=None,
736-
**kwargs
737-
):
786+
file: str,
787+
path: str,
788+
name: Optional[str] = None,
789+
namespace: Optional[str] = None,
790+
overwrite: bool = False,
791+
override_params: Optional[Dict[str, Any]] = None,
792+
**kwargs: Any
793+
) -> Union[Dict[str, Any], requests.Response]:
738794
"""Import a project from an archive file.
739795
740796
Args:
@@ -769,15 +825,15 @@ def import_project(
769825

770826
def import_bitbucket_server(
771827
self,
772-
bitbucket_server_url,
773-
bitbucket_server_username,
774-
personal_access_token,
775-
bitbucket_server_project,
776-
bitbucket_server_repo,
777-
new_name=None,
778-
target_namespace=None,
779-
**kwargs
780-
):
828+
bitbucket_server_url: str,
829+
bitbucket_server_username: str,
830+
personal_access_token: str,
831+
bitbucket_server_project: str,
832+
bitbucket_server_repo: str,
833+
new_name: Optional[str] = None,
834+
target_namespace: Optional[str] = None,
835+
**kwargs: Any
836+
) -> Union[Dict[str, Any], requests.Response]:
781837
"""Import a project from BitBucket Server to Gitlab (schedule the import)
782838
783839
This method will return when an import operation has been safely queued,
@@ -856,8 +912,13 @@ def import_bitbucket_server(
856912
return result
857913

858914
def import_github(
859-
self, personal_access_token, repo_id, target_namespace, new_name=None, **kwargs
860-
):
915+
self,
916+
personal_access_token: str,
917+
repo_id: int,
918+
target_namespace: str,
919+
new_name: Optional[str] = None,
920+
**kwargs: Any
921+
) -> Union[Dict[str, Any], requests.Response]:
861922
"""Import a project from Github to Gitlab (schedule the import)
862923
863924
This method will return when an import operation has been safely queued,
@@ -944,7 +1005,9 @@ class ProjectForkManager(CreateMixin, ListMixin, RESTManager):
9441005
)
9451006
_create_attrs = RequiredOptional(optional=("namespace",))
9461007

947-
def create(self, data, **kwargs):
1008+
def create(
1009+
self, data: Optional[Dict[str, Any]] = None, **kwargs: Any
1010+
) -> ProjectFork:
9481011
"""Creates a new object.
9491012
9501013
Args:
@@ -960,8 +1023,10 @@ def create(self, data, **kwargs):
9601023
RESTObject: A new instance of the managed object class build with
9611024
the data sent by the server
9621025
"""
1026+
if TYPE_CHECKING:
1027+
assert self.path is not None
9631028
path = self.path[:-1] # drop the 's'
964-
return CreateMixin.create(self, data, path=path, **kwargs)
1029+
return cast(ProjectFork, CreateMixin.create(self, data, path=path, **kwargs))
9651030

9661031

9671032
class ProjectRemoteMirror(SaveMixin, RESTObject):

0 commit comments

Comments
 (0)