python-gitlab 4.9.0__py3-none-any.whl → 4.11.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.
gitlab/__init__.py CHANGED
@@ -27,7 +27,7 @@ from gitlab._version import ( # noqa: F401
27
27
  __title__,
28
28
  __version__,
29
29
  )
30
- from gitlab.client import Gitlab, GitlabList # noqa: F401
30
+ from gitlab.client import Gitlab, GitlabList, GraphQL # noqa: F401
31
31
  from gitlab.exceptions import * # noqa: F401,F403
32
32
 
33
33
  warnings.filterwarnings("default", category=DeprecationWarning, module="^gitlab")
@@ -42,5 +42,6 @@ __all__ = [
42
42
  "__version__",
43
43
  "Gitlab",
44
44
  "GitlabList",
45
+ "GraphQL",
45
46
  ]
46
47
  __all__.extend(gitlab.exceptions.__all__)
@@ -0,0 +1,24 @@
1
+ from typing import Any
2
+
3
+ import httpx
4
+ from gql.transport.httpx import HTTPXTransport
5
+
6
+
7
+ class GitlabTransport(HTTPXTransport):
8
+ """A gql httpx transport that reuses an existing httpx.Client.
9
+ By default, gql's transports do not have a keep-alive session
10
+ and do not enable providing your own session that's kept open.
11
+ This transport lets us provide and close our session on our own
12
+ and provide additional auth.
13
+ For details, see https://github.com/graphql-python/gql/issues/91.
14
+ """
15
+
16
+ def __init__(self, *args: Any, client: httpx.Client, **kwargs: Any):
17
+ super().__init__(*args, **kwargs)
18
+ self.client = client
19
+
20
+ def connect(self) -> None:
21
+ pass
22
+
23
+ def close(self) -> None:
24
+ pass
gitlab/_version.py CHANGED
@@ -3,4 +3,4 @@ __copyright__ = "Copyright 2013-2019 Gauvain Pocentek, 2019-2023 python-gitlab t
3
3
  __email__ = "gauvainpocentek@gmail.com"
4
4
  __license__ = "LGPL3"
5
5
  __title__ = "python-gitlab"
6
- __version__ = "4.9.0"
6
+ __version__ = "4.11.0"
gitlab/client.py CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  import os
4
4
  import re
