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
gitlab/client.py CHANGED
@@ -4,18 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import os
6
6
  import re
7
- from typing import (
8
- Any,
9
- BinaryIO,
10
- cast,
11
- Dict,
12
- List,
13
- Optional,
14
- Tuple,
15
- Type,
16
- TYPE_CHECKING,
17
- Union,
18
- )
7
+ from typing import Any, BinaryIO, cast, TYPE_CHECKING
19
8
  from urllib import parse
20
9
 
21
10
  import requests
@@ -83,26 +72,26 @@ class Gitlab:
83
72
 
84
73
  def __init__(
85
74
  self,
86
- url: Optional[str] = None,
87
- private_token: Optional[str] = None,
88
- oauth_token: Optional[str] = None,
89
- job_token: Optional[str] = None,
90
- ssl_verify: Union[bool, str] = True,
91
- http_username: Optional[str] = None,
92
- http_password: Optional[str] = None,
93
- timeout: Optional[float] = None,
75
+ url: str | None = None,
76
+ private_token: str | None = None,
77
+ oauth_token: str | None = None,
78
+ job_token: str | None = None,
79
+ ssl_verify: bool | str = True,
80
+ http_username: str | None = None,
81
+ http_password: str | None = None,
82
+ timeout: float | None = None,
94
83
  api_version: str = "4",
95
- per_page: Optional[int] = None,
96
- pagination: Optional[str] = None,
97
- order_by: Optional[str] = None,
84
+ per_page: int | None = None,
85
+ pagination: str | None = None,
86
+ order_by: str | None = None,
98
87
  user_agent: str = gitlab.const.USER_AGENT,
99
88
  retry_transient_errors: bool = False,
100
89
  keep_base_url: bool = False,
101
90
  **kwargs: Any,
102
91
  ) -> None:
103
92
  self._api_version = str(api_version)
104
- self._server_version: Optional[str] = None
105
- self._server_revision: Optional[str] = None
93
+ self._server_version: str | None = None
94
+ self._server_revision: str | None = None
106
95
  self._base_url = utils.get_base_url(url)
107
96
  self._url = f"{self._base_url}/api/v{api_version}"
108
97
  #: Timeout to use for requests to gitlab server
@@ -123,7 +112,7 @@ class Gitlab:
123
112
  self._set_auth_info()
124
113
 
125
114
  #: Create a session object for requests
126
- _backend: Type[_backends.DefaultBackend] = kwargs.pop(
115
+ _backend: type[_backends.DefaultBackend] = kwargs.pop(
127
116
  "backend", _backends.DefaultBackend
128
117
  )
129
118
  self._backend = _backend(**kwargs)
@@ -141,7 +130,7 @@ class Gitlab:
141
130
  from gitlab.v4 import objects
142
131
 
143
132
  self._objects = objects
144
- self.user: Optional[objects.CurrentUser] = None
133
+ self.user: objects.CurrentUser | None = None
145
134
 
146
135
  self.broadcastmessages = objects.BroadcastMessageManager(self)
147
136
  """See :class:`~gitlab.v4.objects.BroadcastMessageManager`"""
@@ -177,6 +166,8 @@ class Gitlab:
177
166
  """See :class:`~gitlab.v4.objects.LicenseManager`"""
178
167
  self.namespaces = objects.NamespaceManager(self)
179
168
  """See :class:`~gitlab.v4.objects.NamespaceManager`"""
169
+ self.member_roles = objects.MemberRoleManager(self)
170
+ """See :class:`~gitlab.v4.objects.MergeRequestManager`"""
180
171
  self.mergerequests = objects.MergeRequestManager(self)
181
172
  """See :class:`~gitlab.v4.objects.MergeRequestManager`"""
182
173
  self.notificationsettings = objects.NotificationSettingsManager(self)
@@ -224,18 +215,18 @@ class Gitlab:
224
215
  self.statistics = objects.ApplicationStatisticsManager(self)
225
216
  """See :class:`~gitlab.v4.objects.ApplicationStatisticsManager`"""
226
217
 
227
- def __enter__(self) -> "Gitlab":
218
+ def __enter__(self) -> Gitlab:
228
219
  return self
229
220
 
230
221
  def __exit__(self, *args: Any) -> None:
231
222
  self.session.close()
232
223
 
233
- def __getstate__(self) -> Dict[str, Any]:
224
+ def __getstate__(self) -> dict[str, Any]:
234
225
  state = self.__dict__.copy()
235
226
  state.pop("_objects")
236
227
  return state
237
228
 
238
- def __setstate__(self, state: Dict[str, Any]) -> None:
229
+ def __setstate__(self, state: dict[str, Any]) -> None:
239
230
  self.__dict__.update(state)
240
231
  # We only support v4 API at this time
241
232
  if self._api_version not in ("4",):
@@ -266,10 +257,10 @@ class Gitlab:
266
257
  @classmethod
267
258
  def from_config(
268
259
  cls,
269
- gitlab_id: Optional[str] = None,
270
- config_files: Optional[List[str]] = None,
260
+ gitlab_id: str | None = None,
261
+ config_files: list[str] | None = None,
271
262
  **kwargs: Any,
272
- ) -> "Gitlab":
263
+ ) -> Gitlab:
273
264
  """Create a Gitlab connection from configuration files.
274
265
 
275
266
  Args:
@@ -310,10 +301,10 @@ class Gitlab:
310
301
  @classmethod
311
302
  def merge_config(
312
303
  cls,
313
- options: Dict[str, Any],
314
- gitlab_id: Optional[str] = None,
315
- config_files: Optional[List[str]] = None,
316
- ) -> "Gitlab":
304
+ options: dict[str, Any],
305
+ gitlab_id: str | None = None,
306
+ config_files: list[str] | None = None,
307
+ ) -> Gitlab:
317
308
  """Create a Gitlab connection by merging configuration with
318
309
  the following precedence:
319
310
 
@@ -364,8 +355,8 @@ class Gitlab:
364
355
 
365
356
  @staticmethod
366
357
  def _merge_auth(
367
- options: Dict[str, Any], config: gitlab.config.GitlabConfigParser
368
- ) -> Tuple[Optional[str], Optional[str], Optional[str]]:
358
+ options: dict[str, Any], config: gitlab.config.GitlabConfigParser
359
+ ) -> tuple[str | None, str | None, str | None]:
369
360
  """
370
361
  Return a tuple where at most one of 3 token types ever has a value.
371
362
  Since multiple types of tokens may be present in the environment,
@@ -402,7 +393,7 @@ class Gitlab:
402
393
  if hasattr(self.user, "web_url") and hasattr(self.user, "username"):
403
394
  self._check_url(self.user.web_url, path=self.user.username)
404
395
 
405
- def version(self) -> Tuple[str, str]:
396
+ def version(self) -> tuple[str, str]:
406
397
  """Returns the version and revision of the gitlab server.
407
398
 
408
399
  Note that self.version and self.revision will be set on the gitlab
@@ -429,7 +420,7 @@ class Gitlab:
429
420
 
430
421
  @gitlab.exceptions.on_http_error(gitlab.exceptions.GitlabMarkdownError)
431
422
  def markdown(
432
- self, text: str, gfm: bool = False, project: Optional[str] = None, **kwargs: Any
423
+ self, text: str, gfm: bool = False, project: str | None = None, **kwargs: Any
433
424
  ) -> str:
434
425
  """Render an arbitrary Markdown document.
435
426
 
@@ -456,7 +447,7 @@ class Gitlab:
456
447
  return data["html"]
457
448
 
458
449
  @gitlab.exceptions.on_http_error(gitlab.exceptions.GitlabLicenseError)
459
- def get_license(self, **kwargs: Any) -> Dict[str, Union[str, Dict[str, str]]]:
450
+ def get_license(self, **kwargs: Any) -> dict[str, str | dict[str, str]]:
460
451
  """Retrieve information about the current license.
461
452
 
462
453
  Args:
@@ -475,7 +466,7 @@ class Gitlab:
475
466
  return {}
476
467
 
477
468
  @gitlab.exceptions.on_http_error(gitlab.exceptions.GitlabLicenseError)
478
- def set_license(self, license: str, **kwargs: Any) -> Dict[str, Any]:
469
+ def set_license(self, license: str, **kwargs: Any) -> dict[str, Any]:
479
470
  """Add a new license.
480
471
 
481
472
  Args:
@@ -516,7 +507,7 @@ class Gitlab:
516
507
  "authentication should be defined"
517
508
  )
518
509
 
519
- self._auth: Optional[requests.auth.AuthBase] = None
510
+ self._auth: requests.auth.AuthBase | None = None
520
511
  if self.private_token:
521
512
  self._auth = _backends.PrivateTokenAuth(self.private_token)
522
513
 
@@ -564,7 +555,7 @@ class Gitlab:
564
555
  logger.handlers.clear()
565
556
  logger.addHandler(handler)
566
557
 
567
- def _get_session_opts(self) -> Dict[str, Any]:
558
+ def _get_session_opts(self) -> dict[str, Any]:
568
559
  return {
569
560
  "headers": self.headers.copy(),
570
561
  "auth": self._auth,
@@ -585,7 +576,7 @@ class Gitlab:
585
576
  return path
586
577
  return f"{self._url}{path}"
587
578
 
588
- def _check_url(self, url: Optional[str], *, path: str = "api") -> Optional[str]:
579
+ def _check_url(self, url: str | None, *, path: str = "api") -> str | None:
589
580
  """
590
581
  Checks if ``url`` starts with a different base URL from the user-provided base
591
582
  URL and warns the user before returning it. If ``keep_base_url`` is set to
@@ -645,16 +636,16 @@ class Gitlab:
645
636
  self,
646
637
  verb: str,
647
638
  path: str,
648
- query_data: Optional[Dict[str, Any]] = None,
649
- post_data: Optional[Union[Dict[str, Any], bytes, BinaryIO]] = None,
639
+ query_data: dict[str, Any] | None = None,
640
+ post_data: dict[str, Any] | bytes | BinaryIO | None = None,
650
641
  raw: bool = False,
651
642
  streamed: bool = False,
652
- files: Optional[Dict[str, Any]] = None,
653
- timeout: Optional[float] = None,
643
+ files: dict[str, Any] | None = None,
644
+ timeout: float | None = None,
654
645
  obey_rate_limit: bool = True,
655
- retry_transient_errors: Optional[bool] = None,
646
+ retry_transient_errors: bool | None = None,
656
647
  max_retries: int = 10,
657
- extra_headers: Optional[Dict[str, Any]] = None,
648
+ extra_headers: dict[str, Any] | None = None,
658
649
  **kwargs: Any,
659
650
  ) -> requests.Response:
660
651
  """Make an HTTP request to the Gitlab server.
@@ -785,11 +776,11 @@ class Gitlab:
785
776
  def http_get(
786
777
  self,
787
778
  path: str,
788
- query_data: Optional[Dict[str, Any]] = None,
779
+ query_data: dict[str, Any] | None = None,
789
780
  streamed: bool = False,
790
781
  raw: bool = False,
791
782
  **kwargs: Any,
792
- ) -> Union[Dict[str, Any], requests.Response]:
783
+ ) -> dict[str, Any] | requests.Response:
793
784
  """Make a GET request to the Gitlab server.
794
785
 
795
786
  Args:
@@ -829,8 +820,8 @@ class Gitlab:
829
820
  return result
830
821
 
