python-gitlab 5.5.0__py3-none-any.whl → 6.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. gitlab/__init__.py +0 -1
  2. gitlab/_backends/protocol.py +9 -13
  3. gitlab/_backends/requests_backend.py +12 -12
  4. gitlab/_version.py +1 -1
  5. gitlab/base.py +48 -48
  6. gitlab/cli.py +14 -24
  7. gitlab/client.py +114 -140
  8. gitlab/config.py +16 -17
  9. gitlab/exceptions.py +7 -5
  10. gitlab/mixins.py +154 -238
  11. gitlab/types.py +13 -14
  12. gitlab/utils.py +32 -43
  13. gitlab/v4/cli.py +50 -53
  14. gitlab/v4/objects/__init__.py +1 -0
  15. gitlab/v4/objects/access_requests.py +11 -3
  16. gitlab/v4/objects/appearance.py +12 -14
  17. gitlab/v4/objects/applications.py +5 -6
  18. gitlab/v4/objects/artifacts.py +10 -17
  19. gitlab/v4/objects/audit_events.py +4 -19
  20. gitlab/v4/objects/award_emojis.py +13 -57
  21. gitlab/v4/objects/badges.py +4 -19
  22. gitlab/v4/objects/boards.py +7 -27
  23. gitlab/v4/objects/branches.py +3 -15
  24. gitlab/v4/objects/broadcast_messages.py +3 -13
  25. gitlab/v4/objects/bulk_imports.py +6 -14
  26. gitlab/v4/objects/ci_lint.py +7 -13
  27. gitlab/v4/objects/cluster_agents.py +3 -13
  28. gitlab/v4/objects/clusters.py +13 -23
  29. gitlab/v4/objects/commits.py +23 -28
  30. gitlab/v4/objects/container_registry.py +13 -19
  31. gitlab/v4/objects/custom_attributes.py +16 -21
  32. gitlab/v4/objects/deploy_keys.py +22 -19
  33. gitlab/v4/objects/deploy_tokens.py +14 -32
  34. gitlab/v4/objects/deployments.py +13 -15
  35. gitlab/v4/objects/discussions.py +13 -29
  36. gitlab/v4/objects/draft_notes.py +4 -14
  37. gitlab/v4/objects/environments.py +13 -21
  38. gitlab/v4/objects/epics.py +14 -17
  39. gitlab/v4/objects/events.py +27 -79
  40. gitlab/v4/objects/export_import.py +7 -19
  41. gitlab/v4/objects/features.py +11 -12
  42. gitlab/v4/objects/files.py +23 -38
  43. gitlab/v4/objects/geo_nodes.py +7 -11
  44. gitlab/v4/objects/group_access_tokens.py +6 -13
  45. gitlab/v4/objects/groups.py +42 -37
  46. gitlab/v4/objects/hooks.py +4 -17
  47. gitlab/v4/objects/integrations.py +7 -18
  48. gitlab/v4/objects/invitations.py +12 -23
  49. gitlab/v4/objects/issues.py +21 -27
  50. gitlab/v4/objects/iterations.py +4 -8
  51. gitlab/v4/objects/job_token_scope.py +18 -14
  52. gitlab/v4/objects/jobs.py +17 -32
  53. gitlab/v4/objects/keys.py +8 -11
  54. gitlab/v4/objects/labels.py +19 -30
  55. gitlab/v4/objects/ldap.py +25 -9
  56. gitlab/v4/objects/member_roles.py +102 -0
  57. gitlab/v4/objects/members.py +11 -29
  58. gitlab/v4/objects/merge_request_approvals.py +47 -38
  59. gitlab/v4/objects/merge_requests.py +30 -40
  60. gitlab/v4/objects/merge_trains.py +3 -6
  61. gitlab/v4/objects/milestones.py +23 -29
  62. gitlab/v4/objects/namespaces.py +4 -10
  63. gitlab/v4/objects/notes.py +26 -69
  64. gitlab/v4/objects/notification_settings.py +5 -14
  65. gitlab/v4/objects/package_protection_rules.py +8 -8
  66. gitlab/v4/objects/packages.py +22 -37
  67. gitlab/v4/objects/pages.py +8 -14
  68. gitlab/v4/objects/personal_access_tokens.py +7 -10
  69. gitlab/v4/objects/pipelines.py +38 -47
  70. gitlab/v4/objects/project_access_tokens.py +6 -13
  71. gitlab/v4/objects/projects.py +54 -76
  72. gitlab/v4/objects/push_rules.py +13 -15
  73. gitlab/v4/objects/registry_protection_repository_rules.py +6 -7
  74. gitlab/v4/objects/registry_protection_rules.py +7 -11
  75. gitlab/v4/objects/releases.py +6 -20
  76. gitlab/v4/objects/repositories.py +25 -34
  77. gitlab/v4/objects/resource_groups.py +10 -15
  78. gitlab/v4/objects/reviewers.py +4 -2
  79. gitlab/v4/objects/runners.py +14 -13
  80. gitlab/v4/objects/secure_files.py +8 -21
  81. gitlab/v4/objects/service_accounts.py +7 -5
  82. gitlab/v4/objects/settings.py +13 -14
  83. gitlab/v4/objects/sidekiq.py +17 -18
  84. gitlab/v4/objects/snippets.py +78 -66
  85. gitlab/v4/objects/statistics.py +8 -23
  86. gitlab/v4/objects/status_checks.py +6 -3
  87. gitlab/v4/objects/tags.py +3 -13
  88. gitlab/v4/objects/templates.py +11 -59
  89. gitlab/v4/objects/todos.py +3 -6
  90. gitlab/v4/objects/topics.py +10 -21
  91. gitlab/v4/objects/triggers.py +3 -13
  92. gitlab/v4/objects/users.py +87 -93
  93. gitlab/v4/objects/variables.py +4 -19
  94. gitlab/v4/objects/wikis.py +4 -19
  95. {python_gitlab-5.5.0.dist-info → python_gitlab-6.0.0.dist-info}/METADATA +3 -2
  96. python_gitlab-6.0.0.dist-info/RECORD +107 -0
  97. {python_gitlab-5.5.0.dist-info → python_gitlab-6.0.0.dist-info}/WHEEL +1 -1
  98. python_gitlab-5.5.0.dist-info/RECORD +0 -106
  99. {python_gitlab-5.5.0.dist-info → python_gitlab-6.0.0.dist-info}/entry_points.txt +0 -0
  100. {python_gitlab-5.5.0.dist-info → python_gitlab-6.0.0.dist-info/licenses}/AUTHORS +0 -0
  101. {python_gitlab-5.5.0.dist-info → python_gitlab-6.0.0.dist-info/licenses}/COPYING +0 -0
  102. {python_gitlab-5.5.0.dist-info → python_gitlab-6.0.0.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,8 @@
1
- from typing import Any, cast, Dict, List, TYPE_CHECKING, Union
1
+ from typing import Any, Dict, List, TYPE_CHECKING
2
2
 
3
3
  from gitlab import cli
4
4
  from gitlab import exceptions as exc
5
- from gitlab.base import RESTManager, RESTObject
5
+ from gitlab.base import RESTObject
6
6
  from gitlab.mixins import (
7
7
  DeleteMixin,
8
8
  ObjectDeleteMixin,
@@ -12,10 +12,7 @@ from gitlab.mixins import (
12
12
  )
13
13
  from gitlab.types import RequiredOptional
14
14
 
15
- __all__ = [
16
- "GeoNode",
17
- "GeoNodeManager",
18
- ]
15
+ __all__ = ["GeoNode", "GeoNodeManager"]
19
16
 
20
17
 
21
18
  class GeoNode(SaveMixin, ObjectDeleteMixin, RESTObject):
@@ -59,16 +56,15 @@ class GeoNode(SaveMixin, ObjectDeleteMixin, RESTObject):
59
56
  return result
60
57
 
61
58
 
62
- class GeoNodeManager(RetrieveMixin, UpdateMixin, DeleteMixin, RESTManager):
59
+ class GeoNodeManager(
60
+ RetrieveMixin[GeoNode], UpdateMixin[GeoNode], DeleteMixin[GeoNode]
61
+ ):
63
62
  _path = "/geo_nodes"
64
63
  _obj_cls = GeoNode
65
64
  _update_attrs = RequiredOptional(
66
- optional=("enabled", "url", "files_max_capacity", "repos_max_capacity"),
65
+ optional=("enabled", "url", "files_max_capacity", "repos_max_capacity")
67
66
  )
68
67
 
69
- def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> GeoNode:
70
- return cast(GeoNode, super().get(id=id, lazy=lazy, **kwargs))
71
-
72
68
  @cli.register_custom_action(cls_names="GeoNodeManager")
73
69
  @exc.on_http_error(exc.GitlabGetError)
74
70
  def status(self, **kwargs: Any) -> List[Dict[str, Any]]:
@@ -1,6 +1,4 @@
1
- from typing import Any, cast, Union
2
-
3
- from gitlab.base import RESTManager, RESTObject
1
+ from gitlab.base import RESTObject
4
2
  from gitlab.mixins import (
5
3
  CreateMixin,
6
4
  DeleteMixin,
@@ -11,10 +9,7 @@ from gitlab.mixins import (
11
9
  )
12
10
  from gitlab.types import ArrayAttribute, RequiredOptional
13
11
 
14
- __all__ = [
15
- "GroupAccessToken",
16
- "GroupAccessTokenManager",
17
- ]
12
+ __all__ = ["GroupAccessToken", "GroupAccessTokenManager"]
18
13
 
19
14
 
20
15
  class GroupAccessToken(ObjectDeleteMixin, ObjectRotateMixin, RESTObject):
@@ -22,7 +17,10 @@ class GroupAccessToken(ObjectDeleteMixin, ObjectRotateMixin, RESTObject):
22
17
 
23
18
 
24
19
  class GroupAccessTokenManager(
25
- CreateMixin, DeleteMixin, RetrieveMixin, RotateMixin, RESTManager
20
+ CreateMixin[GroupAccessToken],
21
+ DeleteMixin[GroupAccessToken],
22
+ RetrieveMixin[GroupAccessToken],
23
+ RotateMixin[GroupAccessToken],
26
24
  ):
27
25
  _path = "/groups/{group_id}/access_tokens"
28
26
  _obj_cls = GroupAccessToken
@@ -31,8 +29,3 @@ class GroupAccessTokenManager(
31
29
  required=("name", "scopes"), optional=("access_level", "expires_at")
32
30
  )
33
31
  _types = {"scopes": ArrayAttribute}
34
-
35
- def get(
36
- self, id: Union[str, int], lazy: bool = False, **kwargs: Any
37
- ) -> GroupAccessToken:
38
- return cast(GroupAccessToken, super().get(id=id, lazy=lazy, **kwargs))
@@ -1,4 +1,6 @@
1
- from typing import Any, BinaryIO, cast, Dict, List, Optional, Type, TYPE_CHECKING, Union
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, BinaryIO, TYPE_CHECKING
2
4
 
3
5
  import requests
4
6
 
@@ -6,7 +8,7 @@ import gitlab
6
8
  from gitlab import cli
7
9
  from gitlab import exceptions as exc
8
10
  from gitlab import types
9
- from gitlab.base import RESTManager, RESTObject
11
+ from gitlab.base import RESTObject, TObjCls
10
12
  from gitlab.mixins import (
11
13
  CreateMixin,
12
14
  CRUDMixin,
@@ -34,11 +36,13 @@ from .invitations import GroupInvitationManager # noqa: F401
34
36
  from .issues import GroupIssueManager # noqa: F401
35
37
  from .iterations import GroupIterationManager # noqa: F401
36
38
  from .labels import GroupLabelManager # noqa: F401
39
+ from .member_roles import GroupMemberRoleManager # noqa: F401
37
40
  from .members import ( # noqa: F401
38
41
  GroupBillableMemberManager,
39
42
  GroupMemberAllManager,
40
43
  GroupMemberManager,
41
44
  )
45
+ from .merge_request_approvals import GroupApprovalRuleManager
42
46
  from .merge_requests import GroupMergeRequestManager # noqa: F401
43
47
  from .milestones import GroupMilestoneManager # noqa: F401
44
48
  from .notification_settings import GroupNotificationSettingsManager # noqa: F401
@@ -70,6 +74,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
70
74
 
71
75
  access_tokens: GroupAccessTokenManager
72
76
  accessrequests: GroupAccessRequestManager
77
+ approval_rules: GroupApprovalRuleManager
73
78
  audit_events: GroupAuditEventManager
74
79
  badges: GroupBadgeManager
75
80
  billable_members: GroupBillableMemberManager
@@ -77,7 +82,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
77
82
  clusters: GroupClusterManager
78
83
  customattributes: GroupCustomAttributeManager
79
84
  deploytokens: GroupDeployTokenManager
80
- descendant_groups: "GroupDescendantGroupManager"
85
+ descendant_groups: GroupDescendantGroupManager
81
86
  epics: GroupEpicManager
82
87
  exports: GroupExportManager
83
88
  hooks: GroupHookManager
@@ -87,7 +92,8 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
87
92
  issues_statistics: GroupIssuesStatisticsManager
88
93
  iterations: GroupIterationManager
89
94
  labels: GroupLabelManager
90
- ldap_group_links: "GroupLDAPGroupLinkManager"
95
+ ldap_group_links: GroupLDAPGroupLinkManager
96
+ member_roles: GroupMemberRoleManager
91
97
  members: GroupMemberManager
92
98
  members_all: GroupMemberAllManager
93
99
  mergerequests: GroupMergeRequestManager
@@ -99,11 +105,11 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
99
105
  pushrules: GroupPushRulesManager
100
106
  registry_repositories: GroupRegistryRepositoryManager
101
107
  runners: GroupRunnerManager
102
- subgroups: "GroupSubgroupManager"
108
+ subgroups: GroupSubgroupManager
103
109
  variables: GroupVariableManager
104
110
  wikis: GroupWikiManager
105
- saml_group_links: "GroupSAMLGroupLinkManager"
106
- service_accounts: "GroupServiceAccountManager"
111
+ saml_group_links: GroupSAMLGroupLinkManager
112
+ service_accounts: GroupServiceAccountManager
107
113
 
108
114
  @cli.register_custom_action(cls_names="Group", required=("project_id",))
109
115
  @exc.on_http_error(exc.GitlabTransferProjectError)
@@ -123,7 +129,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
123
129
 
124
130
  @cli.register_custom_action(cls_names="Group", required=(), optional=("group_id",))
125
131
  @exc.on_http_error(exc.GitlabGroupTransferError)
126
- def transfer(self, group_id: Optional[int] = None, **kwargs: Any) -> None:
132
+ def transfer(self, group_id: int | None = None, **kwargs: Any) -> None:
127
133
  """Transfer the group to a new parent group or make it a top-level group.
128
134
 
129
135
  Requires GitLab ≥14.6.
@@ -147,7 +153,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
147
153
  @exc.on_http_error(exc.GitlabSearchError)
148
154
  def search(
149
155
  self, scope: str, search: str, **kwargs: Any
150
- ) -> Union[gitlab.GitlabList, List[Dict[str, Any]]]:
156
+ ) -> gitlab.GitlabList | list[dict[str, Any]]:
151
157
  """Search the group resources matching the provided string.
152
158
 
153
159
  Args:
@@ -191,7 +197,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
191
197
  self,
192
198
  group_id: int,
193
199
  group_access: int,
194
- expires_at: Optional[str] = None,
200
+ expires_at: str | None = None,
195
201
  **kwargs: Any,
196
202
  ) -> None:
197
203
  """Share the group with a group.
@@ -251,7 +257,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
251
257
  self.manager.gitlab.http_post(path, **kwargs)
252
258
 
253
259
 
254
- class GroupManager(CRUDMixin, RESTManager):
260
+ class GroupManager(CRUDMixin[Group]):
255
261
  _path = "/groups"
256
262
  _obj_cls = Group
257
263
  _list_filters = (
@@ -313,22 +319,19 @@ class GroupManager(CRUDMixin, RESTManager):
313
319
  "extra_shared_runners_minutes_limit",
314
320
  "prevent_forking_outside_group",
315
321
  "shared_runners_setting",
316
- ),
322
+ )
317
323
  )
318
324
  _types = {"avatar": types.ImageAttribute, "skip_groups": types.ArrayAttribute}
319
325
 
320
- def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> Group:
321
- return cast(Group, super().get(id=id, lazy=lazy, **kwargs))
322
-
323
326
  @exc.on_http_error(exc.GitlabImportError)
324
327
  def import_group(
325
328
  self,
326
329
  file: BinaryIO,
327
330
  path: str,
328
331
  name: str,
329
- parent_id: Optional[Union[int, str]] = None,
332
+ parent_id: int | str | None = None,
330
333
  **kwargs: Any,
331
- ) -> Union[Dict[str, Any], requests.Response]:
334
+ ) -> dict[str, Any] | requests.Response:
332
335
  """Import a group from an archive file.
333
336
 
334
337
  Args:
@@ -347,7 +350,7 @@ class GroupManager(CRUDMixin, RESTManager):
347
350
  A representation of the import status.
348
351
  """
349
352
  files = {"file": ("file.tar.gz", file, "application/octet-stream")}
350
- data: Dict[str, Any] = {"path": path, "name": name}
353
+ data: dict[str, Any] = {"path": path, "name": name}
351
354
  if parent_id is not None:
352
355
  data["parent_id"] = parent_id
353
356
 
@@ -356,13 +359,7 @@ class GroupManager(CRUDMixin, RESTManager):
356
359
  )
357
360
 
358
361
 
359
- class GroupSubgroup(RESTObject):
360
- pass
361
-
362
-
363
- class GroupSubgroupManager(ListMixin, RESTManager):
364
- _path = "/groups/{group_id}/subgroups"
365
- _obj_cls: Union[Type["GroupDescendantGroup"], Type[GroupSubgroup]] = GroupSubgroup
362
+ class SubgroupBaseManager(ListMixin[TObjCls]):
366
363
  _from_parent_attrs = {"group_id": "id"}
367
364
  _list_filters = (
368
365
  "skip_groups",
@@ -378,24 +375,33 @@ class GroupSubgroupManager(ListMixin, RESTManager):
378
375
  _types = {"skip_groups": types.ArrayAttribute}
379
376
 
380
377
 
378
+ class GroupSubgroup(RESTObject):
379
+ pass
380
+
381
+
382
+ class GroupSubgroupManager(SubgroupBaseManager[GroupSubgroup]):
383
+ _path = "/groups/{group_id}/subgroups"
384
+ _obj_cls = GroupSubgroup
385
+
386
+
381
387
  class GroupDescendantGroup(RESTObject):
382
388
  pass
383
389
 
384
390
 
385
- class GroupDescendantGroupManager(GroupSubgroupManager):
391
+ class GroupDescendantGroupManager(SubgroupBaseManager[GroupDescendantGroup]):
386
392
  """
387
393
  This manager inherits from GroupSubgroupManager as descendant groups
388
394
  share all attributes with subgroups, except the path and object class.
389
395
  """
390
396
 
391
397
  _path = "/groups/{group_id}/descendant_groups"
392
- _obj_cls: Type[GroupDescendantGroup] = GroupDescendantGroup
398
+ _obj_cls = GroupDescendantGroup
393
399
 
394
400
 
395
401
  class GroupLDAPGroupLink(RESTObject):
396
402
  _repr_attr = "provider"
397
403
 
398
- def _get_link_attrs(self) -> Dict[str, str]:
404
+ def _get_link_attrs(self) -> dict[str, str]:
399
405
  # https://docs.gitlab.com/ee/api/groups.html#add-ldap-group-link-with-cn-or-filter
400
406
  # https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link-with-cn-or-filter
401
407
  # We can tell what attribute to use based on the data returned
@@ -424,9 +430,13 @@ class GroupLDAPGroupLink(RESTObject):
424
430
  )
425
431
 
426
432
 
427
- class GroupLDAPGroupLinkManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
433
+ class GroupLDAPGroupLinkManager(
434
+ ListMixin[GroupLDAPGroupLink],
435
+ CreateMixin[GroupLDAPGroupLink],
436
+ DeleteMixin[GroupLDAPGroupLink],
437
+ ):
428
438
  _path = "/groups/{group_id}/ldap_group_links"
429
- _obj_cls: Type[GroupLDAPGroupLink] = GroupLDAPGroupLink
439
+ _obj_cls = GroupLDAPGroupLink
430
440
  _from_parent_attrs = {"group_id": "id"}
431
441
  _create_attrs = RequiredOptional(
432
442
  required=("provider", "group_access"), exclusive=("cn", "filter")
@@ -438,13 +448,8 @@ class GroupSAMLGroupLink(ObjectDeleteMixin, RESTObject):
438
448
  _repr_attr = "name"
439
449
 
440
450
 
441
- class GroupSAMLGroupLinkManager(NoUpdateMixin, RESTManager):
451
+ class GroupSAMLGroupLinkManager(NoUpdateMixin[GroupSAMLGroupLink]):
442
452
  _path = "/groups/{group_id}/saml_group_links"
443
- _obj_cls: Type[GroupSAMLGroupLink] = GroupSAMLGroupLink
453
+ _obj_cls = GroupSAMLGroupLink
444
454
  _from_parent_attrs = {"group_id": "id"}
445
455
  _create_attrs = RequiredOptional(required=("saml_group_name", "access_level"))
446
-
447
- def get(
448
- self, id: Union[str, int], lazy: bool = False, **kwargs: Any
449
- ) -> GroupSAMLGroupLink:
450
- return cast(GroupSAMLGroupLink, super().get(id=id, lazy=lazy, **kwargs))
@@ -1,7 +1,5 @@
1
- from typing import Any, cast, Union
2
-
3
1
  from gitlab import exceptions as exc
4
- from gitlab.base import RESTManager, RESTObject
2
+ from gitlab.base import RESTObject
5
3
  from gitlab.mixins import CRUDMixin, NoUpdateMixin, ObjectDeleteMixin, SaveMixin
6
4
  from gitlab.types import RequiredOptional
7
5
 
@@ -20,14 +18,11 @@ class Hook(ObjectDeleteMixin, RESTObject):
20
18
  _repr_attr = "url"
21
19
 
22
20
 
23
- class HookManager(NoUpdateMixin, RESTManager):
21
+ class HookManager(NoUpdateMixin[Hook]):
24
22
  _path = "/hooks"
25
23
  _obj_cls = Hook
26
24
  _create_attrs = RequiredOptional(required=("url",))
27
25
 
28
- def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> Hook:
29
- return cast(Hook, super().get(id=id, lazy=lazy, **kwargs))
30
-
31
26
 
32
27
  class ProjectHook(SaveMixin, ObjectDeleteMixin, RESTObject):
33
28
  _repr_attr = "url"
@@ -47,7 +42,7 @@ class ProjectHook(SaveMixin, ObjectDeleteMixin, RESTObject):
47
42
  self.manager.gitlab.http_post(path)
48
43
 
49
44
 
50
- class ProjectHookManager(CRUDMixin, RESTManager):
45
+ class ProjectHookManager(CRUDMixin[ProjectHook]):
51
46
  _path = "/projects/{project_id}/hooks"
52
47
  _obj_cls = ProjectHook
53
48
  _from_parent_attrs = {"project_id": "id"}
@@ -84,11 +79,6 @@ class ProjectHookManager(CRUDMixin, RESTManager):
84
79
  ),
85
80
  )
86
81
 
87
- def get(
88
- self, id: Union[str, int], lazy: bool = False, **kwargs: Any
89
- ) -> ProjectHook:
90
- return cast(ProjectHook, super().get(id=id, lazy=lazy, **kwargs))
91
-
92
82
 
93
83
  class GroupHook(SaveMixin, ObjectDeleteMixin, RESTObject):
94
84
  _repr_attr = "url"
@@ -108,7 +98,7 @@ class GroupHook(SaveMixin, ObjectDeleteMixin, RESTObject):
108
98
  self.manager.gitlab.http_post(path)
109
99
 
110
100
 
111
- class GroupHookManager(CRUDMixin, RESTManager):
101
+ class GroupHookManager(CRUDMixin[GroupHook]):
112
102
  _path = "/groups/{group_id}/hooks"
113
103
  _obj_cls = GroupHook
114
104
  _from_parent_attrs = {"group_id": "id"}
@@ -152,6 +142,3 @@ class GroupHookManager(CRUDMixin, RESTManager):
152
142
  "token",
153
143
  ),
154
144
  )
155
-
156
- def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> GroupHook:
157
- return cast(GroupHook, super().get(id=id, lazy=lazy, **kwargs))
@@ -3,10 +3,10 @@ GitLab API:
3
3
  https://docs.gitlab.com/ee/api/integrations.html
4
4
  """
5
5
 
6
- from typing import Any, cast, List, Union
6
+ from typing import List
7
7
 
8
8
  from gitlab import cli
9
- from gitlab.base import RESTManager, RESTObject
9
+ from gitlab.base import RESTObject
10
10
  from gitlab.mixins import (
11
11
  DeleteMixin,
12
12
  GetMixin,
@@ -29,7 +29,10 @@ class ProjectIntegration(SaveMixin, ObjectDeleteMixin, RESTObject):
29
29
 
30
30
 
31
31
  class ProjectIntegrationManager(
32
- GetMixin, UpdateMixin, DeleteMixin, ListMixin, RESTManager
32
+ GetMixin[ProjectIntegration],
33
+ UpdateMixin[ProjectIntegration],
34
+ DeleteMixin[ProjectIntegration],
35
+ ListMixin[ProjectIntegration],
33
36
  ):
34
37
  _path = "/projects/{project_id}/integrations"
35
38
  _from_parent_attrs = {"project_id": "id"}
@@ -149,11 +152,7 @@ class ProjectIntegrationManager(
149
152
  ),
150
153
  ),
151
154
  "jira": (
152
- (
153
- "url",
154
- "username",
155
- "password",
156
- ),
155
+ ("url", "username", "password"),
157
156
  (
158
157
  "api_url",
159
158
  "active",
@@ -265,11 +264,6 @@ class ProjectIntegrationManager(
265
264
  "youtrack": (("issues_url", "project_url"), ("description", "push_events")),
266
265
  }
267
266
 
268
- def get(
269
- self, id: Union[str, int], lazy: bool = False, **kwargs: Any
270
- ) -> ProjectIntegration:
271
- return cast(ProjectIntegration, super().get(id=id, lazy=lazy, **kwargs))
272
-
273
267
  @cli.register_custom_action(
274
268
  cls_names=("ProjectIntegrationManager", "ProjectServiceManager")
275
269
  )
@@ -288,8 +282,3 @@ class ProjectService(ProjectIntegration):
288
282
 
289
283
  class ProjectServiceManager(ProjectIntegrationManager):
290
284
  _obj_cls = ProjectService
291
-
292
- def get(
293
- self, id: Union[str, int], lazy: bool = False, **kwargs: Any
294
- ) -> ProjectService:
295
- return cast(ProjectService, super().get(id=id, lazy=lazy, **kwargs))
@@ -1,6 +1,8 @@
1
- from typing import Any, cast, Union
1
+ from __future__ import annotations
2
2
 
3
- from gitlab.base import RESTManager, RESTObject
3
+ from typing import Any
4
+
5
+ from gitlab.base import RESTObject, TObjCls
4
6
  from gitlab.exceptions import GitlabInvitationError
5
7
  from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin
6
8
  from gitlab.types import ArrayAttribute, CommaSeparatedListAttribute, RequiredOptional
@@ -13,9 +15,10 @@ __all__ = [
13
15
  ]
14
16
 
15
17
 
16
- class InvitationMixin(CRUDMixin):
17
- def create(self, *args: Any, **kwargs: Any) -> RESTObject:
18
- invitation = super().create(*args, **kwargs)
18
+ class InvitationMixin(CRUDMixin[TObjCls]):
19
+ # pylint: disable=abstract-method
20
+ def create(self, data: dict[str, Any] | None = None, **kwargs: Any) -> TObjCls:
21
+ invitation = super().create(data, **kwargs)
19
22
 
20
23
  if invitation.status == "error":
21
24
  raise GitlabInvitationError(invitation.message)
@@ -27,7 +30,7 @@ class ProjectInvitation(SaveMixin, ObjectDeleteMixin, RESTObject):
27
30
  _id_attr = "email"
28
31
 
29
32
 
30
- class ProjectInvitationManager(InvitationMixin, RESTManager):
33
+ class ProjectInvitationManager(InvitationMixin[ProjectInvitation]):
31
34
  _path = "/projects/{project_id}/invitations"
32
35
  _obj_cls = ProjectInvitation
33
36
  _from_parent_attrs = {"project_id": "id"}
@@ -41,9 +44,7 @@ class ProjectInvitationManager(InvitationMixin, RESTManager):
41
44
  ),
42
45
  exclusive=("email", "user_id"),
43
46
  )
44
- _update_attrs = RequiredOptional(
45
- optional=("access_level", "expires_at"),
46
- )
47
+ _update_attrs = RequiredOptional(optional=("access_level", "expires_at"))
47
48
  _list_filters = ("query",)
48
49
  _types = {
49
50
  "email": CommaSeparatedListAttribute,
@@ -51,17 +52,12 @@ class ProjectInvitationManager(InvitationMixin, RESTManager):
51
52
  "tasks_to_be_done": ArrayAttribute,
52
53
  }
53
54
 
54
- def get(
55
- self, id: Union[str, int], lazy: bool = False, **kwargs: Any
56
- ) -> ProjectInvitation:
57
- return cast(ProjectInvitation, super().get(id=id, lazy=lazy, **kwargs))
58
-
59
55
 
60
56
  class GroupInvitation(SaveMixin, ObjectDeleteMixin, RESTObject):
61
57
  _id_attr = "email"
62
58
 
63
59
 
64
- class GroupInvitationManager(InvitationMixin, RESTManager):
60
+ class GroupInvitationManager(InvitationMixin[GroupInvitation]):
65
61
  _path = "/groups/{group_id}/invitations"
66
62
  _obj_cls = GroupInvitation
67
63
  _from_parent_attrs = {"group_id": "id"}
@@ -75,17 +71,10 @@ class GroupInvitationManager(InvitationMixin, RESTManager):
75
71
  ),
76
72
  exclusive=("email", "user_id"),
77
73
  )
78
- _update_attrs = RequiredOptional(
79
- optional=("access_level", "expires_at"),
80
- )
74
+ _update_attrs = RequiredOptional(optional=("access_level", "expires_at"))
81
75
  _list_filters = ("query",)
82
76
  _types = {
83
77
  "email": CommaSeparatedListAttribute,
84
78
  "user_id": CommaSeparatedListAttribute,
85
79
  "tasks_to_be_done": ArrayAttribute,
86
80
  }
87
-
88
- def get(
89
- self, id: Union[str, int], lazy: bool = False, **kwargs: Any
90
- ) -> GroupInvitation:
91
- return cast(GroupInvitation, super().get(id=id, lazy=lazy, **kwargs))
@@ -1,11 +1,13 @@
1
- from typing import Any, cast, Dict, List, Optional, Tuple, TYPE_CHECKING, Union
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, TYPE_CHECKING
2
4
 
3
5
  import requests
4
6
 
5
7
  from gitlab import cli, client
6
8
  from gitlab import exceptions as exc
7
9
  from gitlab import types
8
- from gitlab.base import RESTManager, RESTObject
10
+ from gitlab.base import RESTObject
9
11
  from gitlab.mixins import (
10
12
  CreateMixin,
11
13
  CRUDMixin,
@@ -50,7 +52,7 @@ class Issue(RESTObject):
50
52
  _repr_attr = "title"
51
53
 
52
54
 
53
- class IssueManager(RetrieveMixin, RESTManager):
55
+ class IssueManager(RetrieveMixin[Issue]):
54
56
  _path = "/issues"
55
57
  _obj_cls = Issue
56
58
  _list_filters = (
@@ -73,15 +75,12 @@ class IssueManager(RetrieveMixin, RESTManager):
73
75
  )
74
76
  _types = {"iids": types.ArrayAttribute, "labels": types.CommaSeparatedListAttribute}
75
77
 
76
- def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> Issue:
77
- return cast(Issue, super().get(id=id, lazy=lazy, **kwargs))
78
-
79
78
 
80
79
  class GroupIssue(RESTObject):
81
80
  pass
82
81
 
83
82
 
84
- class GroupIssueManager(ListMixin, RESTManager):
83
+ class GroupIssueManager(ListMixin[GroupIssue]):
85
84
  _path = "/groups/{group_id}/issues"
86
85
  _obj_cls = GroupIssue
87
86
  _from_parent_attrs = {"group_id": "id"}
@@ -120,7 +119,7 @@ class ProjectIssue(
120
119
 
121
120
  awardemojis: ProjectIssueAwardEmojiManager
122
121
  discussions: ProjectIssueDiscussionManager
123
- links: "ProjectIssueLinkManager"
122
+ links: ProjectIssueLinkManager
124
123
  notes: ProjectIssueNoteManager
125
124
  resourcelabelevents: ProjectIssueResourceLabelEventManager
126
125
  resourcemilestoneevents: ProjectIssueResourceMilestoneEventManager
@@ -154,8 +153,8 @@ class ProjectIssue(
154
153
  @exc.on_http_error(exc.GitlabUpdateError)
155
154
  def reorder(
156
155
  self,
157
- move_after_id: Optional[int] = None,
158
- move_before_id: Optional[int] = None,
156
+ move_after_id: int | None = None,
157
+ move_before_id: int | None = None,
159
158
  **kwargs: Any,
160
159
  ) -> None:
161
160
  """Reorder an issue on a board.
@@ -170,7 +169,7 @@ class ProjectIssue(
170
169
  GitlabUpdateError: If the issue could not be reordered
171
170
  """
172
171
  path = f"{self.manager.path}/{self.encoded_id}/reorder"
173
- data: Dict[str, Any] = {}
172
+ data: dict[str, Any] = {}
174
173
 
175
174
  if move_after_id is not None:
176
175
  data["move_after_id"] = move_after_id
@@ -186,7 +185,7 @@ class ProjectIssue(
186
185
  @exc.on_http_error(exc.GitlabGetError)
187
186
  def related_merge_requests(
188
187
  self, **kwargs: Any
189
- ) -> Union[client.GitlabList, List[Dict[str, Any]]]:
188
+ ) -> client.GitlabList | list[dict[str, Any]]:
190
189
  """List merge requests related to the issue.
191
190
 
192
191
  Args:
@@ -207,9 +206,7 @@ class ProjectIssue(
207
206
 
208
207
  @cli.register_custom_action(cls_names="ProjectIssue")
209
208
  @exc.on_http_error(exc.GitlabGetError)
210
- def closed_by(
211
- self, **kwargs: Any
212
- ) -> Union[client.GitlabList, List[Dict[str, Any]]]:
209
+ def closed_by(self, **kwargs: Any) -> client.GitlabList | list[dict[str, Any]]:
213
210
  """List merge requests that will close the issue when merged.
214
211
 
215
212
  Args:
@@ -229,7 +226,7 @@ class ProjectIssue(
229
226
  return result
230
227
 
231
228
 
232
- class ProjectIssueManager(CRUDMixin, RESTManager):
229
+ class ProjectIssueManager(CRUDMixin[ProjectIssue]):
233
230
  _path = "/projects/{project_id}/issues"
234
231
  _obj_cls = ProjectIssue
235
232
  _from_parent_attrs = {"project_id": "id"}
@@ -279,21 +276,20 @@ class ProjectIssueManager(CRUDMixin, RESTManager):
279
276
  "updated_at",
280
277
  "due_date",
281
278
  "discussion_locked",
282
- ),
279
+ )
283
280
  )
284
281
  _types = {"iids": types.ArrayAttribute, "labels": types.CommaSeparatedListAttribute}
285
282
 
286
- def get(
287
- self, id: Union[str, int], lazy: bool = False, **kwargs: Any
288
- ) -> ProjectIssue:
289
- return cast(ProjectIssue, super().get(id=id, lazy=lazy, **kwargs))
290
-
291
283
 
292
284
  class ProjectIssueLink(ObjectDeleteMixin, RESTObject):
293
285
  _id_attr = "issue_link_id"
294
286
 
295
287
 
296
- class ProjectIssueLinkManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
288
+ class ProjectIssueLinkManager(
289
+ ListMixin[ProjectIssueLink],
290
+ CreateMixin[ProjectIssueLink],
291
+ DeleteMixin[ProjectIssueLink],
292
+ ):
297
293
  _path = "/projects/{project_id}/issues/{issue_iid}/links"
298
294
  _obj_cls = ProjectIssueLink
299
295
  _from_parent_attrs = {"project_id": "project_id", "issue_iid": "iid"}
@@ -303,8 +299,8 @@ class ProjectIssueLinkManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
303
299
  # NOTE(jlvillal): Signature doesn't match CreateMixin.create() so ignore
304
300
  # type error
305
301
  def create( # type: ignore[override]
306
- self, data: Dict[str, Any], **kwargs: Any
307
- ) -> Tuple[RESTObject, RESTObject]:
302
+ self, data: dict[str, Any], **kwargs: Any
303
+ ) -> tuple[ProjectIssue, ProjectIssue]:
308
304
  """Create a new object.
309
305
 
310
306
  Args:
@@ -320,8 +316,6 @@ class ProjectIssueLinkManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
320
316
  GitlabCreateError: If the server cannot perform the request
321
317
  """
322
318
  self._create_attrs.validate_attrs(data=data)
323
- if TYPE_CHECKING:
324
- assert self.path is not None
325
319
  server_data = self.gitlab.http_post(self.path, post_data=data, **kwargs)
326
320
  if TYPE_CHECKING:
327
321
  assert isinstance(server_data, dict)
@@ -1,19 +1,15 @@
1
1
  from gitlab import types
2
- from gitlab.base import RESTManager, RESTObject
2
+ from gitlab.base import RESTObject
3
3
  from gitlab.mixins import ListMixin
4
4
 
5
- __all__ = [
6
- "ProjectIterationManager",
7
- "GroupIteration",
8
- "GroupIterationManager",
9
- ]
5
+ __all__ = ["ProjectIterationManager", "GroupIteration", "GroupIterationManager"]
10
6
 
11
7
 
12
8
  class GroupIteration(RESTObject):
13
9
  _repr_attr = "title"
14
10
 
15
11
 
16
- class GroupIterationManager(ListMixin, RESTManager):
12
+ class GroupIterationManager(ListMixin[GroupIteration]):
17
13
  _path = "/groups/{group_id}/iterations"
18
14
  _obj_cls = GroupIteration
19
15
  _from_parent_attrs = {"group_id": "id"}
@@ -33,7 +29,7 @@ class GroupIterationManager(ListMixin, RESTManager):
33
29
  _types = {"in": types.ArrayAttribute}
34
30
 
35
31
 
36
- class ProjectIterationManager(ListMixin, RESTManager):
32
+ class ProjectIterationManager(ListMixin[GroupIteration]):
37
33
  _path = "/projects/{project_id}/iterations"
38
34
  _obj_cls = GroupIteration
39
35
  _from_parent_attrs = {"project_id": "id"}