ghapi 2.0.5__tar.gz → 2.0.7__tar.gz
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.
- {ghapi-2.0.5/ghapi.egg-info → ghapi-2.0.7}/PKG-INFO +44 -29
- {ghapi-2.0.5 → ghapi-2.0.7}/README.md +40 -26
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/__init__.py +2 -1
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/_modidx.py +23 -13
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/build_lib.py +10 -2
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/core.py +137 -8
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/gh_spec.py +375 -37
- ghapi-2.0.7/ghapi/gql_spec.py +1815 -0
- ghapi-2.0.7/ghapi/graphql.py +39 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/skill.py +19 -13
- {ghapi-2.0.5 → ghapi-2.0.7/ghapi.egg-info}/PKG-INFO +44 -29
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi.egg-info/SOURCES.txt +1 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi.egg-info/requires.txt +5 -2
- {ghapi-2.0.5 → ghapi-2.0.7}/pyproject.toml +1 -1
- ghapi-2.0.5/ghapi/graphql.py +0 -74
- {ghapi-2.0.5 → ghapi-2.0.7}/CONTRIBUTING.md +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/LICENSE +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/MANIFEST.in +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/actions.py +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/all.py +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/auth.py +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/cli.py +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/event.py +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/page.py +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/py.typed +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi/templates.py +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi.egg-info/dependency_links.txt +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi.egg-info/entry_points.txt +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/ghapi.egg-info/top_level.txt +0 -0
- {ghapi-2.0.5 → ghapi-2.0.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ghapi
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.7
|
|
4
4
|
Summary: A python client for the GitHub API
|
|
5
5
|
Author-email: Jeremy Howard <info@fast.ai>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -15,8 +15,9 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
15
15
|
Requires-Python: >=3.10
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE
|
|
18
|
-
Requires-Dist: fastcore>=2.
|
|
19
|
-
Requires-Dist: fastspec>=0.1.
|
|
18
|
+
Requires-Dist: fastcore>=2.2.6
|
|
19
|
+
Requires-Dist: fastspec>=0.1.7
|
|
20
|
+
Requires-Dist: tomli; python_version < "3.11"
|
|
20
21
|
Provides-Extra: dev
|
|
21
22
|
Requires-Dist: fastgit; extra == "dev"
|
|
22
23
|
Requires-Dist: matplotlib; extra == "dev"
|
|
@@ -69,6 +70,9 @@ To access the GitHub API, first create a [`GhApi`](https://ghapi.fast.ai/core.ht
|
|
|
69
70
|
|
|
70
71
|
``` python
|
|
71
72
|
from ghapi.all import GhApi
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
``` python
|
|
72
76
|
api = GhApi()
|
|
73
77
|
```
|
|
74
78
|
|
|
@@ -78,8 +82,6 @@ Every part of the API includes documentation directly in the `api` object itself
|
|
|
78
82
|
api
|
|
79
83
|
```
|
|
80
84
|
|
|
81
|
-
<div class="prose" markdown="1">
|
|
82
|
-
|
|
83
85
|
- [actions](https://docs.github.com/rest/reference/actions)
|
|
84
86
|
- [activity](https://docs.github.com/rest/reference/activity)
|
|
85
87
|
- [agent_tasks](https://docs.github.com/rest/reference/agent-tasks)
|
|
@@ -119,6 +121,7 @@ api
|
|
|
119
121
|
- [packages](https://docs.github.com/rest/reference/packages)
|
|
120
122
|
- [private_registries](https://docs.github.com/rest/reference/private-registries)
|
|
121
123
|
- [projects](https://docs.github.com/rest/reference/projects)
|
|
124
|
+
- [pull_request_stacks](https://docs.github.com/rest/reference/pull-request-stacks)
|
|
122
125
|
- [pulls](https://docs.github.com/rest/reference/pulls)
|
|
123
126
|
- [rate_limit](https://docs.github.com/rest/reference/rate-limit)
|
|
124
127
|
- [reactions](https://docs.github.com/rest/reference/reactions)
|
|
@@ -129,16 +132,12 @@ api
|
|
|
129
132
|
- [teams](https://docs.github.com/rest/reference/teams)
|
|
130
133
|
- [users](https://docs.github.com/rest/reference/users)
|
|
131
134
|
|
|
132
|
-
</div>
|
|
133
|
-
|
|
134
135
|
Then we can explore the endpoints provided by the API in each group, e.g. for the `git` group:
|
|
135
136
|
|
|
136
137
|
``` python
|
|
137
138
|
api.git
|
|
138
139
|
```
|
|
139
140
|
|
|
140
|
-
<div class="prose" markdown="1">
|
|
141
|
-
|
|
142
141
|
- [git.create_blob](https://docs.github.com/rest/git/blobs#create-a-blob)(owner, repo, content, encoding): *Create a blob*
|
|
143
142
|
- [git.get_blob](https://docs.github.com/rest/git/blobs#get-a-blob)(owner, repo, file_sha): *Get a blob*
|
|
144
143
|
- [git.create_commit](https://docs.github.com/rest/git/commits#create-a-commit)(owner, repo, message, tree, parents, author, committer, signature): *Create a commit*
|
|
@@ -153,16 +152,12 @@ api.git
|
|
|
153
152
|
- [git.create_tree](https://docs.github.com/rest/git/trees#create-a-tree)(owner, repo, tree, base_tree): *Create a tree*
|
|
154
153
|
- [git.get_tree](https://docs.github.com/rest/git/trees#get-a-tree)(owner, repo, tree_sha, recursive): *Get a tree*
|
|
155
154
|
|
|
156
|
-
</div>
|
|
157
|
-
|
|
158
155
|
Here’s how to learn about an endpoint you want to use, e.g.:
|
|
159
156
|
|
|
160
157
|
``` python
|
|
161
158
|
api.git.get_ref
|
|
162
159
|
```
|
|
163
160
|
|
|
164
|
-
<div class="prose" markdown="1">
|
|
165
|
-
|
|
166
161
|
Get a reference
|
|
167
162
|
|
|
168
163
|
Docs: https://docs.github.com/rest/git/refs#get-a-reference
|
|
@@ -172,16 +167,12 @@ Parameters:
|
|
|
172
167
|
- repo (str, required): The name of the repository without the `.git` extension. The name is not case sensitive.
|
|
173
168
|
- ref (str, required): The Git reference. For more information, see “[Git References](https://git-scm.com/book/en/v2/Git-Internals-Git-References)” in the Git documentation.
|
|
174
169
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
In Jupyter Notebook full tab completion, parameter lists, etc are provided for all endpoints. Endpoints are called as standard Python methods:
|
|
170
|
+
Jupyter provides full tab completion and parameter lists for every endpoint. Endpoints are called as standard Python methods:
|
|
178
171
|
|
|
179
172
|
``` python
|
|
180
173
|
await api.git.get_ref(owner='fastai', repo='fastcore', ref='heads/master')
|
|
181
174
|
```
|
|
182
175
|
|
|
183
|
-
<div class="prose" markdown="1">
|
|
184
|
-
|
|
185
176
|
``` python
|
|
186
177
|
{ 'node_id': 'MDM6UmVmMjI1NDYwNTk5OnJlZnMvaGVhZHMvbWFzdGVy',
|
|
187
178
|
'object': { 'sha': 'c0608379fe60014534c8dffe2e381138e8160f53',
|
|
@@ -191,17 +182,13 @@ await api.git.get_ref(owner='fastai', repo='fastcore', ref='heads/master')
|
|
|
191
182
|
'url': 'https://api.github.com/repos/AnswerDotAI/fastcore/git/refs/heads/master'}
|
|
192
183
|
```
|
|
193
184
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
To use [`ghapi`](https://ghapi.fast.ai/cli.html#ghapi) to access authenticated operations (other than when running through GitHub Actions), you will need a GitHub [personal access token](https://docs.github.com/github/authenticating-to-github/creating-a-personal-access-token), which is a secret code used to access your account. If you don’t have one, [click here](https://github.com/settings/tokens/new) to create one. You’ll be asked to enter a name – choose anything you like, for instance “*ghapi*”. You’ll also be asked to choose “scopes”; this limits what you’ll be able to do with the API using this token. If you’re not sure, click “*repo*” “*gist*”, “*notifications*”, and “*workflow*”. Then click “Generate Token” at the bottom of the screen, and copy the token (the long string of letters and numbers shown). You can easily do that by clicking the little clipboard icon next to the token.
|
|
197
|
-
|
|
198
|
-
Rather than pasting that token into every script, it’s easiest to save it as an environment variable. If you save it as `$GITHUB_TOKEN` then it will be most convenient, so add this to the end of your `.bashrc` or `.zshrc` file:
|
|
185
|
+
To use authenticated operations (other than when running through GitHub Actions), you will need a GitHub [personal access token](https://docs.github.com/github/authenticating-to-github/creating-a-personal-access-token). If you don’t have one, [click here](https://github.com/settings/tokens/new) to create it, choosing the scopes you need (“repo”, “gist”, “notifications”, and “workflow” cover most uses). Save it as an environment variable named `GITHUB_TOKEN`, e.g. by adding this to your `.bashrc` or `.zshrc`:
|
|
199
186
|
|
|
200
187
|
export GITHUB_TOKEN=xxx
|
|
201
188
|
|
|
202
|
-
|
|
189
|
+
[`GhApi`](https://ghapi.fast.ai/core.html#ghapi) uses that variable automatically, or you can pass `token=` explicitly.
|
|
203
190
|
|
|
204
|
-
As well as
|
|
191
|
+
As well as `token`, you can pass any parameters you want auto-inserted into relevant methods, such as `owner` and `repo`:
|
|
205
192
|
|
|
206
193
|
``` python
|
|
207
194
|
api = GhApi(owner='fastai', repo='fastcore', token=github_token)
|
|
@@ -213,8 +200,6 @@ We can now repeat the previous method, but only need to pass `ref`:
|
|
|
213
200
|
await api.git.get_ref('heads/master')
|
|
214
201
|
```
|
|
215
202
|
|
|
216
|
-
<div class="prose" markdown="1">
|
|
217
|
-
|
|
218
203
|
``` python
|
|
219
204
|
{ 'node_id': 'MDM6UmVmMjI1NDYwNTk5OnJlZnMvaGVhZHMvbWFzdGVy',
|
|
220
205
|
'object': { 'sha': 'c0608379fe60014534c8dffe2e381138e8160f53',
|
|
@@ -224,8 +209,6 @@ await api.git.get_ref('heads/master')
|
|
|
224
209
|
'url': 'https://api.github.com/repos/AnswerDotAI/fastcore/git/refs/heads/master'}
|
|
225
210
|
```
|
|
226
211
|
|
|
227
|
-
</div>
|
|
228
|
-
|
|
229
212
|
Now that we’ve provided our token, we can use authenticated endpoints such as creating an issue:
|
|
230
213
|
|
|
231
214
|
``` python
|
|
@@ -238,6 +221,38 @@ Since we’ve now checked out GhApi, let’s close this issue. 😎
|
|
|
238
221
|
await api.issues.update(issue.number, state='closed')
|
|
239
222
|
```
|
|
240
223
|
|
|
224
|
+
## Beyond the endpoints
|
|
225
|
+
|
|
226
|
+
[`ghapi`](https://ghapi.fast.ai/cli.html#ghapi) also layers task-level conveniences over the generated endpoints – see the [GhApi details](https://ghapi.fast.ai/core.html) page for the full set. Highlights: [`paged`](https://ghapi.fast.ai/page.html#paged)/[`pages`](https://ghapi.fast.ai/page.html#pages) iterate any list endpoint; [`read_issue`](https://ghapi.fast.ai/core.html#read_issue)/[`read_pr`](https://ghapi.fast.ai/core.html#read_pr) gather a whole issue or PR (body, comments, diff, reviews) in one call; [`dep_graph`](https://ghapi.fast.ai/core.html#dep_graph)/[`dep_order`](https://ghapi.fast.ai/core.html#dep_order) sort an ecosystem’s repos dependency-first; plus helpers for gists, releases, branches, and repo files. For CI, [`check_status`](https://ghapi.fast.ai/core.html#check_status) combines commit statuses and check runs into one verdict, and [`failed_step_log`](https://ghapi.fast.ai/core.html#failed_step_log) drills into why a run went red:
|
|
227
|
+
|
|
228
|
+
``` python
|
|
229
|
+
api = GhApi(owner='AnswerDotAI', repo='ghapi', token=github_token)
|
|
230
|
+
await api.check_status('main')
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**failure**
|
|
234
|
+
|
|
235
|
+
- 93199230629 update-pip-graph: success (46s)
|
|
236
|
+
- 93199227080 deploy: failure (22s)
|
|
237
|
+
|
|
238
|
+
## GraphQL
|
|
239
|
+
|
|
240
|
+
When a read fans out across many repos, the [GraphQL client](https://ghapi.fast.ai/graphql.html) fetches it in a single `batch` call – issued as parallel chunked requests under the hood, at a fraction of the rate-limit cost of per-repo REST calls. Build schema-checked query fragments by attribute chaining, then `batch` them: here, the head commit of several repos at once. The same page covers interactive schema discovery, cursor pagination, raw queries, and more:
|
|
241
|
+
|
|
242
|
+
``` python
|
|
243
|
+
from ghapi.graphql import GhGql
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
``` python
|
|
247
|
+
gql = GhGql()
|
|
248
|
+
await gql.batch(*[gql.repository(owner='AnswerDotAI', name=n).defaultBranchRef.target.oid
|
|
249
|
+
for n in ('fastcore', 'fasthtml', 'ghapi')])
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
['25c4f3228ccac3c5a63da71b5eaa4be3c428f602',
|
|
253
|
+
'e5d967ae627c63035e296e6f319f220e278327e7',
|
|
254
|
+
'ad07893daac86de6693bc9bb57ae7216c1b347d0']
|
|
255
|
+
|
|
241
256
|
## How to use - command line
|
|
242
257
|
|
|
243
258
|
You can use [`GhApi`](https://ghapi.fast.ai/core.html#ghapi) via the command line, and can access nearly everything in the [GitHub API](https://docs.github.com/rest). We provide an overview here of one of the command line programs, [`ghapi`](https://ghapi.fast.ai/cli.html#ghapi) – see the full CLI docs page for details on all the programs available.
|
|
@@ -40,6 +40,9 @@ To access the GitHub API, first create a [`GhApi`](https://ghapi.fast.ai/core.ht
|
|
|
40
40
|
|
|
41
41
|
``` python
|
|
42
42
|
from ghapi.all import GhApi
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
``` python
|
|
43
46
|
api = GhApi()
|
|
44
47
|
```
|
|
45
48
|
|
|
@@ -49,8 +52,6 @@ Every part of the API includes documentation directly in the `api` object itself
|
|
|
49
52
|
api
|
|
50
53
|
```
|
|
51
54
|
|
|
52
|
-
<div class="prose" markdown="1">
|
|
53
|
-
|
|
54
55
|
- [actions](https://docs.github.com/rest/reference/actions)
|
|
55
56
|
- [activity](https://docs.github.com/rest/reference/activity)
|
|
56
57
|
- [agent_tasks](https://docs.github.com/rest/reference/agent-tasks)
|
|
@@ -90,6 +91,7 @@ api
|
|
|
90
91
|
- [packages](https://docs.github.com/rest/reference/packages)
|
|
91
92
|
- [private_registries](https://docs.github.com/rest/reference/private-registries)
|
|
92
93
|
- [projects](https://docs.github.com/rest/reference/projects)
|
|
94
|
+
- [pull_request_stacks](https://docs.github.com/rest/reference/pull-request-stacks)
|
|
93
95
|
- [pulls](https://docs.github.com/rest/reference/pulls)
|
|
94
96
|
- [rate_limit](https://docs.github.com/rest/reference/rate-limit)
|
|
95
97
|
- [reactions](https://docs.github.com/rest/reference/reactions)
|
|
@@ -100,16 +102,12 @@ api
|
|
|
100
102
|
- [teams](https://docs.github.com/rest/reference/teams)
|
|
101
103
|
- [users](https://docs.github.com/rest/reference/users)
|
|
102
104
|
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
105
|
Then we can explore the endpoints provided by the API in each group, e.g. for the `git` group:
|
|
106
106
|
|
|
107
107
|
``` python
|
|
108
108
|
api.git
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
<div class="prose" markdown="1">
|
|
112
|
-
|
|
113
111
|
- [git.create_blob](https://docs.github.com/rest/git/blobs#create-a-blob)(owner, repo, content, encoding): *Create a blob*
|
|
114
112
|
- [git.get_blob](https://docs.github.com/rest/git/blobs#get-a-blob)(owner, repo, file_sha): *Get a blob*
|
|
115
113
|
- [git.create_commit](https://docs.github.com/rest/git/commits#create-a-commit)(owner, repo, message, tree, parents, author, committer, signature): *Create a commit*
|
|
@@ -124,16 +122,12 @@ api.git
|
|
|
124
122
|
- [git.create_tree](https://docs.github.com/rest/git/trees#create-a-tree)(owner, repo, tree, base_tree): *Create a tree*
|
|
125
123
|
- [git.get_tree](https://docs.github.com/rest/git/trees#get-a-tree)(owner, repo, tree_sha, recursive): *Get a tree*
|
|
126
124
|
|
|
127
|
-
</div>
|
|
128
|
-
|
|
129
125
|
Here’s how to learn about an endpoint you want to use, e.g.:
|
|
130
126
|
|
|
131
127
|
``` python
|
|
132
128
|
api.git.get_ref
|
|
133
129
|
```
|
|
134
130
|
|
|
135
|
-
<div class="prose" markdown="1">
|
|
136
|
-
|
|
137
131
|
Get a reference
|
|
138
132
|
|
|
139
133
|
Docs: https://docs.github.com/rest/git/refs#get-a-reference
|
|
@@ -143,16 +137,12 @@ Parameters:
|
|
|
143
137
|
- repo (str, required): The name of the repository without the `.git` extension. The name is not case sensitive.
|
|
144
138
|
- ref (str, required): The Git reference. For more information, see “[Git References](https://git-scm.com/book/en/v2/Git-Internals-Git-References)” in the Git documentation.
|
|
145
139
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
In Jupyter Notebook full tab completion, parameter lists, etc are provided for all endpoints. Endpoints are called as standard Python methods:
|
|
140
|
+
Jupyter provides full tab completion and parameter lists for every endpoint. Endpoints are called as standard Python methods:
|
|
149
141
|
|
|
150
142
|
``` python
|
|
151
143
|
await api.git.get_ref(owner='fastai', repo='fastcore', ref='heads/master')
|
|
152
144
|
```
|
|
153
145
|
|
|
154
|
-
<div class="prose" markdown="1">
|
|
155
|
-
|
|
156
146
|
``` python
|
|
157
147
|
{ 'node_id': 'MDM6UmVmMjI1NDYwNTk5OnJlZnMvaGVhZHMvbWFzdGVy',
|
|
158
148
|
'object': { 'sha': 'c0608379fe60014534c8dffe2e381138e8160f53',
|
|
@@ -162,17 +152,13 @@ await api.git.get_ref(owner='fastai', repo='fastcore', ref='heads/master')
|
|
|
162
152
|
'url': 'https://api.github.com/repos/AnswerDotAI/fastcore/git/refs/heads/master'}
|
|
163
153
|
```
|
|
164
154
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
To use [`ghapi`](https://ghapi.fast.ai/cli.html#ghapi) to access authenticated operations (other than when running through GitHub Actions), you will need a GitHub [personal access token](https://docs.github.com/github/authenticating-to-github/creating-a-personal-access-token), which is a secret code used to access your account. If you don’t have one, [click here](https://github.com/settings/tokens/new) to create one. You’ll be asked to enter a name – choose anything you like, for instance “*ghapi*”. You’ll also be asked to choose “scopes”; this limits what you’ll be able to do with the API using this token. If you’re not sure, click “*repo*” “*gist*”, “*notifications*”, and “*workflow*”. Then click “Generate Token” at the bottom of the screen, and copy the token (the long string of letters and numbers shown). You can easily do that by clicking the little clipboard icon next to the token.
|
|
168
|
-
|
|
169
|
-
Rather than pasting that token into every script, it’s easiest to save it as an environment variable. If you save it as `$GITHUB_TOKEN` then it will be most convenient, so add this to the end of your `.bashrc` or `.zshrc` file:
|
|
155
|
+
To use authenticated operations (other than when running through GitHub Actions), you will need a GitHub [personal access token](https://docs.github.com/github/authenticating-to-github/creating-a-personal-access-token). If you don’t have one, [click here](https://github.com/settings/tokens/new) to create it, choosing the scopes you need (“repo”, “gist”, “notifications”, and “workflow” cover most uses). Save it as an environment variable named `GITHUB_TOKEN`, e.g. by adding this to your `.bashrc` or `.zshrc`:
|
|
170
156
|
|
|
171
157
|
export GITHUB_TOKEN=xxx
|
|
172
158
|
|
|
173
|
-
|
|
159
|
+
[`GhApi`](https://ghapi.fast.ai/core.html#ghapi) uses that variable automatically, or you can pass `token=` explicitly.
|
|
174
160
|
|
|
175
|
-
As well as
|
|
161
|
+
As well as `token`, you can pass any parameters you want auto-inserted into relevant methods, such as `owner` and `repo`:
|
|
176
162
|
|
|
177
163
|
``` python
|
|
178
164
|
api = GhApi(owner='fastai', repo='fastcore', token=github_token)
|
|
@@ -184,8 +170,6 @@ We can now repeat the previous method, but only need to pass `ref`:
|
|
|
184
170
|
await api.git.get_ref('heads/master')
|
|
185
171
|
```
|
|
186
172
|
|
|
187
|
-
<div class="prose" markdown="1">
|
|
188
|
-
|
|
189
173
|
``` python
|
|
190
174
|
{ 'node_id': 'MDM6UmVmMjI1NDYwNTk5OnJlZnMvaGVhZHMvbWFzdGVy',
|
|
191
175
|
'object': { 'sha': 'c0608379fe60014534c8dffe2e381138e8160f53',
|
|
@@ -195,8 +179,6 @@ await api.git.get_ref('heads/master')
|
|
|
195
179
|
'url': 'https://api.github.com/repos/AnswerDotAI/fastcore/git/refs/heads/master'}
|
|
196
180
|
```
|
|
197
181
|
|
|
198
|
-
</div>
|
|
199
|
-
|
|
200
182
|
Now that we’ve provided our token, we can use authenticated endpoints such as creating an issue:
|
|
201
183
|
|
|
202
184
|
``` python
|
|
@@ -209,6 +191,38 @@ Since we’ve now checked out GhApi, let’s close this issue. 😎
|
|
|
209
191
|
await api.issues.update(issue.number, state='closed')
|
|
210
192
|
```
|
|
211
193
|
|
|
194
|
+
## Beyond the endpoints
|
|
195
|
+
|
|
196
|
+
[`ghapi`](https://ghapi.fast.ai/cli.html#ghapi) also layers task-level conveniences over the generated endpoints – see the [GhApi details](https://ghapi.fast.ai/core.html) page for the full set. Highlights: [`paged`](https://ghapi.fast.ai/page.html#paged)/[`pages`](https://ghapi.fast.ai/page.html#pages) iterate any list endpoint; [`read_issue`](https://ghapi.fast.ai/core.html#read_issue)/[`read_pr`](https://ghapi.fast.ai/core.html#read_pr) gather a whole issue or PR (body, comments, diff, reviews) in one call; [`dep_graph`](https://ghapi.fast.ai/core.html#dep_graph)/[`dep_order`](https://ghapi.fast.ai/core.html#dep_order) sort an ecosystem’s repos dependency-first; plus helpers for gists, releases, branches, and repo files. For CI, [`check_status`](https://ghapi.fast.ai/core.html#check_status) combines commit statuses and check runs into one verdict, and [`failed_step_log`](https://ghapi.fast.ai/core.html#failed_step_log) drills into why a run went red:
|
|
197
|
+
|
|
198
|
+
``` python
|
|
199
|
+
api = GhApi(owner='AnswerDotAI', repo='ghapi', token=github_token)
|
|
200
|
+
await api.check_status('main')
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**failure**
|
|
204
|
+
|
|
205
|
+
- 93199230629 update-pip-graph: success (46s)
|
|
206
|
+
- 93199227080 deploy: failure (22s)
|
|
207
|
+
|
|
208
|
+
## GraphQL
|
|
209
|
+
|
|
210
|
+
When a read fans out across many repos, the [GraphQL client](https://ghapi.fast.ai/graphql.html) fetches it in a single `batch` call – issued as parallel chunked requests under the hood, at a fraction of the rate-limit cost of per-repo REST calls. Build schema-checked query fragments by attribute chaining, then `batch` them: here, the head commit of several repos at once. The same page covers interactive schema discovery, cursor pagination, raw queries, and more:
|
|
211
|
+
|
|
212
|
+
``` python
|
|
213
|
+
from ghapi.graphql import GhGql
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
``` python
|
|
217
|
+
gql = GhGql()
|
|
218
|
+
await gql.batch(*[gql.repository(owner='AnswerDotAI', name=n).defaultBranchRef.target.oid
|
|
219
|
+
for n in ('fastcore', 'fasthtml', 'ghapi')])
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
['25c4f3228ccac3c5a63da71b5eaa4be3c428f602',
|
|
223
|
+
'e5d967ae627c63035e296e6f319f220e278327e7',
|
|
224
|
+
'ad07893daac86de6693bc9bb57ae7216c1b347d0']
|
|
225
|
+
|
|
212
226
|
## How to use - command line
|
|
213
227
|
|
|
214
228
|
You can use [`GhApi`](https://ghapi.fast.ai/core.html#ghapi) via the command line, and can access nearly everything in the [GitHub API](https://docs.github.com/rest). We provide an overview here of one of the command line programs, [`ghapi`](https://ghapi.fast.ai/cli.html#ghapi) – see the full CLI docs page for details on all the programs available.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Modules:
|
|
4
4
|
|
|
5
|
+
- `ghapi.graphql`: Query GitHub's GraphQL API: schema-aware chained queries, one-request batching, and raw GraphQL
|
|
5
6
|
- `ghapi.skill`: GitHub REST API access via `GhApi`, plus local git operations via `fastgit.Git`. Use this for day-to-day GitHub work: reading/creating issues and PRs, checking CI status, managing releases/branches/gists, and repo-local git operations -- all from Python, no shelling out to `gh`/`git` needed."""
|
|
6
7
|
|
|
7
|
-
__version__ = "2.0.
|
|
8
|
+
__version__ = "2.0.7"
|
|
@@ -32,7 +32,8 @@ d = { 'settings': { 'branch': 'main',
|
|
|
32
32
|
'ghapi.auth.GhDeviceAuth.wait': ('auth.html#ghdeviceauth.wait', 'ghapi/auth.py'),
|
|
33
33
|
'ghapi.auth.github_auth_device': ('auth.html#github_auth_device', 'ghapi/auth.py'),
|
|
34
34
|
'ghapi.auth.scope_str': ('auth.html#scope_str', 'ghapi/auth.py')},
|
|
35
|
-
'ghapi.build_lib': {'ghapi.build_lib.
|
|
35
|
+
'ghapi.build_lib': { 'ghapi.build_lib.build_gql_spec': ('build_lib.html#build_gql_spec', 'ghapi/build_lib.py'),
|
|
36
|
+
'ghapi.build_lib.build_spec': ('build_lib.html#build_spec', 'ghapi/build_lib.py')},
|
|
36
37
|
'ghapi.cli': { 'ghapi.cli._api': ('cli.html#_api', 'ghapi/cli.py'),
|
|
37
38
|
'ghapi.cli._call_api': ('cli.html#_call_api', 'ghapi/cli.py'),
|
|
38
39
|
'ghapi.cli._ghapi': ('cli.html#_ghapi', 'ghapi/cli.py'),
|
|
@@ -42,7 +43,11 @@ d = { 'settings': { 'branch': 'main',
|
|
|
42
43
|
'ghapi.cli.ghapi': ('cli.html#ghapi', 'ghapi/cli.py'),
|
|
43
44
|
'ghapi.cli.ghpath': ('cli.html#ghpath', 'ghapi/cli.py'),
|
|
44
45
|
'ghapi.cli.ghraw': ('cli.html#ghraw', 'ghapi/cli.py')},
|
|
45
|
-
'ghapi.core': { 'ghapi.core.
|
|
46
|
+
'ghapi.core': { 'ghapi.core.CheckRun': ('core.html#checkrun', 'ghapi/core.py'),
|
|
47
|
+
'ghapi.core.CheckRun.__repr__': ('core.html#checkrun.__repr__', 'ghapi/core.py'),
|
|
48
|
+
'ghapi.core.CommitStatus': ('core.html#commitstatus', 'ghapi/core.py'),
|
|
49
|
+
'ghapi.core.CommitStatus.__repr__': ('core.html#commitstatus.__repr__', 'ghapi/core.py'),
|
|
50
|
+
'ghapi.core.GhApi': ('core.html#ghapi', 'ghapi/core.py'),
|
|
46
51
|
'ghapi.core.GhApi.__call__': ('core.html#ghapi.__call__', 'ghapi/core.py'),
|
|
47
52
|
'ghapi.core.GhApi.__getitem__': ('core.html#ghapi.__getitem__', 'ghapi/core.py'),
|
|
48
53
|
'ghapi.core.GhApi.__init__': ('core.html#ghapi.__init__', 'ghapi/core.py'),
|
|
@@ -59,6 +64,8 @@ d = { 'settings': { 'branch': 'main',
|
|
|
59
64
|
'ghapi.core.GhApi.recv_hdrs': ('core.html#ghapi.recv_hdrs', 'ghapi/core.py'),
|
|
60
65
|
'ghapi.core.GhApi.update_gist': ('core.html#ghapi.update_gist', 'ghapi/core.py'),
|
|
61
66
|
'ghapi.core.GhApi.upload_file': ('core.html#ghapi.upload_file', 'ghapi/core.py'),
|
|
67
|
+
'ghapi.core.GhRows': ('core.html#ghrows', 'ghapi/core.py'),
|
|
68
|
+
'ghapi.core.GhRows.__repr__': ('core.html#ghrows.__repr__', 'ghapi/core.py'),
|
|
62
69
|
'ghapi.core.GhSyncTransport': ('core.html#ghsynctransport', 'ghapi/core.py'),
|
|
63
70
|
'ghapi.core.GhSyncTransport.request': ('core.html#ghsynctransport.request', 'ghapi/core.py'),
|
|
64
71
|
'ghapi.core.GhTransport': ('core.html#ghtransport', 'ghapi/core.py'),
|
|
@@ -72,14 +79,19 @@ d = { 'settings': { 'branch': 'main',
|
|
|
72
79
|
'ghapi.core._IssueInfo': ('core.html#_issueinfo', 'ghapi/core.py'),
|
|
73
80
|
'ghapi.core._IssueInfo._repr_markdown_': ('core.html#_issueinfo._repr_markdown_', 'ghapi/core.py'),
|
|
74
81
|
'ghapi.core._LiveDefaults': ('core.html#_livedefaults', 'ghapi/core.py'),
|
|
82
|
+
'ghapi.core._LiveDefaults.__contains__': ('core.html#_livedefaults.__contains__', 'ghapi/core.py'),
|
|
83
|
+
'ghapi.core._LiveDefaults.get': ('core.html#_livedefaults.get', 'ghapi/core.py'),
|
|
75
84
|
'ghapi.core._LiveDefaults.items': ('core.html#_livedefaults.items', 'ghapi/core.py'),
|
|
85
|
+
'ghapi.core._dur': ('core.html#_dur', 'ghapi/core.py'),
|
|
76
86
|
'ghapi.core._filter_diff': ('core.html#_filter_diff', 'ghapi/core.py'),
|
|
77
87
|
'ghapi.core._find_matches': ('core.html#_find_matches', 'ghapi/core.py'),
|
|
78
88
|
'ghapi.core._fmt_replies': ('core.html#_fmt_replies', 'ghapi/core.py'),
|
|
79
89
|
'ghapi.core._include': ('core.html#_include', 'ghapi/core.py'),
|
|
90
|
+
'ghapi.core._listed': ('core.html#_listed', 'ghapi/core.py'),
|
|
80
91
|
'ghapi.core._parse_tmpl': ('core.html#_parse_tmpl', 'ghapi/core.py'),
|
|
81
92
|
'ghapi.core._reduce_ctx': ('core.html#_reduce_ctx', 'ghapi/core.py'),
|
|
82
93
|
'ghapi.core._run_subp': ('core.html#_run_subp', 'ghapi/core.py'),
|
|
94
|
+
'ghapi.core._transdeps': ('core.html#_transdeps', 'ghapi/core.py'),
|
|
83
95
|
'ghapi.core.call_gh': ('core.html#call_gh', 'ghapi/core.py'),
|
|
84
96
|
'ghapi.core.check_status': ('core.html#check_status', 'ghapi/core.py'),
|
|
85
97
|
'ghapi.core.commit_tree': ('core.html#commit_tree', 'ghapi/core.py'),
|
|
@@ -92,7 +104,13 @@ d = { 'settings': { 'branch': 'main',
|
|
|
92
104
|
'ghapi.core.delete_file': ('core.html#delete_file', 'ghapi/core.py'),
|
|
93
105
|
'ghapi.core.delete_release': ('core.html#delete_release', 'ghapi/core.py'),
|
|
94
106
|
'ghapi.core.delete_tag': ('core.html#delete_tag', 'ghapi/core.py'),
|
|
107
|
+
'ghapi.core.dep_closure': ('core.html#dep_closure', 'ghapi/core.py'),
|
|
108
|
+
'ghapi.core.dep_dependents': ('core.html#dep_dependents', 'ghapi/core.py'),
|
|
109
|
+
'ghapi.core.dep_graph': ('core.html#dep_graph', 'ghapi/core.py'),
|
|
110
|
+
'ghapi.core.dep_key': ('core.html#dep_key', 'ghapi/core.py'),
|
|
111
|
+
'ghapi.core.dep_order': ('core.html#dep_order', 'ghapi/core.py'),
|
|
95
112
|
'ghapi.core.enable_pages': ('core.html#enable_pages', 'ghapi/core.py'),
|
|
113
|
+
'ghapi.core.failed_step_log': ('core.html#failed_step_log', 'ghapi/core.py'),
|
|
96
114
|
'ghapi.core.get_branch': ('core.html#get_branch', 'ghapi/core.py'),
|
|
97
115
|
'ghapi.core.get_content': ('core.html#get_content', 'ghapi/core.py'),
|
|
98
116
|
'ghapi.core.gh2date': ('core.html#gh2date', 'ghapi/core.py'),
|
|
@@ -102,6 +120,7 @@ d = { 'settings': { 'branch': 'main',
|
|
|
102
120
|
'ghapi.core.list_branches': ('core.html#list_branches', 'ghapi/core.py'),
|
|
103
121
|
'ghapi.core.list_files': ('core.html#list_files', 'ghapi/core.py'),
|
|
104
122
|
'ghapi.core.list_tags': ('core.html#list_tags', 'ghapi/core.py'),
|
|
123
|
+
'ghapi.core.local_dep_graph': ('core.html#local_dep_graph', 'ghapi/core.py'),
|
|
105
124
|
'ghapi.core.pr_file_diff': ('core.html#pr_file_diff', 'ghapi/core.py'),
|
|
106
125
|
'ghapi.core.pr_status': ('core.html#pr_status', 'ghapi/core.py'),
|
|
107
126
|
'ghapi.core.print_summary': ('core.html#print_summary', 'ghapi/core.py'),
|
|
@@ -126,19 +145,10 @@ d = { 'settings': { 'branch': 'main',
|
|
|
126
145
|
'ghapi.event.load_sample_events': ('event.html#load_sample_events', 'ghapi/event.py'),
|
|
127
146
|
'ghapi.event.save_sample_events': ('event.html#save_sample_events', 'ghapi/event.py')},
|
|
128
147
|
'ghapi.gh_spec': {},
|
|
148
|
+
'ghapi.gql_spec': {},
|
|
129
149
|
'ghapi.graphql': { 'ghapi.graphql.GhGql': ('graphql.html#ghgql', 'ghapi/graphql.py'),
|
|
130
|
-
'ghapi.graphql.GhGql.__call__': ('graphql.html#ghgql.__call__', 'ghapi/graphql.py'),
|
|
131
150
|
'ghapi.graphql.GhGql.__init__': ('graphql.html#ghgql.__init__', 'ghapi/graphql.py'),
|
|
132
|
-
'ghapi.graphql.GhGql.
|
|
133
|
-
'ghapi.graphql.GhGql.list_queries': ('graphql.html#ghgql.list_queries', 'ghapi/graphql.py'),
|
|
134
|
-
'ghapi.graphql.GhGql.query_args': ('graphql.html#ghgql.query_args', 'ghapi/graphql.py'),
|
|
135
|
-
'ghapi.graphql.GhGql.schema': ('graphql.html#ghgql.schema', 'ghapi/graphql.py'),
|
|
136
|
-
'ghapi.graphql.GhGql.type_fields': ('graphql.html#ghgql.type_fields', 'ghapi/graphql.py'),
|
|
137
|
-
'ghapi.graphql._get_client': ('graphql.html#_get_client', 'ghapi/graphql.py'),
|
|
138
|
-
'ghapi.graphql.gh_query': ('graphql.html#gh_query', 'ghapi/graphql.py'),
|
|
139
|
-
'ghapi.graphql.list_queries': ('graphql.html#list_queries', 'ghapi/graphql.py'),
|
|
140
|
-
'ghapi.graphql.query_args': ('graphql.html#query_args', 'ghapi/graphql.py'),
|
|
141
|
-
'ghapi.graphql.type_fields': ('graphql.html#type_fields', 'ghapi/graphql.py')},
|
|
151
|
+
'ghapi.graphql.GhGql.repo': ('graphql.html#ghgql.repo', 'ghapi/graphql.py')},
|
|
142
152
|
'ghapi.page': { 'ghapi.page.GhApi.last_page': ('page.html#ghapi.last_page', 'ghapi/page.py'),
|
|
143
153
|
'ghapi.page._Scanner': ('page.html#_scanner', 'ghapi/page.py'),
|
|
144
154
|
'ghapi.page._Scanner.__getitem__': ('page.html#_scanner.__getitem__', 'ghapi/page.py'),
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/90_build_lib.ipynb.
|
|
4
4
|
|
|
5
5
|
# %% auto #0
|
|
6
|
-
__all__ = ['GH_OPENAPI_URL', 'build_spec']
|
|
6
|
+
__all__ = ['GH_OPENAPI_URL', 'build_spec', 'build_gql_spec']
|
|
7
7
|
|
|
8
8
|
# %% ../nbs/90_build_lib.ipynb #cdbcf258
|
|
9
9
|
from fastcore.all import *
|
|
10
10
|
from fastspec.spec import SpecParser
|
|
11
|
+
from fastspec.gql import GqlSpec, INTROSPECT
|
|
11
12
|
|
|
12
|
-
import json
|
|
13
|
+
import json, httpx
|
|
13
14
|
|
|
14
15
|
# %% ../nbs/90_build_lib.ipynb #c215ed8d
|
|
15
16
|
GH_OPENAPI_URL = 'https://github.com/github/rest-api-description/raw/main/descriptions/api.github.com/api.github.com.json?raw=true'
|
|
@@ -18,3 +19,10 @@ GH_OPENAPI_URL = 'https://github.com/github/rest-api-description/raw/main/descri
|
|
|
18
19
|
def build_spec(nm='ghapi/gh_spec.py', url=GH_OPENAPI_URL):
|
|
19
20
|
"Regenerate the compact spec module `gh_spec.py` from GitHub's OpenAPI description."
|
|
20
21
|
SpecParser.from_openapi(dict2obj(json.loads(urlread(url)))).save(nm)
|
|
22
|
+
|
|
23
|
+
# %% ../nbs/90_build_lib.ipynb #9aef0afb
|
|
24
|
+
def build_gql_spec(nm='ghapi/gql_spec.py', url='https://api.github.com/graphql'):
|
|
25
|
+
"Regenerate the distilled GraphQL schema tables shipped as `ghapi.gql_spec`."
|
|
26
|
+
r = httpx.post(url, json=dict(query=INTROSPECT), headers=dict(Authorization=f'bearer {os.environ["GITHUB_TOKEN"]}'), timeout=60)
|
|
27
|
+
r.raise_for_status()
|
|
28
|
+
GqlSpec.from_introspection(r.json()).save(nm)
|