831
822
  def http_head(
832
- self, path: str, query_data: Optional[Dict[str, Any]] = None, **kwargs: Any
833
- ) -> "requests.structures.CaseInsensitiveDict[Any]":
823
+ self, path: str, query_data: dict[str, Any] | None = None, **kwargs: Any
824
+ ) -> requests.structures.CaseInsensitiveDict[Any]:
834
825
  """Make a HEAD request to the Gitlab server.
835
826
 
836
827
  Args:
@@ -852,12 +843,12 @@ class Gitlab:
852
843
  def http_list(
853
844
  self,
854
845
  path: str,
855
- query_data: Optional[Dict[str, Any]] = None,
846
+ query_data: dict[str, Any] | None = None,
856
847
  *,
857
- iterator: Optional[bool] = None,
858
- message_details: Optional[utils.WarnMessageData] = None,
848
+ iterator: bool | None = None,
849
+ message_details: utils.WarnMessageData | None = None,
859
850
  **kwargs: Any,
860
- ) -> Union["GitlabList", List[Dict[str, Any]]]:
851
+ ) -> GitlabList | list[dict[str, Any]]:
861
852
  """Make a GET request to the Gitlab server for list-oriented queries.
862
853
 
863
854
  Args:
@@ -892,18 +883,16 @@ class Gitlab:
892
883
 
893
884
  page = kwargs.get("page")
894
885
 
895
- if iterator and page is not None:
896
- arg_used_message = f"iterator={iterator}"
897
- utils.warn(
898
- message=(
899
- f"`{arg_used_message}` and `page={page}` were both specified. "
900
- f"`{arg_used_message}` will be ignored and a `list` will be "
901
- f"returned."
902
- ),
903
- category=UserWarning,
904
- )
886
+ if iterator:
887
+ if page is not None:
888
+ utils.warn(
889
+ message=(
890
+ f"`{iterator=}` and `{page=}` were both specified. "
891
+ f"`{page=}` will be ignored."
892
+ ),
893
+ category=UserWarning,
894
+ )
905
895
 
906
- if iterator and page is None:
907
896
  # Generator requested
908
897
  return GitlabList(self, url, query_data, **kwargs)
909
898
 
@@ -958,22 +947,18 @@ class Gitlab:
958
947
  f"`get_all=False` to the `list()` call."
959
948
  )
960
949
  show_caller = True
961
- utils.warn(
962
- message=message,
963
- category=UserWarning,
964
- show_caller=show_caller,
965
- )
950
+ utils.warn(message=message, category=UserWarning, show_caller=show_caller)
966
951
  return items
967
952
 
968
953
  def http_post(
969
954
  self,
970
955
  path: str,
971
- query_data: Optional[Dict[str, Any]] = None,
972
- post_data: Optional[Dict[str, Any]] = None,
956
+ query_data: dict[str, Any] | None = None,
957
+ post_data: dict[str, Any] | None = None,
973
958
  raw: bool = False,
974
- files: Optional[Dict[str, Any]] = None,
959
+ files: dict[str, Any] | None = None,
975
960
  **kwargs: Any,
976
- ) -> Union[Dict[str, Any], requests.Response]:
961
+ ) -> dict[str, Any] | requests.Response:
977
962
  """Make a POST request to the Gitlab server.
978
963
 
979
964
  Args:
@@ -1023,12 +1008,12 @@ class Gitlab:
1023
1008
  def http_put(
1024
1009
  self,
1025
1010
  path: str,
1026
- query_data: Optional[Dict[str, Any]] = None,
1027
- post_data: Optional[Union[Dict[str, Any], bytes, BinaryIO]] = None,
1011
+ query_data: dict[str, Any] | None = None,
1012
+ post_data: dict[str, Any] | bytes | BinaryIO | None = None,
1028
1013
  raw: bool = False,
1029
- files: Optional[Dict[str, Any]] = None,
1014
+ files: dict[str, Any] | None = None,
1030
1015
  **kwargs: Any,
1031
- ) -> Union[Dict[str, Any], requests.Response]:
1016
+ ) -> dict[str, Any] | requests.Response:
1032
1017
  """Make a PUT request to the Gitlab server.
1033
1018
 
1034
1019
  Args:
@@ -1076,11 +1061,11 @@ class Gitlab:
1076
1061
  self,
1077
1062
  path: str,
1078
1063
  *,
