|
25 | 25 | import gitlab.exceptions
|
26 | 26 | from gitlab import _backends, utils
|
27 | 27 |
|
| 28 | +try: |
| 29 | + import gql |
| 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 @@ def __init__(
|
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 @@ def _get_session_opts(self) -> Dict[str, Any]:
|
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 |
|
@@ -1296,3 +1296,62 @@ def next(self) -> Dict[str, Any]:
|
1296 | 1296 | return self.next()
|
1297 | 1297 |
|
1298 | 1298 | raise StopIteration
|
| 1299 | + |
| 1300 | + |
| 1301 | +class GraphQL: |
| 1302 | + def __init__( |
| 1303 | + self, |
| 1304 | + url: Optional[str] = None, |
| 1305 | + *, |
| 1306 | + token: Optional[str] = None, |
| 1307 | + ssl_verify: Union[bool, str] = True, |
| 1308 | + client: Optional[httpx.Client] = None, |
| 1309 | + timeout: Optional[float] = None, |
| 1310 | + user_agent: str = gitlab.const.USER_AGENT, |
| 1311 | + fetch_schema_from_transport: bool = False, |
| 1312 | + ) -> None: |
| 1313 | + if not _GQL_INSTALLED: |
| 1314 | + raise ImportError( |
| 1315 | + "The GraphQL client could not be initialized because " |
| 1316 | + "the gql dependencies are not installed. " |
| 1317 | + "Install them with 'pip install python-gitlab[graphql]'" |
| 1318 | + ) |
| 1319 | + self._base_url = utils.get_base_url(url) |
| 1320 | + self._timeout = timeout |
| 1321 | + self._token = token |
| 1322 | + self._url = f"{self._base_url}/api/graphql" |
| 1323 | + self._user_agent = user_agent |
| 1324 | + self._ssl_verify = ssl_verify |
| 1325 | + |
| 1326 | + opts = self._get_client_opts() |
| 1327 | + self._http_client = client or httpx.Client(**opts) |
| 1328 | + self._transport = GitlabTransport(self._url, client=self._http_client) |
| 1329 | + self._client = gql.Client( |
| 1330 | + transport=self._transport, |
| 1331 | + fetch_schema_from_transport=fetch_schema_from_transport, |
| 1332 | + ) |
| 1333 | + self._gql = gql.gql |
| 1334 | + |
| 1335 | + def __enter__(self) -> "GraphQL": |
| 1336 | + return self |
| 1337 | + |
| 1338 | + def __exit__(self, *args: Any) -> None: |
| 1339 | + self._http_client.close() |
| 1340 | + |
| 1341 | + def _get_client_opts(self) -> Dict[str, Any]: |
| 1342 | + headers = {"User-Agent": self._user_agent} |
| 1343 | + |
| 1344 | + if self._token: |
| 1345 | + headers["Authorization"] = f"Bearer {self._token}" |
| 1346 | + |
| 1347 | + return { |
| 1348 | + "headers": headers, |
| 1349 | + "timeout": self._timeout, |
| 1350 | + "verify": self._ssl_verify, |
| 1351 | + } |
| 1352 | + |
| 1353 | + def execute( |
| 1354 | + self, request: Union[str, graphql.Source], *args: Any, **kwargs: Any |
| 1355 | + ) -> Any: |
| 1356 | + parsed_document = self._gql(request) |
| 1357 | + return self._client.execute(parsed_document, *args, **kwargs) |
0 commit comments