5
- import time
6
5
  from typing import (
7
6
  Any,
8
7
  BinaryIO,
@@ -25,6 +24,19 @@ import gitlab.const
25
24
  import gitlab.exceptions
26
25
  from gitlab import _backends, utils
27
26
 
27
+ try:
28
+ import gql
29
+ import gql.transport.exceptions
30
+ import graphql
31
+ import httpx
32
+
33
+ from ._backends.graphql import GitlabTransport
34
+
35
+ _GQL_INSTALLED = True
36
+ except ImportError: # pragma: no cover
37
+ _GQL_INSTALLED = False
38
+
39
+
28
40
  REDIRECT_MSG = (
29
41
  "python-gitlab detected a {status_code} ({reason!r}) redirection. You must update "
30
42
  "your GitLab URL to the correct URL to avoid issues. The redirection was from: "
@@ -89,7 +101,7 @@ class Gitlab:
89
101
  self._api_version = str(api_version)
90
102
  self._server_version: Optional[str] = None
91
103
  self._server_revision: Optional[str] = None
92
- self._base_url = self._get_base_url(url)
104
+ self._base_url = utils.get_base_url(url)
93
105
  self._url = f"{self._base_url}/api/v{api_version}"
94
106
  #: Timeout to use for requests to gitlab server
95
107
  self.timeout = timeout
@@ -557,18 +569,6 @@ class Gitlab:
557
569
  "verify": self.ssl_verify,
558
570
  }
559
571
 
560
- @staticmethod
561
- def _get_base_url(url: Optional[str] = None) -> str:
562
- """Return the base URL with the trailing slash stripped.
563
- If the URL is a Falsy value, return the default URL.
564
- Returns:
565
- The base URL
566
- """
567
- if not url:
568
- return gitlab.const.DEFAULT_URL
569
-
570
- return url.rstrip("/")
571
-
572
572
  def _build_url(self, path: str) -> str:
573
573
  """Returns the full url from path.
574
574
 
@@ -718,7 +718,12 @@ class Gitlab:
718
718
  send_data = self._backend.prepare_send_data(files, post_data, raw)
719
719
  opts["headers"]["Content-type"] = send_data.content_type
720
720
 
721
- cur_retries = 0
721
+ retry = utils.Retry(
722
+ max_retries=max_retries,
723
+ obey_rate_limit=obey_rate_limit,
724
+ retry_transient_errors=retry_transient_errors,
725
+ )
726
+
722
727
  while True:
723
728
  try:
724
729
  result = self._backend.http_request(
@@ -733,14 +738,8 @@ class Gitlab:
733
738
  **opts,
734
739
  )
735
740
  except (requests.ConnectionError, requests.exceptions.ChunkedEncodingError):
736
- if retry_transient_errors and (
737
- max_retries == -1 or cur_retries < max_retries
738
- ):
739
- wait_time = 2**cur_retries * 0.1
740
- cur_retries += 1
741
- time.sleep(wait_time)
741
+ if retry.handle_retry():
742
742
  continue
743
-
744
743
  raise
745
744
 
746
745
  self._check_redirects(result.response)
@@ -748,31 +747,10 @@ class Gitlab:
748
747
  if 200 <= result.status_code < 300:
749
748
  return result.response
750
749
 
751
- def should_retry() -> bool:
752
- if result.status_code == 429 and obey_rate_limit:
753
- return True
754
-
755
- if not retry_transient_errors:
756
- return False
757
- if result.status_code in gitlab.const.RETRYABLE_TRANSIENT_ERROR_CODES:
758
- return True
759
- if result.status_code == 409 and "Resource lock" in result.reason:
760
- return True
761
-
762
- return False
763
-
764
- if should_retry():
765
- # Response headers documentation:
766
- # https://docs.gitlab.com/ee/user/admin_area/settings/user_and_ip_rate_limits.html#response-headers
767
- if max_retries == -1 or cur_retries < max_retries:
768
- wait_time = 2**cur_retries * 0.1
769
- if "Retry-After" in result.headers:
770
- wait_time = int(result.headers["Retry-After"])
771
- elif "RateLimit-Reset" in result.headers:
772
- wait_time = int(result.headers["RateLimit-Reset"]) - time.time()
773
- cur_retries += 1
774
- time.sleep(wait_time)
775
- continue
750
+ if retry.handle_retry_on_status(
751
+ result.status_code, result.headers, result.reason
752
+ ):
753
+ continue
776
754
 
777
755
  error_message = result.content
778
756
  try:
@@ -1296,3 +1274,94 @@ class GitlabList:
1296
1274
  return self.next()
1297
1275
 
1298
1276
  raise StopIteration
1277
+
1278
+
1279
+ class GraphQL:
1280
+ def __init__(
1281
+ self,
1282
+ url: Optional[str] = None,
1283
+ *,
1284
+ token: Optional[str] = None,
1285
+ ssl_verify: Union[bool, str] = True,
1286
+ client: Optional[httpx.Client] = None,
1287
+ timeout: Optional[float] = None,
1288
+ user_agent: str = gitlab.const.USER_AGENT,
1289
+ fetch_schema_from_transport: bool = False,
1290
+ max_retries: int = 10,
1291
+ obey_rate_limit: bool = True,
1292
+ retry_transient_errors: bool = False,
1293
+ ) -> None:
1294
+ if not _GQL_INSTALLED:
1295
+ raise ImportError(
1296
+ "The GraphQL client could not be initialized because "
1297
+ "the gql dependencies are not installed. "
1298
+ "Install them with 'pip install python-gitlab[graphql]'"
1299
+ )
1300
+ self._base_url = utils.get_base_url(url)
1301
+ self._timeout = timeout
1302
+ self._token = token
1303
+ self._url = f"{self._base_url}/api/graphql"
1304
+ self._user_agent = user_agent
1305
+ self._ssl_verify = ssl_verify
1306
+ self._max_retries = max_retries
1307
+ self._obey_rate_limit = obey_rate_limit
1308
+ self._retry_transient_errors = retry_transient_errors
1309
+
1310
+ opts = self._get_client_opts()
1311
+ self._http_client = client or httpx.Client(**opts)
1312
+ self._transport = GitlabTransport(self._url, client=self._http_client)
1313
+ self._client = gql.Client(
1314
+ transport=self._transport,
1315
+ fetch_schema_from_transport=fetch_schema_from_transport,
1316
+ )
1317
+ self._gql = gql.gql
1318
+
1319
+ def __enter__(self) -> "GraphQL":
1320
+ return self
1321
+
1322
+ def __exit__(self, *args: Any) -> None:
1323
+ self._http_client.close()
1324
+
1325
+ def _get_client_opts(self) -> Dict[str, Any]:
1326
+ headers = {"User-Agent": self._user_agent}
1327
+
1328
+ if self._token:
1329
+ headers["Authorization"] = f"Bearer {self._token}"
1330
+
1331
+ return {
1332
+ "headers": headers,
1333
+ "timeout": self._timeout,
1334
+ "verify": self._ssl_verify,
1335
+ }
1336
+
1337
+ def execute(
1338
+ self, request: Union[str, graphql.Source], *args: Any, **kwargs: Any
1339
+ ) -> Any:
1340
+ parsed_document = self._gql(request)
1341
+ retry = utils.Retry(
1342
+ max_retries=self._max_retries,
1343
+ obey_rate_limit=self._obey_rate_limit,
1344
+ retry_transient_errors=self._retry_transient_errors,
1345
+ )
1346
+
1347
+ while True:
1348
+ try:
1349
+ result = self._client.execute(parsed_document, *args, **kwargs)
1350
+ except gql.transport.exceptions.TransportServerError as e:
1351
+ if retry.handle_retry_on_status(
1352
+ status_code=e.code, headers=self._transport.response_headers
1353
+ ):
1354
+ continue
1355
+
1356
+ if e.code == 401:
1357
+ raise gitlab.exceptions.GitlabAuthenticationError(
1358
+ response_code=e.code,
1359
+ error_message=str(e),
1360
+ )
1361
+
1362
+ raise gitlab.exceptions.GitlabHttpError(
1363
+ response_code=e.code,
1364
+ error_message=str(e),
1365
+ )
1366
+
1367
+ return result
gitlab/exceptions.py CHANGED
@@ -316,6 +316,10 @@ class GitlabDeploymentApprovalError(GitlabOperationError):
316
316
  pass
317
317
 
318
318
 
319
+ class GitlabHookTestError(GitlabOperationError):
320
+ pass
321
+
322
+
319
323
  # For an explanation of how these type-hints work see:
320
324
  # https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
321
325
  #
@@ -370,6 +374,7 @@ __all__ = [
370
374
  "GitlabGetError",
371
375
  "GitlabGroupTransferError",
372
376
  "GitlabHeadError",
377
+ "GitlabHookTestError",
373
378
  "GitlabHousekeepingError",
374
379
  "GitlabHttpError",
375
380
  "GitlabImportError",
gitlab/utils.py CHANGED
@@ -2,14 +2,26 @@ import dataclasses
2
2
  import email.message
3
3
  import logging
4
4
  import pathlib
5
+ import time
5
6
  import traceback
6
7
  import urllib.parse
7
8
  import warnings
8
- from typing import Any, Callable, Dict, Iterator, Literal, Optional, Tuple, Type, Union
9
+ from typing import (
10
+ Any,
11
+ Callable,
12
+ Dict,
13
+ Iterator,
14
+ Literal,
15
+ MutableMapping,
16
+ Optional,
17
+ Tuple,
18
+ Type,
19
+ Union,
20
+ )
9
21
 
10
22
  import requests
11
23
 
12
- from gitlab import types
24
+ from gitlab import const, types
13
25
 
14
26
 
15
27
  class _StdoutStream:
@@ -17,6 +29,18 @@ class _StdoutStream:
17
29
  print(chunk)
18
30
 
19
31
 
32
+ def get_base_url(url: Optional[str] = None) -> str:
33
+ """Return the base URL with the trailing slash stripped.
34
+ If the URL is a Falsy value, return the default URL.
35
+ Returns:
36
+ The base URL
37
+ """
38
+ if not url:
39
+ return const.DEFAULT_URL
40
+
41
+ return url.rstrip("/")
42
+
43
+
20
44
  def get_content_type(content_type: Optional[str]) -> str:
21
45
  message = email.message.Message()
22
46
  if content_type is not None:
@@ -73,6 +97,71 @@ def response_content(
73
97
  return None
74
98
 
75
99
 
100
+ class Retry:
101
+ def __init__(
102
+ self,
103
+ max_retries: int,
104
+ obey_rate_limit: Optional[bool] = True,
105
+ retry_transient_errors: Optional[bool] = False,
106
+ ) -> None:
107
+ self.cur_retries = 0
108
+ self.max_retries = max_retries
109
+ self.obey_rate_limit = obey_rate_limit
110
+ self.retry_transient_errors = retry_transient_errors
111
+
112
+ def _retryable_status_code(
113
+ self, status_code: Optional[int], reason: str = ""
114
+ ) -> bool:
115
+ if status_code == 429 and self.obey_rate_limit:
116
+ return True
117
+
118
+ if not self.retry_transient_errors:
119
+ return False
120
+ if status_code in const.RETRYABLE_TRANSIENT_ERROR_CODES:
121
+ return True
122
+ if status_code == 409 and "Resource lock" in reason:
123
+ return True
124
+
125
+ return False
126
+
127
+ def handle_retry_on_status(
128
+ self,
129
+ status_code: Optional[int],
130
+ headers: Optional[MutableMapping[str, str]] = None,
131
+ reason: str = "",
132
+ ) -> bool:
133
+ if not self._retryable_status_code(status_code, reason):
134
+ return False
135
+
136
+ if headers is None:
137
+ headers = {}
138
+
139
+ # Response headers documentation:
140
+ # https://docs.gitlab.com/ee/user/admin_area/settings/user_and_ip_rate_limits.html#response-headers
141
+ if self.max_retries == -1 or self.cur_retries < self.max_retries:
142
+ wait_time = 2**self.cur_retries * 0.1
143
+ if "Retry-After" in headers:
144
+ wait_time = int(headers["Retry-After"])
145
+ elif "RateLimit-Reset" in headers:
146
+ wait_time = int(headers["RateLimit-Reset"]) - time.time()
147
+ self.cur_retries += 1
148
+ time.sleep(wait_time)
149
+ return True
150
+
151
+ return False
152
+
153
+ def handle_retry(self) -> bool:
154
+ if self.retry_transient_errors and (
155
+ self.max_retries == -1 or self.cur_retries < self.max_retries
156
+ ):
157
+ wait_time = 2**self.cur_retries * 0.1
158
+ self.cur_retries += 1
159
+ time.sleep(wait_time)
160
+ return True
161
+
162
+ return False
163
+
164
+
76
165
  def _transform_types(
77
166
  data: Dict[str, Any],
78
167
  custom_types: Dict[str, Any],
@@ -1,5 +1,6 @@
1
1
  from typing import Any, cast, Union
2
2
 
3
+ from gitlab import exceptions as exc
3
4
  from gitlab.base import RESTManager, RESTObject
4
5
  from gitlab.mixins import CRUDMixin, NoUpdateMixin, ObjectDeleteMixin, SaveMixin
5
6
  from gitlab.types import RequiredOptional
@@ -31,6 +32,20 @@ class HookManager(NoUpdateMixin, RESTManager):
31
32
  class ProjectHook(SaveMixin, ObjectDeleteMixin, RESTObject):
32
33
  _repr_attr = "url"
33
34
 
35
+ @exc.on_http_error(exc.GitlabHookTestError)
36
+ def test(self, trigger: str) -> None:
37
+ """
38
+ Test a Project Hook
39
+
40
+ Args:
41
+ trigger: Type of trigger event to test
42
+
43
+ Raises:
44
+ GitlabHookTestError: If the hook test attempt failed
45
+ """
46
+ path = f"{self.manager.path}/{self.encoded_id}/test/{trigger}"
47
+ self.manager.gitlab.http_post(path)
48
+
34
49
 
35
50
  class ProjectHookManager(CRUDMixin, RESTManager):
36
51
  _path = "/projects/{project_id}/hooks"
@@ -78,6 +93,20 @@ class ProjectHookManager(CRUDMixin, RESTManager):
78
93
  class GroupHook(SaveMixin, ObjectDeleteMixin, RESTObject):
79
94
  _repr_attr = "url"
80
95
 
96
+ @exc.on_http_error(exc.GitlabHookTestError)
97
+ def test(self, trigger: str) -> None:
98
+ """
99
+ Test a Group Hook
100
+
101
+ Args:
102
+ trigger: Type of trigger event to test
103
+
104
+ Raises:
105
+ GitlabHookTestError: If the hook test attempt failed
106
+ """
107
+ path = f"{self.manager.path}/{self.encoded_id}/test/{trigger}"
108
+ self.manager.gitlab.http_post(path)
109
+
81
110
 
82
111
  class GroupHookManager(CRUDMixin, RESTManager):
83
112
  _path = "/groups/{group_id}/hooks"
@@ -37,8 +37,9 @@ class GroupMemberManager(CRUDMixin, RESTManager):
37
37
  _obj_cls = GroupMember
38
38
  _from_parent_attrs = {"group_id": "id"}
39
39
  _create_attrs = RequiredOptional(
40
- required=("access_level", "user_id"),
40
+ required=("access_level",),
41
41
  optional=("expires_at", "tasks_to_be_done"),
42
+ exclusive=("username", "user_id"),
42
43
  )
43
44
  _update_attrs = RequiredOptional(
44
45
  required=("access_level",), optional=("expires_at",)
@@ -101,8 +102,9 @@ class ProjectMemberManager(CRUDMixin, RESTManager):
101
102
  _obj_cls = ProjectMember
102
103
  _from_parent_attrs = {"project_id": "id"}
103
104
  _create_attrs = RequiredOptional(
104
- required=("access_level", "user_id"),
105
+ required=("access_level",),
105
106
  optional=("expires_at", "tasks_to_be_done"),
107
+ exclusive=("username", "user_id"),
106
108
  )
107
109
  _update_attrs = RequiredOptional(
108
110
  required=("access_level",), optional=("expires_at",)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-gitlab
3
- Version: 4.9.0
3
+ Version: 4.11.0
4
4
  Summary: A python wrapper for the GitLab API
5
5
  Author-email: Gauvain Pocentek <gauvain@pocentek.net>
6
6
  Maintainer-email: John Villalovos <john@sodarock.com>, Max Wittig <max.wittig@siemens.com>, Nejc Habjan <nejc.habjan@siemens.com>, Roger Meier <r.meier@siemens.com>
@@ -32,6 +32,8 @@ Requires-Dist: requests >=2.32.0
32
32
  Requires-Dist: requests-toolbelt >=1.0.0
33
33
  Provides-Extra: autocompletion
34
34
  Requires-Dist: argcomplete <3,>=1.10.0 ; extra == 'autocompletion'
35
+ Provides-Extra: graphql
36
+ Requires-Dist: gql[httpx] <4,>=3.5.0 ; extra == 'graphql'
35
37
  Provides-Extra: yaml
36
38
  Requires-Dist: PyYaml >=6.0.1 ; extra == 'yaml'
37
39
 
@@ -1,17 +1,18 @@
1
- gitlab/__init__.py,sha256=bd8BSLyUUjtHMKtzmf-T5855W6FUHcuhIwx2hNu0w2o,1382
1
+ gitlab/__init__.py,sha256=DlY_IEbIbeTJnMfkcl4866XbJ_50UiaE4yI0PwOq36E,1406
2
2
  gitlab/__main__.py,sha256=HTesNl0UAU6mPb9EXWkTKMy6Q6pAUxGi3iPnDHTE2uE,68
3
- gitlab/_version.py,sha256=8WblZEmwtyX2c4VXUoXvIs7Z3e6CE5dlH-tV99io0nc,249
3
+ gitlab/_version.py,sha256=_ZHsoVye-Iaog0jEDXMthyNXtQA9GiK4pyR3vDJgPVM,250
4
4
  gitlab/base.py,sha256=5cotawlHD01Vw88aN4o7wNIhDyk_bmcwubX4mbOpnVo,13780
5
5
  gitlab/cli.py,sha256=d3-LtZuA1Fgon5wZWn4c3E70fTIu4mM4Juyhh3F8EBs,12416
6
- gitlab/client.py,sha256=fPezDHNi4kJxzGxGeDWOWsKmKy76wVR4-fteCgDrY4I,49296
6
+ gitlab/client.py,sha256=BCglR-5hrEQVEc7FdsfAT3u4_sIYQBkbdaEj2feDzPo,51181
7
7
  gitlab/config.py,sha256=T1DgUXD0-MN2qNszrv-SO5d4uy0FITnNN0vWJgOt2yo,9088
8
8
  gitlab/const.py,sha256=rtPU-fxVSOvgpueoQVTvZGQp6iAZ-aa3nsY4RcSs_M4,5352
9
- gitlab/exceptions.py,sha256=Ruz9LusKMRu6SyV1vXpOu_UTCi3XU64A9BeHsqKASOw,8303
9
+ gitlab/exceptions.py,sha256=VOQftPzEq5mpVj6vke7z6Xe4S7Yf_rDTab0lNHqf3AY,8390
10
10
  gitlab/mixins.py,sha256=7iPlzqGmd5Ew2RLzRzRWsJ4r8Bn6wteUj791BJrjtXc,36645
11
11
  gitlab/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  gitlab/types.py,sha256=lepiiI_YOr94B4koqIHuY70tszZC_X3YW4lDvbadbI8,3312
13
- gitlab/utils.py,sha256=9WwqvrpYkKZCXFlLZmbEiVvbGWv3ubmi05HiABhwGSA,6569
13
+ gitlab/utils.py,sha256=3OngV45Gb4UO2GR-6-kXax1Ghdw6bpyRdUC2cHpyCSw,9027
14
14
  gitlab/_backends/__init__.py,sha256=WalQZRIDzw19FuNxraG7fvck6ddg4cdNd3bi53QKvZM,392
15
+ gitlab/_backends/graphql.py,sha256=SiGEfqqBqRey_EhozhF1pWFO81c_VVKdM50XvCQ4PZc,737
15
16
  gitlab/_backends/protocol.py,sha256=m5qSz1o3i0H4XJCWnqx0wIFilOIU9cKxzFsYxLL6Big,842
16
17
  gitlab/_backends/requests_backend.py,sha256=CrSDTfkvi17dT4kTU8R3qQFBNCPJqEfBJq4gJ2GXleA,5534
17
18
  gitlab/v4/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -48,7 +49,7 @@ gitlab/v4/objects/files.py,sha256=9M7pocu_n9JDRAPu5BqIt398emYD5WVnGh3wAJinPX8,10
48
49
  gitlab/v4/objects/geo_nodes.py,sha256=tD9piU7OIZgbNQRUeLTFPtAJ6PVL_SI6tR_zh6Tm2M8,3686
49
50
  gitlab/v4/objects/group_access_tokens.py,sha256=EijY0sfsp0Gtx_q4JLBeLL3jphx5b_6-nTzKxV272jc,1023
50
51
  gitlab/v4/objects/groups.py,sha256=YxOeaRYUjhu8PicCicVT7Eua04YuyOLAc8J13V7r9Gg,15958
51
- gitlab/v4/objects/hooks.py,sha256=1uDYi09GOmgR6t7gVT06CeMGL0ZZ1N5swz1KMtsybDk,3598
52
+ gitlab/v4/objects/hooks.py,sha256=ig8qyC6ZWpZXqcGYCSS7LVvTpD1xnLkNNtfJAOXeYv8,4445
52
53
  gitlab/v4/objects/integrations.py,sha256=QWl5ZnE1oivt4ho9qJa_o268ORdaW35D4klBRy1jUyQ,9229
53
54
  gitlab/v4/objects/invitations.py,sha256=ya9x7xhL1oSbx-FLJud-lHKmbYQoTplZlAbjsZip2CI,2734
54
55
  gitlab/v4/objects/issues.py,sha256=kxciXrLGxCsevJ2eoxpDdMLnw1kF4VrQTy4YB4AoN1U,10393
@@ -58,7 +59,7 @@ gitlab/v4/objects/jobs.py,sha256=g7l5dA6-99tyLDoohjJ_xZvGyMbeytn4L9T-h78NQaE,914
58
59
  gitlab/v4/objects/keys.py,sha256=IclYGSzcVEZPIhDdIz-p16rvb68FnBTgAf1cWCXWjkY,882
59
60
  gitlab/v4/objects/labels.py,sha256=JvOciJ6V76pF9HuJp5OT_Ykq8oqaa6ItxvpKf3hiEzs,4736
60
61
  gitlab/v4/objects/ldap.py,sha256=adpkdfk7VBjshuh8SpCsc77Pax4QgqCx1N12CuzitDE,1662
61
- gitlab/v4/objects/members.py,sha256=knzhMYLqaKWAUbTX4QAowMmtMirU2Kizt85zZRcpgmA,3836
62
+ gitlab/v4/objects/members.py,sha256=YJO9MaqlCSUnozHIlI7MfSlcWTju4xRmW8QIlEiBmok,3902
62
63
  gitlab/v4/objects/merge_request_approvals.py,sha256=oPZFd4AUtrAVhBTa0iM4krNkk2UTNOTw_MWlEWo2HAQ,6400
63
64
  gitlab/v4/objects/merge_requests.py,sha256=tpFCMmTVWyL9X7HtUoZuHJP4MVZUz1kk9-Bv-SbnwfU,17422
64
65
  gitlab/v4/objects/merge_trains.py,sha256=e0Gp2Ri75elcG_r9w8qxdrcWW_YiebPRwUYIH5od8kc,422
@@ -94,10 +95,10 @@ gitlab/v4/objects/triggers.py,sha256=UAERq_C-QdPBbBQPHLh5IfhpkdDeIxdnVGPHfu9Qy5Y
94
95
  gitlab/v4/objects/users.py,sha256=_gGrTwcE17jeoXIPgfFSv54jtF1_9C1R0Y0hhssTvXY,21381
95
96
  gitlab/v4/objects/variables.py,sha256=S0Vz32jEpUbo4J2js8gMPPTVpcy1ge5FYVHLiPz9c-A,2627
96
97
  gitlab/v4/objects/wikis.py,sha256=JtI1cQqZV1_PRfKVlQRMh4LZjdxEfi9T2VuFYv6PrV8,1775
97
- python_gitlab-4.9.0.dist-info/AUTHORS,sha256=Z0P61GJSVnp7iFbRcMezhx3f4zMyPkVmG--TWaRo768,526
98
- python_gitlab-4.9.0.dist-info/COPYING,sha256=2n6rt7r999OuXp8iOqW9we7ORaxWncIbOwN1ILRGR2g,7651
99
- python_gitlab-4.9.0.dist-info/METADATA,sha256=IRtLbkQzDvBZ5PfUV0aoYo8Z_AchFifHacjgnmBY7Ik,8228
100
- python_gitlab-4.9.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
101
- python_gitlab-4.9.0.dist-info/entry_points.txt,sha256=nhpKLLP_uQPFByn8UtE9zsvQQwa402t52o_Cw9IFXMo,43
102
- python_gitlab-4.9.0.dist-info/top_level.txt,sha256=MvIaP8p_Oaf4gO_hXmHkX-5y2deHLp1pe6tJR3ukQ6o,7
103
- python_gitlab-4.9.0.dist-info/RECORD,,
98
+ python_gitlab-4.11.0.dist-info/AUTHORS,sha256=Z0P61GJSVnp7iFbRcMezhx3f4zMyPkVmG--TWaRo768,526
99
+ python_gitlab-4.11.0.dist-info/COPYING,sha256=2n6rt7r999OuXp8iOqW9we7ORaxWncIbOwN1ILRGR2g,7651
100
+ python_gitlab-4.11.0.dist-info/METADATA,sha256=iSsCzBj4kepfxKWEmWopKZuOmm7aWrbIW_0aIr156Fg,8311
101
+ python_gitlab-4.11.0.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
102
+ python_gitlab-4.11.0.dist-info/entry_points.txt,sha256=nhpKLLP_uQPFByn8UtE9zsvQQwa402t52o_Cw9IFXMo,43
103
+ python_gitlab-4.11.0.dist-info/top_level.txt,sha256=MvIaP8p_Oaf4gO_hXmHkX-5y2deHLp1pe6tJR3ukQ6o,7
104
+ python_gitlab-4.11.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (74.1.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5