1079
- query_data: Optional[Dict[str, Any]] = None,
1080
- post_data: Optional[Union[Dict[str, Any], bytes]] = None,
1064
+ query_data: dict[str, Any] | None = None,
1065
+ post_data: dict[str, Any] | bytes | None = None,
1081
1066
  raw: bool = False,
1082
1067
  **kwargs: Any,
1083
- ) -> Union[Dict[str, Any], requests.Response]:
1068
+ ) -> dict[str, Any] | requests.Response:
1084
1069
  """Make a PATCH request to the Gitlab server.
1085
1070
 
1086
1071
  Args:
@@ -1103,12 +1088,7 @@ class Gitlab:
1103
1088
  post_data = post_data or {}
1104
1089
 
1105
1090
  result = self.http_request(
1106
- "patch",
1107
- path,
1108
- query_data=query_data,
1109
- post_data=post_data,
1110
- raw=raw,
1111
- **kwargs,
1091
+ "patch", path, query_data=query_data, post_data=post_data, raw=raw, **kwargs
1112
1092
  )
1113
1093
  if result.status_code in gitlab.const.NO_JSON_RESPONSE_CODES:
1114
1094
  return result
@@ -1141,7 +1121,7 @@ class Gitlab:
1141
1121
  @gitlab.exceptions.on_http_error(gitlab.exceptions.GitlabSearchError)
1142
1122
  def search(
1143
1123
  self, scope: str, search: str, **kwargs: Any
1144
- ) -> Union["GitlabList", List[Dict[str, Any]]]:
1124
+ ) -> GitlabList | list[dict[str, Any]]:
1145
1125
  """Search GitLab resources matching the provided string.'
1146
1126
 
1147
1127
  Args:
@@ -1171,7 +1151,7 @@ class GitlabList:
1171
1151
  self,
1172
1152
  gl: Gitlab,
1173
1153
  url: str,
1174
- query_data: Dict[str, Any],
1154
+ query_data: dict[str, Any],
1175
1155
  get_next: bool = True,
1176
1156
  **kwargs: Any,
1177
1157
  ) -> None:
@@ -1187,7 +1167,7 @@ class GitlabList:
1187
1167
  self._kwargs.pop("query_parameters", None)
1188
1168
 
1189
1169
  def _query(
1190
- self, url: str, query_data: Optional[Dict[str, Any]] = None, **kwargs: Any
1170
+ self, url: str, query_data: dict[str, Any] | None = None, **kwargs: Any
1191
1171
  ) -> None:
1192
1172
  query_data = query_data or {}
1193
1173
  result = self._gl.http_request("get", url, query_data=query_data, **kwargs)
@@ -1197,15 +1177,15 @@ class GitlabList:
1197
1177
  next_url = None
1198
1178
 
1199
1179
  self._next_url = self._gl._check_url(next_url)
1200
- self._current_page: Optional[str] = result.headers.get("X-Page")
1201
- self._prev_page: Optional[str] = result.headers.get("X-Prev-Page")
1202
- self._next_page: Optional[str] = result.headers.get("X-Next-Page")
1203
- self._per_page: Optional[str] = result.headers.get("X-Per-Page")
1204
- self._total_pages: Optional[str] = result.headers.get("X-Total-Pages")
1205
- self._total: Optional[str] = result.headers.get("X-Total")
1180
+ self._current_page: str | None = result.headers.get("X-Page")
1181
+ self._prev_page: str | None = result.headers.get("X-Prev-Page")
1182
+ self._next_page: str | None = result.headers.get("X-Next-Page")
1183
+ self._per_page: str | None = result.headers.get("X-Per-Page")
1184
+ self._total_pages: str | None = result.headers.get("X-Total-Pages")
1185
+ self._total: str | None = result.headers.get("X-Total")
1206
1186
 
1207
1187
  try:
1208
- self._data: List[Dict[str, Any]] = result.json()
1188
+ self._data: list[dict[str, Any]] = result.json()
1209
1189
  except Exception as e:
