3232import graphql
3333import httpx
3434
35- from ._backends .graphql import GitlabTransport
35+ from ._backends .graphql import GitlabAsyncTransport , GitlabTransport
3636
3737_GQL_INSTALLED = True
3838except ImportError :# pragma: no cover
@@ -1278,14 +1278,13 @@ def next(self) -> Dict[str, Any]:
12781278raise StopIteration
12791279
12801280
1281- class GraphQL :
1281+ class _BaseGraphQL :
12821282def __init__ (
12831283self ,
12841284url :Optional [str ]= None ,
12851285* ,
12861286token :Optional [str ]= None ,
12871287ssl_verify :Union [bool ,str ]= True ,
1288- client :Optional [httpx .Client ]= None ,
12891288timeout :Optional [float ]= None ,
12901289user_agent :str = gitlab .const .USER_AGENT ,
12911290fetch_schema_from_transport :bool = False ,
@@ -1308,9 +1307,50 @@ def __init__(
13081307self ._max_retries = max_retries
13091308self ._obey_rate_limit = obey_rate_limit
13101309self ._retry_transient_errors = retry_transient_errors
1310+ self ._client_opts = self ._get_client_opts ()
1311+ self ._fetch_schema_from_transport = fetch_schema_from_transport
1312+
1313+ def _get_client_opts (self )-> Dict [str ,Any ]:
1314+ headers = {"User-Agent" :self ._user_agent }
1315+
1316+ if self ._token :
1317+ headers ["Authorization" ]= f"Bearer{ self ._token } "
1318+
1319+ return {
1320+ "headers" :headers ,
1321+ "timeout" :self ._timeout ,
1322+ "verify" :self ._ssl_verify ,
1323+ }
1324+
13111325
1312- opts = self ._get_client_opts ()
1313- self ._http_client = client or httpx .Client (** opts )
1326+ class GraphQL (_BaseGraphQL ):
1327+ def __init__ (
1328+ self ,
1329+ url :Optional [str ]= None ,
1330+ * ,
1331+ token :Optional [str ]= None ,
1332+ ssl_verify :Union [bool ,str ]= True ,
1333+ client :Optional [httpx .Client ]= None ,
1334+ timeout :Optional [float ]= None ,
1335+ user_agent :str = gitlab .const .USER_AGENT ,
1336+ fetch_schema_from_transport :bool = False ,
1337+ max_retries :int = 10 ,
1338+ obey_rate_limit :bool = True ,
1339+ retry_transient_errors :bool = False ,
1340+ )-> None :
1341+ super ().__init__ (
1342+ url = url ,
1343+ token = token ,
1344+ ssl_verify = ssl_verify ,
1345+ timeout = timeout ,
1346+ user_agent = user_agent ,
1347+ fetch_schema_from_transport = fetch_schema_from_transport ,
1348+ max_retries = max_retries ,
1349+ obey_rate_limit = obey_rate_limit ,
1350+ retry_transient_errors = retry_transient_errors ,
1351+ )
1352+
1353+ self ._http_client = client or httpx .Client (** self ._client_opts )
13141354self ._transport = GitlabTransport (self ._url ,client = self ._http_client )
13151355self ._client = gql .Client (
13161356transport = self ._transport ,
@@ -1324,19 +1364,81 @@ def __enter__(self) -> "GraphQL":
13241364def __exit__ (self ,* args :Any )-> None :
13251365self ._http_client .close ()
13261366
1327- def _get_client_opts (self )-> Dict [str ,Any ]:
1328- headers = {"User-Agent" :self ._user_agent }
1367+ def execute (
1368+ self ,request :Union [str ,graphql .Source ],* args :Any ,** kwargs :Any
1369+ )-> Any :
1370+ parsed_document = self ._gql (request )
1371+ retry = utils .Retry (
1372+ max_retries = self ._max_retries ,
1373+ obey_rate_limit = self ._obey_rate_limit ,
1374+ retry_transient_errors = self ._retry_transient_errors ,
1375+ )
13291376
1330- if self ._token :
1331- headers ["Authorization" ]= f"Bearer{ self ._token } "
1377+ while True :
1378+ try :
1379+ result = self ._client .execute (parsed_document ,* args ,** kwargs )
1380+ except gql .transport .exceptions .TransportServerError as e :
1381+ if retry .handle_retry_on_status (
1382+ status_code = e .code ,headers = self ._transport .response_headers
1383+ ):
1384+ continue
13321385
1333- return {
1334- "headers" : headers ,
1335- "timeout" : self . _timeout ,
1336- "verify" : self . _ssl_verify ,
1337- }
1386+ if e . code == 401 :
1387+ raise gitlab . exceptions . GitlabAuthenticationError (
1388+ response_code = e . code ,
1389+ error_message = str ( e ) ,
1390+ )
13381391
1339- def execute (
1392+ raise gitlab .exceptions .GitlabHttpError (
1393+ response_code = e .code ,
1394+ error_message = str (e ),
1395+ )
1396+
1397+ return result
1398+
1399+
1400+ class AsyncGraphQL (_BaseGraphQL ):
1401+ def __init__ (
1402+ self ,
1403+ url :Optional [str ]= None ,
1404+ * ,
1405+ token :Optional [str ]= None ,
1406+ ssl_verify :Union [bool ,str ]= True ,
1407+ client :Optional [httpx .AsyncClient ]= None ,
1408+ timeout :Optional [float ]= None ,
1409+ user_agent :str = gitlab .const .USER_AGENT ,
1410+ fetch_schema_from_transport :bool = False ,
1411+ max_retries :int = 10 ,
1412+ obey_rate_limit :bool = True ,
1413+ retry_transient_errors :bool = False ,
1414+ )-> None :
1415+ super ().__init__ (
1416+ url = url ,
1417+ token = token ,
1418+ ssl_verify = ssl_verify ,
1419+ timeout = timeout ,
1420+ user_agent = user_agent ,
1421+ fetch_schema_from_transport = fetch_schema_from_transport ,
1422+ max_retries = max_retries ,
1423+ obey_rate_limit = obey_rate_limit ,
1424+ retry_transient_errors = retry_transient_errors ,
1425+ )
1426+
1427+ self ._http_client = client or httpx .AsyncClient (** self ._client_opts )
1428+ self ._transport = GitlabAsyncTransport (self ._url ,client = self ._http_client )
1429+ self ._client = gql .Client (
1430+ transport = self ._transport ,
1431+ fetch_schema_from_transport = fetch_schema_from_transport ,
1432+ )
1433+ self ._gql = gql .gql
1434+
1435+ async def __aenter__ (self )-> "AsyncGraphQL" :
1436+ return self
1437+
1438+ async def __aexit__ (self ,* args :Any )-> None :
1439+ await self ._http_client .aclose ()
1440+
1441+ async def execute (
13401442self ,request :Union [str ,graphql .Source ],* args :Any ,** kwargs :Any
13411443 )-> Any :
13421444parsed_document = self ._gql (request )
@@ -1348,7 +1450,9 @@ def execute(
13481450
13491451while True :
13501452try :
1351- result = self ._client .execute (parsed_document ,* args ,** kwargs )
1453+ result = await self ._client .execute_async (
1454+ parsed_document ,* args ,** kwargs
1455+ )
13521456except gql .transport .exceptions .TransportServerError as e :
13531457if retry .handle_retry_on_status (
13541458status_code = e .code ,headers = self ._transport .response_headers