|
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