1210
1190
  raise gitlab.exceptions.GitlabParsingError(
1211
1191
  error_message="Failed to parse the server message"
@@ -1221,7 +1201,7 @@ class GitlabList:
1221
1201
  return int(self._current_page)
1222
1202
 
1223
1203
  @property
1224
- def prev_page(self) -> Optional[int]:
1204
+ def prev_page(self) -> int | None:
1225
1205
  """The previous page number.
1226
1206
 
1227
1207
  If None, the current page is the first.
@@ -1229,7 +1209,7 @@ class GitlabList:
1229
1209
  return int(self._prev_page) if self._prev_page else None
1230
1210
 
1231
1211
  @property
1232
- def next_page(self) -> Optional[int]:
1212
+ def next_page(self) -> int | None:
1233
1213
  """The next page number.
1234
1214
 
1235
1215
  If None, the current page is the last.
@@ -1237,7 +1217,7 @@ class GitlabList:
1237
1217
  return int(self._next_page) if self._next_page else None
1238
1218
 
1239
1219
  @property
1240
- def per_page(self) -> Optional[int]:
1220
+ def per_page(self) -> int | None:
1241
1221
  """The number of items per page."""
1242
1222
  return int(self._per_page) if self._per_page is not None else None
1243
1223
 
@@ -1245,20 +1225,20 @@ class GitlabList:
1245
1225
  # the headers 'x-total-pages' and 'x-total'. In those cases we return None.
1246
1226
  # https://docs.gitlab.com/ee/user/gitlab_com/index.html#pagination-response-headers
1247
1227
  @property
1248
- def total_pages(self) -> Optional[int]:
1228
+ def total_pages(self) -> int | None:
1249
1229
  """The total number of pages."""
1250
1230
  if self._total_pages is not None:
1251
1231
  return int(self._total_pages)
1252
1232
  return None
1253
1233
 
1254
1234
  @property
1255
- def total(self) -> Optional[int]:
1235
+ def total(self) -> int | None:
1256
1236
  """The total number of items."""
1257
1237
  if self._total is not None:
1258
1238
  return int(self._total)
1259
1239
  return None
1260
1240
 
1261
- def __iter__(self) -> "GitlabList":
1241
+ def __iter__(self) -> GitlabList:
1262
1242
  return self
1263
1243
 
1264
1244
  def __len__(self) -> int:
@@ -1266,10 +1246,10 @@ class GitlabList:
1266
1246
  return 0
1267
1247
  return int(self._total)
1268
1248
 
1269
- def __next__(self) -> Dict[str, Any]:
1249
+ def __next__(self) -> dict[str, Any]:
1270
1250
  return self.next()
1271
1251
 
1272
- def next(self) -> Dict[str, Any]:
1252
+ def next(self) -> dict[str, Any]:
1273
1253
  try:
1274
1254
  item = self._data[self._current]
1275
1255
  self._current += 1
@@ -1287,11 +1267,11 @@ class GitlabList:
1287
1267
  class _BaseGraphQL:
1288
1268
  def __init__(
1289
1269
  self,
1290
- url: Optional[str] = None,
1270
+ url: str | None = None,
1291
1271
  *,
1292
- token: Optional[str] = None,
1293
- ssl_verify: Union[bool, str] = True,
1294
- timeout: Optional[float] = None,
1272
+ token: str | None = None,
1273
+ ssl_verify: bool | str = True,
1274
+ timeout: float | None = None,
1295
1275
  user_agent: str = gitlab.const.USER_AGENT,
1296
1276
  fetch_schema_from_transport: bool = False,
1297
1277
  max_retries: int = 10,
@@ -1316,7 +1296,7 @@ class _BaseGraphQL:
1316
1296
  self._client_opts = self._get_client_opts()
1317
1297
  self._fetch_schema_from_transport = fetch_schema_from_transport
1318
1298
 
1319
- def _get_client_opts(self) -> Dict[str, Any]:
1299
+ def _get_client_opts(self) -> dict[str, Any]:
1320
1300
  headers = {"User-Agent": self._user_agent}
1321
1301
 
1322
1302
  if self._token:
@@ -1332,12 +1312,12 @@ class _BaseGraphQL:
1332
1312
  class GraphQL(_BaseGraphQL):
1333
1313
  def __init__(
1334
1314
  self,
1335
- url: Optional[str] = None,
1315
+ url: str | None = None,
1336
1316
  *,
1337
- token: Optional[str] = None,
1338
- ssl_verify: Union[bool, str] = True,
1339
- client: Optional[httpx.Client] = None,
1340
- timeout: Optional[float] = None,
1317
+ token: str | None = None,
1318
+ ssl_verify: bool | str = True,
1319
+ client: httpx.Client | None = None,
1320
+ timeout: float | None = None,
1341
1321
  user_agent: str = gitlab.const.USER_AGENT,
1342
1322
  fetch_schema_from_transport: bool = False,
1343
1323
  max_retries: int = 10,
@@ -1364,15 +1344,13 @@ class GraphQL(_BaseGraphQL):
1364
1344
  )
1365
1345
  self._gql = gql.gql
1366
1346
 
1367
- def __enter__(self) -> "GraphQL":
1347
+ def __enter__(self) -> GraphQL:
1368
1348
  return self
1369
1349
 
1370
1350
  def __exit__(self, *args: Any) -> None:
1371
1351
  self._http_client.close()
1372
1352
 
1373
- def execute(
1374
- self, request: Union[str, graphql.Source], *args: Any, **kwargs: Any
1375
- ) -> Any:
1353
+ def execute(self, request: str | graphql.Source, *args: Any, **kwargs: Any) -> Any:
1376
1354
  parsed_document = self._gql(request)
1377
1355
  retry = utils.Retry(
1378
1356
  max_retries=self._max_retries,
@@ -1391,13 +1369,11 @@ class GraphQL(_BaseGraphQL):
1391
1369
 
1392
1370
  if e.code == 401:
1393
1371
  raise gitlab.exceptions.GitlabAuthenticationError(
1394
- response_code=e.code,
1395
- error_message=str(e),
1372
+ response_code=e.code, error_message=str(e)
1396
1373
  )
1397
1374
 
1398
1375
  raise gitlab.exceptions.GitlabHttpError(
1399
- response_code=e.code,
1400
- error_message=str(e),
1376
+ response_code=e.code, error_message=str(e)
1401
1377
  )
1402
1378
 
1403
1379
  return result
@@ -1406,12 +1382,12 @@ class GraphQL(_BaseGraphQL):
1406
1382
  class AsyncGraphQL(_BaseGraphQL):
1407
1383
  def __init__(
1408
1384
  self,
1409
- url: Optional[str] = None,
1385
+ url: str | None = None,
1410
1386
  *,
1411
- token: Optional[str] = None,
1412
- ssl_verify: Union[bool, str] = True,
1413
- client: Optional[httpx.AsyncClient] = None,
1414
- timeout: Optional[float] = None,
1387
+ token: str | None = None,
1388
+ ssl_verify: bool | str = True,
1389
+ client: httpx.AsyncClient | None = None,
1390
+ timeout: float | None = None,
1415
1391
  user_agent: str = gitlab.const.USER_AGENT,
1416
1392
  fetch_schema_from_transport: bool = False,
1417
1393
  max_retries: int = 10,
@@ -1438,14 +1414,14 @@ class AsyncGraphQL(_BaseGraphQL):
1438
1414
  )
1439
1415
  self._gql = gql.gql
1440
1416
 
1441
- async def __aenter__(self) -> "AsyncGraphQL":
1417
+ async def __aenter__(self) -> AsyncGraphQL:
1442
1418
  return self
1443
1419
 
1444
1420
  async def __aexit__(self, *args: Any) -> None:
1445
1421
  await self._http_client.aclose()
1446
1422
 
1447
1423
  async def execute(
1448
- self, request: Union[str, graphql.Source], *args: Any, **kwargs: Any
1424
+ self, request: str | graphql.Source, *args: Any, **kwargs: Any
1449
1425
  ) -> Any:
1450
1426
  parsed_document = self._gql(request)
1451
1427
  retry = utils.Retry(
@@ -1467,13 +1443,11 @@ class AsyncGraphQL(_BaseGraphQL):
1467
1443
 
1468
1444
  if e.code == 401:
1469
1445
  raise gitlab.exceptions.GitlabAuthenticationError(
1470
- response_code=e.code,
1471
- error_message=str(e),
1446
+ response_code=e.code, error_message=str(e)
1472
1447
  )
1473
1448
 
1474
1449
  raise gitlab.exceptions.GitlabHttpError(
1475
- response_code=e.code,
1476
- error_message=str(e),
1450
+ response_code=e.code, error_message=str(e)
1477
1451
  )
1478
1452
 
1479
1453
  return result
gitlab/config.py CHANGED
@@ -1,14 +1,15 @@
1
+ from __future__ import annotations
2
+
1
3
  import configparser
2
4
  import os
3
5
  import shlex
4
6
  import subprocess
5
7
  from os.path import expanduser, expandvars
6
8
  from pathlib import Path
7
- from typing import List, Optional, Union
8
9
 
9
10
  from gitlab.const import USER_AGENT
10
11
 
11
- _DEFAULT_FILES: List[str] = [
12
+ _DEFAULT_FILES: list[str] = [
12
13
  "/etc/python-gitlab.cfg",
13
14
  str(Path.home() / ".python-gitlab.cfg"),
14
15
  ]
@@ -20,14 +21,12 @@ HELPER_ATTRIBUTES = ["job_token", "http_password", "private_token", "oauth_token
20
21
  _CONFIG_PARSER_ERRORS = (configparser.NoOptionError, configparser.NoSectionError)
21
22
 
22
23
 
23
- def _resolve_file(filepath: Union[Path, str]) -> str:
24
+ def _resolve_file(filepath: Path | str) -> str:
24
25
  resolved = Path(filepath).resolve(strict=True)
25
26
  return str(resolved)
26
27
 
27
28
 
28
- def _get_config_files(
29
- config_files: Optional[List[str]] = None,
30
- ) -> Union[str, List[str]]:
29
+ def _get_config_files(config_files: list[str] | None = None) -> str | list[str]:
31
30
  """
32
31
  Return resolved path(s) to config files if they exist, with precedence:
33
32
  1. Files passed in config_files
@@ -90,23 +89,23 @@ class GitlabConfigHelperError(ConfigError):
90
89
 
91
90
  class GitlabConfigParser:
92
91
  def __init__(
93
- self, gitlab_id: Optional[str] = None, config_files: Optional[List[str]] = None
92
+ self, gitlab_id: str | None = None, config_files: list[str] | None = None
94
93
  ) -> None:
95
94
  self.gitlab_id = gitlab_id
96
- self.http_username: Optional[str] = None
97
- self.http_password: Optional[str] = None
98
- self.job_token: Optional[str] = None
99
- self.oauth_token: Optional[str] = None
100
- self.private_token: Optional[str] = None
95
+ self.http_username: str | None = None
96
+ self.http_password: str | None = None
97
+ self.job_token: str | None = None
98
+ self.oauth_token: str | None = None
99
+ self.private_token: str | None = None
101
100
 
102
101
  self.api_version: str = "4"
103
- self.order_by: Optional[str] = None
104
- self.pagination: Optional[str] = None
105
- self.per_page: Optional[int] = None
102
+ self.order_by: str | None = None
103
+ self.pagination: str | None = None
104
+ self.per_page: int | None = None
106
105
  self.retry_transient_errors: bool = False
107
- self.ssl_verify: Union[bool, str] = True
106
+ self.ssl_verify: bool | str = True
108
107
  self.timeout: int = 60
109
- self.url: Optional[str] = None
108
+ self.url: str | None = None
110
109
  self.user_agent: str = USER_AGENT
111
110
  self.keep_base_url: bool = False
112
111