Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd6b1b0a

Browse files
nejchmax-wittig
authored andcommitted
feat: add a minimal GraphQL client
1 parentd44ddd2 commitd6b1b0a

File tree

14 files changed

+210
-24
lines changed

14 files changed

+210
-24
lines changed

‎docs/api-usage-graphql.rst

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
############################
2+
Using the GraphQL API (beta)
3+
############################
4+
5+
python-gitlab provides basic support for executing GraphQL queries and mutations.
6+
7+
..danger::
8+
9+
The GraphQL client is experimental and only provides basic support.
10+
It does not currently support pagination, obey rate limits,
11+
or attempt complex retries. You can use it to build simple queries and mutations.
12+
13+
It is currently unstable and its implementation may change. You can expect a more
14+
mature client in one of the upcoming versions.
15+
16+
The ``gitlab.GraphQL`` class
17+
==================================
18+
19+
As with the REST client, you connect to a GitLab instance by creating a ``gitlab.GraphQL`` object:
20+
21+
..code-block::python
22+
23+
import gitlab
24+
25+
# anonymous read-only access for public resources (GitLab.com)
26+
gq= gitlab.GraphQL()
27+
28+
# anonymous read-only access for public resources (self-hosted GitLab instance)
29+
gq= gitlab.GraphQL('https://gitlab.example.com')
30+
31+
# personal access token or OAuth2 token authentication (GitLab.com)
32+
gq= gitlab.GraphQL(token='glpat-JVNSESs8EwWRx5yDxM5q')
33+
34+
# personal access token or OAuth2 token authentication (self-hosted GitLab instance)
35+
gq= gitlab.GraphQL('https://gitlab.example.com',token='glpat-JVNSESs8EwWRx5yDxM5q')
36+
37+
Sending queries
38+
===============
39+
40+
Get the result of a query:
41+
42+
..code-block::python
43+
44+
query="""{
45+
query {
46+
currentUser {
47+
name
48+
}
49+
}
50+
"""
51+
52+
result= gq.execute(query)

‎docs/api-usage.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
############################
2-
Getting started withthe API
3-
############################
1+
##################
2+
Usingthe REST API
3+
##################
44

5-
python-gitlab only supports GitLabAPI v4.
5+
python-gitlabcurrentlyonly supportsv4 of theGitLabREST API.
66

77
``gitlab.Gitlab`` class
88
=======================

‎docs/cli-usage.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
############################
2-
Getting started with the CLI
3-
############################
1+
#############
2+
Using the CLI
3+
#############
44

55
``python-gitlab`` provides a:command:`gitlab` command-line tool to interact
66
with GitLab servers.

‎docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
cli-usage
88
api-usage
99
api-usage-advanced
10+
api-usage-graphql
1011
cli-examples
1112
api-objects
1213
api/gitlab

‎gitlab/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
__title__,
2828
__version__,
2929
)
30-
fromgitlab.clientimportGitlab,GitlabList# noqa: F401
30+
fromgitlab.clientimportGitlab,GitlabList,GraphQL# noqa: F401
3131
fromgitlab.exceptionsimport*# noqa: F401,F403
3232

3333
warnings.filterwarnings("default",category=DeprecationWarning,module="^gitlab")
@@ -42,5 +42,6 @@
4242
"__version__",
4343
"Gitlab",
4444
"GitlabList",
45+
"GraphQL",
4546
]
4647
__all__.extend(gitlab.exceptions.__all__)

‎gitlab/_backends/graphql.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
fromtypingimportAny
2+
3+
importhttpx
4+
fromgql.transport.httpximportHTTPXTransport
5+
6+
7+
classGitlabTransport(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+
defconnect(self)->None:
21+
pass
22+
23+
defclose(self)->None:
24+
pass

‎gitlab/client.py

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@
2525
importgitlab.exceptions
2626
fromgitlabimport_backends,utils
2727

28+
try:
29+
importgql
30+
importgraphql
31+
importhttpx
32+
33+
from ._backends.graphqlimportGitlabTransport
34+
35+
_GQL_INSTALLED=True
36+
exceptImportError:# pragma: no cover
37+
_GQL_INSTALLED=False
38+
39+
2840
REDIRECT_MSG= (
2941
"python-gitlab detected a {status_code} ({reason!r}) redirection. You must update "
3042
"your GitLab URL to the correct URL to avoid issues. The redirection was from: "
@@ -89,7 +101,7 @@ def __init__(
89101
self._api_version=str(api_version)
90102
self._server_version:Optional[str]=None
91103
self._server_revision:Optional[str]=None
92-
self._base_url=self._get_base_url(url)
104+
self._base_url=utils.get_base_url(url)
93105
self._url=f"{self._base_url}/api/v{api_version}"
94106
#: Timeout to use for requests to gitlab server
95107
self.timeout=timeout
@@ -557,18 +569,6 @@ def _get_session_opts(self) -> Dict[str, Any]:
557569
"verify":self.ssl_verify,
558570
}
559571

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-
ifnoturl:
568-
returngitlab.const.DEFAULT_URL
569-
570-
returnurl.rstrip("/")
571-
572572
def_build_url(self,path:str)->str:
573573
"""Returns the full url from path.
574574
@@ -1296,3 +1296,62 @@ def next(self) -> Dict[str, Any]:
12961296
returnself.next()
12971297

12981298
raiseStopIteration
1299+
1300+
1301+
classGraphQL:
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+
ifnot_GQL_INSTALLED:
1314+
raiseImportError(
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=clientorhttpx.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+
returnself
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+
ifself._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+
defexecute(
1354+
self,request:Union[str,graphql.Source],*args:Any,**kwargs:Any
1355+
)->Any:
1356+
parsed_document=self._gql(request)
1357+
returnself._client.execute(parsed_document,*args,**kwargs)

‎gitlab/utils.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,26 @@
99

1010
importrequests
1111

12-
fromgitlabimporttypes
12+
fromgitlabimportconst,types
1313

1414

1515
class_StdoutStream:
1616
def__call__(self,chunk:Any)->None:
1717
print(chunk)
1818

1919

20+
defget_base_url(url:Optional[str]=None)->str:
21+
"""Return the base URL with the trailing slash stripped.
22+
If the URL is a Falsy value, return the default URL.
23+
Returns:
24+
The base URL
25+
"""
26+
ifnoturl:
27+
returnconst.DEFAULT_URL
28+
29+
returnurl.rstrip("/")
30+
31+
2032
defget_content_type(content_type:Optional[str])->str:
2133
message=email.message.Message()
2234
ifcontent_typeisnotNone:

‎pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ dynamic = ["version"]
4343
[project.optional-dependencies]
4444
autocompletion = ["argcomplete>=1.10.0,<3"]
4545
yaml = ["PyYaml>=6.0.1"]
46+
graphql = ["gql[httpx]>=3.5.0,<4"]
4647

4748
[project.scripts]
4849
gitlab ="gitlab.cli:main"

‎requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
gql==3.5.0
2+
httpx==0.27.0
13
requests==2.32.3
24
requests-toolbelt==1.0.0

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp