ghapi 2.1.1__tar.gz → 2.1.3__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.1.1/ghapi.egg-info → ghapi-2.1.3}/PKG-INFO +4 -3
- ghapi-2.1.3/ghapi/__init__.py +8 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/core.py +25 -22
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/page.py +1 -1
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/skill.py +2 -2
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/templates.py +4 -4
- {ghapi-2.1.1 → ghapi-2.1.3/ghapi.egg-info}/PKG-INFO +4 -3
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi.egg-info/requires.txt +3 -2
- {ghapi-2.1.1 → ghapi-2.1.3}/pyproject.toml +1 -1
- ghapi-2.1.1/ghapi/__init__.py +0 -8
- {ghapi-2.1.1 → ghapi-2.1.3}/CONTRIBUTING.md +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/LICENSE +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/MANIFEST.in +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/README.md +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/_modidx.py +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/actions.py +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/all.py +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/auth.py +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/build_lib.py +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/cli.py +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/event.py +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/gh_spec.py +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/gql_spec.py +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/graphql.py +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi/py.typed +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi.egg-info/SOURCES.txt +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi.egg-info/dependency_links.txt +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi.egg-info/entry_points.txt +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/ghapi.egg-info/top_level.txt +0 -0
- {ghapi-2.1.1 → ghapi-2.1.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ghapi
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.3
|
|
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.2.
|
|
19
|
-
Requires-Dist: fastspec>=0.2.
|
|
18
|
+
Requires-Dist: fastcore>=2.2.7
|
|
19
|
+
Requires-Dist: fastspec>=0.2.1
|
|
20
|
+
Requires-Dist: fasttransport>=0.0.2
|
|
20
21
|
Requires-Dist: tomli; python_version < "3.11"
|
|
21
22
|
Provides-Extra: dev
|
|
22
23
|
Requires-Dist: fastgit; extra == "dev"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""A python client for the GitHub API
|
|
2
|
+
|
|
3
|
+
Modules:
|
|
4
|
+
|
|
5
|
+
- `ghapi.graphql`: Query GitHub's GraphQL API: schema-aware chained queries, one-request batching, and raw GraphQL
|
|
6
|
+
- `ghapi.skill`: GitHub REST API access via `GhApi`, plus local git operations via `fastgit.Git`. Trigger: ALWAYS read before reading/creating issues and PRs, checking CI status, managing releases/branches/gists, and doing repo-local git operations."""
|
|
7
|
+
|
|
8
|
+
__version__ = "2.1.3"
|
|
@@ -5,29 +5,31 @@ Docs: https://ghapi.fast.ai/core.html.md"""
|
|
|
5
5
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.
|
|
6
6
|
|
|
7
7
|
# %% auto #0
|
|
8
|
-
__all__ = ['GH_HOST', 'pspec', 'img_md_pat', 'EMPTY_TREE_SHA', '
|
|
9
|
-
'GhApi', 'call_gh', 'date2gh', 'gh2date', 'GhRows', 'delete_release', 'create_release',
|
|
10
|
-
'list_branches', 'create_branch_empty', 'delete_tag', 'delete_branch', 'get_branch',
|
|
11
|
-
'list_files', 'get_content', 'create_or_update_file', 'create_file', 'delete_file',
|
|
12
|
-
'enable_pages', 'read_issue', 'read_pr', 'pr_file_diff', 'PullRow', 'PullRows',
|
|
13
|
-
'
|
|
14
|
-
'local_dep_graph', 'dep_closure', 'dep_order', 'dep_dependents', 'dep_graph',
|
|
8
|
+
__all__ = ['GH_HOST', 'pspec', 'img_md_pat', 'EMPTY_TREE_SHA', 'MAXLEN', 'GhTransport', 'GhSyncTransport', 'print_summary',
|
|
9
|
+
'gh_patch', 'GhApi', 'call_gh', 'date2gh', 'gh2date', 'GhRows', 'delete_release', 'create_release',
|
|
10
|
+
'list_tags', 'list_branches', 'create_branch_empty', 'delete_tag', 'delete_branch', 'get_branch',
|
|
11
|
+
'commit_tree', 'list_files', 'get_content', 'create_or_update_file', 'create_file', 'delete_file',
|
|
12
|
+
'update_contents', 'enable_pages', 'read_issue', 'read_pr', 'pr_file_diff', 'PullRow', 'PullRows',
|
|
13
|
+
'list_prs', 'issue_template', 'issue_body', 'CheckRun', 'CommitStatus', 'check_status', 'pr_status',
|
|
14
|
+
'failed_step_log', 'dep_key', 'local_dep_graph', 'dep_closure', 'dep_order', 'dep_dependents', 'dep_graph',
|
|
15
|
+
'APIError']
|
|
15
16
|
|
|
16
17
|
# %% ../nbs/00_core.ipynb #5b5cba7b
|
|
17
18
|
from contextvars import ContextVar
|
|
18
19
|
|
|
19
20
|
from fastcore.all import *
|
|
21
|
+
from fastcore.ansi import strip_ansi
|
|
20
22
|
from fastspec.spec import SpecParser
|
|
21
23
|
from fastspec.oapi import OpenAPIClient, OpFunc, SyncOpFunc
|
|
22
|
-
from
|
|
24
|
+
from fasttransport.core import AsyncTransport, SyncTransport
|
|
23
25
|
from .gh_spec import spec
|
|
24
|
-
from
|
|
26
|
+
from fasttransport.errors import APIError
|
|
25
27
|
|
|
26
28
|
import mimetypes,base64
|
|
27
29
|
from collections import Counter
|
|
28
30
|
from urllib.parse import quote
|
|
29
31
|
from datetime import datetime, timezone
|
|
30
|
-
import os, shutil, tempfile, subprocess, fnmatch, html
|
|
32
|
+
import os, shutil, tempfile, subprocess, fnmatch, html, io, zipfile
|
|
31
33
|
import asyncio
|
|
32
34
|
|
|
33
35
|
try: import tomllib
|
|
@@ -142,7 +144,7 @@ class GhApi(OpenAPIClient):
|
|
|
142
144
|
if verb is None: verb = 'POST' if data else 'GET'
|
|
143
145
|
if route: path = path.format(**{k:quote(str(v), safe='') for k,v in route.items()})
|
|
144
146
|
if not path.startswith(('http://', 'https://')): path = self.gh_host + path
|
|
145
|
-
kw = dict(content=data) if isinstance(data, (bytes,str)) else dict(
|
|
147
|
+
kw = dict(content=data) if isinstance(data, (bytes,str)) else dict(json=data)
|
|
146
148
|
return self.transport.request(verb, path, headers=headers, params=query, **kw)
|
|
147
149
|
|
|
148
150
|
@property
|
|
@@ -487,7 +489,7 @@ async def read_pr(
|
|
|
487
489
|
diff = _reduce_ctx(_filter_diff(info.diff, folder=folder))
|
|
488
490
|
res += f"\n\n## Diff\n```diff\n{diff}\n```"
|
|
489
491
|
if replies: res += _fmt_replies(info)
|
|
490
|
-
return res
|
|
492
|
+
return TruncatedString(res, 8_000)
|
|
491
493
|
|
|
492
494
|
# %% ../nbs/00_core.ipynb #69d12346
|
|
493
495
|
async def pr_file_diff(
|
|
@@ -505,6 +507,8 @@ async def pr_file_diff(
|
|
|
505
507
|
return f"File `{filename}` not found in PR #{pr_number}"
|
|
506
508
|
|
|
507
509
|
# %% ../nbs/00_core.ipynb #2c94c2c8
|
|
510
|
+
MAXLEN = 180 # Most characters shown per displayed line
|
|
511
|
+
|
|
508
512
|
def _age(s):
|
|
509
513
|
"Compact age of ISO-8601 timestamp `s`"
|
|
510
514
|
secs = (datetime.now(timezone.utc) - datetime.fromisoformat(s.replace('Z', '+00:00'))).total_seconds()
|
|
@@ -520,21 +524,21 @@ def _pr_mark(r):
|
|
|
520
524
|
|
|
521
525
|
class PullRow(AttrDict):
|
|
522
526
|
"One pull request as an actionable line"
|
|
523
|
-
def line(self, maxlen=
|
|
527
|
+
def line(self, maxlen=MAXLEN): return f'#{self.number} {_age(self.updated_at)} {_pr_mark(self)}{truncstr(self.title, maxlen)}'
|
|
524
528
|
__repr__ = line
|
|
525
529
|
|
|
526
530
|
class PullRows(GhRows):
|
|
527
531
|
"Pull request rows, displayed with titles truncated to `maxlen`"
|
|
528
|
-
def __init__(self, items, maxlen=
|
|
532
|
+
def __init__(self, items, maxlen=MAXLEN):
|
|
529
533
|
super().__init__(items)
|
|
530
534
|
self.maxlen = maxlen
|
|
531
|
-
def __repr__(self): return '\n'.join(o.line(self.maxlen) for o in self)
|
|
535
|
+
def __repr__(self): return '\n'.join(o.line(self.maxlen) for o in self) or 'no PRs'
|
|
532
536
|
|
|
533
537
|
@gh_patch
|
|
534
538
|
async def list_prs(
|
|
535
539
|
self:GhApi,
|
|
536
540
|
state='open', # 'open', 'closed', or 'all'
|
|
537
|
-
maxlen=
|
|
541
|
+
maxlen=MAXLEN, # Title characters shown per row
|
|
538
542
|
per_page=100, # PRs per request (100 max)
|
|
539
543
|
page=1, # Page of results, for repos with more than `per_page` PRs
|
|
540
544
|
)->PullRows:
|
|
@@ -622,15 +626,14 @@ async def pr_status(self:GhApi, pull_number:int):
|
|
|
622
626
|
async def failed_step_log(self:GhApi, job_id:int):
|
|
623
627
|
"Log sections of `job_id`'s failed steps, each headed by its step name"
|
|
624
628
|
job = await self.actions.get_job_for_workflow_run(job_id=job_id)
|
|
625
|
-
|
|
629
|
+
zf = zipfile.ZipFile(io.BytesIO(await self.actions.download_workflow_run_logs(run_id=job.run_id)))
|
|
626
630
|
res = []
|
|
627
631
|
for s in job.steps:
|
|
628
632
|
if s.conclusion!='failure': continue
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
return '\n\n'.join(res)
|
|
633
|
+
name = first(n for n in zf.namelist() if n.startswith(f'{job.name}/{s.number}_'))
|
|
634
|
+
lines = [strip_ansi(l.split(' ', 1)[-1]) for l in zf.read(name).decode().splitlines()]
|
|
635
|
+
res.append(f'# {s.name}\n' + '\n'.join(lines))
|
|
636
|
+
return TruncatedString('\n\n'.join(res), 8_000)
|
|
634
637
|
|
|
635
638
|
# %% ../nbs/00_core.ipynb #751c4e54
|
|
636
639
|
def dep_key(dep):
|
|
@@ -11,7 +11,7 @@ __all__ = ['paged', 'parse_link_hdr', 'pages', 'sync_paged', 'sync_pages', 'Noti
|
|
|
11
11
|
from fastcore.all import *
|
|
12
12
|
from .core import *
|
|
13
13
|
from .core import _age
|
|
14
|
-
from
|
|
14
|
+
from fasttransport.errors import APIError
|
|
15
15
|
|
|
16
16
|
import re, asyncio
|
|
17
17
|
from datetime import datetime, timedelta, timezone
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""GitHub REST API access via `GhApi`, plus local git operations via `fastgit.Git`.
|
|
1
|
+
"""GitHub REST API access via `GhApi`, plus local git operations via `fastgit.Git`. Trigger: ALWAYS read before reading/creating issues and PRs, checking CI status, managing releases/branches/gists, and doing repo-local git operations.
|
|
2
2
|
|
|
3
3
|
`ghapi` is a full, always-up-to-date wrapper over the entire GitHub REST API, dynamically generated from GitHub's own OpenAPI spec. `fastgit` is a tiny complementary wrapper around the local `git` CLI, for anything that's about the local repo rather than GitHub's servers -- cheaper, and not rate-limited. As of v2, `ghapi` is async by default: `await` every API call (notebooks and modern REPLs support top-level `await`; scripts use `asyncio.run`). For sync code, `GhApi(sync=True)` gives a client whose generated endpoint calls block and return results directly (the convenience methods below stay async-only; drive those with `fastcore.aio.run_sync` on an async client. `paged`/`pages` have sync twins `sync_paged`/`sync_pages`).
|
|
4
4
|
|
|
@@ -90,7 +90,7 @@ Once the PR exists, the fork branch is the source of truth, and the local clone
|
|
|
90
90
|
- Results with tuned reprs (`read_issue`, `check_status`, `list_prs`, `gh_notifs`) display bare. Raw endpoint results don't, so when only confirmation matters (a `create_comment`, a `pulls.update`), assign the result to a variable and show one key (`r.html_url`, `r.state`) instead of displaying the whole payload.
|
|
91
91
|
- A PR *is* an issue for general comments (`issues.list_comments`, not `pulls.*`) -- inline code-review comments are the separate `pulls.list_review_comments`.
|
|
92
92
|
- Rate limits: register `limit_cb` on `GhApi(...)` to get called back whenever the remaining quota changes, or check `api.limit_rem` any time.
|
|
93
|
-
- HTTP errors raise `
|
|
93
|
+
- HTTP errors raise `fasttransport.errors.APIError`, which carries `.status_code` and the endpoint called.
|
|
94
94
|
- `per_page` maxes out at 100; beyond that, use `paged`/`pages` rather than manually looping `page=`.
|
|
95
95
|
- Per-call headers on named endpoints use `headers_=` (e.g. `await api.pulls.get(n, headers_={'Accept': 'application/vnd.github.v3.diff'})` for the raw diff); plain `headers=` is a kwarg only for direct `api(path, verb, ...)` calls.
|
|
96
96
|
- `GITHUB_TOKEN` unset means unauthenticated (heavily rate-limited, no write access) -- `GhApi()` warns but doesn't raise.
|
|
@@ -14,8 +14,8 @@ $NEEDS
|
|
|
14
14
|
matrix: { os: $OPERSYS }
|
|
15
15
|
runs-on: ${{ matrix.os }}-latest
|
|
16
16
|
steps:
|
|
17
|
-
- uses: actions/checkout@
|
|
18
|
-
- uses: actions/setup-python@
|
|
17
|
+
- uses: actions/checkout@v7
|
|
18
|
+
- uses: actions/setup-python@v7
|
|
19
19
|
with: {python-version: '3.12'}
|
|
20
20
|
- name: Run script
|
|
21
21
|
env:
|
|
@@ -30,8 +30,8 @@ pre_tmpl = """prebuild:
|
|
|
30
30
|
outputs:
|
|
31
31
|
out: ${{ toJson(steps) }}
|
|
32
32
|
steps:
|
|
33
|
-
- uses: actions/checkout@
|
|
34
|
-
- uses: actions/setup-python@
|
|
33
|
+
- uses: actions/checkout@v7
|
|
34
|
+
- uses: actions/setup-python@v7
|
|
35
35
|
with: {python-version: '3.12'}
|
|
36
36
|
- name: Create release
|
|
37
37
|
id: step1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ghapi
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.3
|
|
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.2.
|
|
19
|
-
Requires-Dist: fastspec>=0.2.
|
|
18
|
+
Requires-Dist: fastcore>=2.2.7
|
|
19
|
+
Requires-Dist: fastspec>=0.2.1
|
|
20
|
+
Requires-Dist: fasttransport>=0.0.2
|
|
20
21
|
Requires-Dist: tomli; python_version < "3.11"
|
|
21
22
|
Provides-Extra: dev
|
|
22
23
|
Requires-Dist: fastgit; extra == "dev"
|
|
@@ -12,7 +12,7 @@ license = {text = "Apache-2.0"}
|
|
|
12
12
|
authors = [{name = "Jeremy Howard", email = "info@fast.ai"}]
|
|
13
13
|
keywords = ['github', 'api']
|
|
14
14
|
classifiers = ["Natural Language :: English", "Intended Audience :: Developers", "Development Status :: 5 - Production/Stable", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only"]
|
|
15
|
-
dependencies = ['fastcore>=2.2.
|
|
15
|
+
dependencies = ['fastcore>=2.2.7', 'fastspec>=0.2.1', 'fasttransport>=0.0.2', 'tomli; python_version < "3.11"']
|
|
16
16
|
|
|
17
17
|
[project.urls]
|
|
18
18
|
Repository = "https://github.com/fastai/ghapi"
|
ghapi-2.1.1/ghapi/__init__.py
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"""A python client for the GitHub API
|
|
2
|
-
|
|
3
|
-
Modules:
|
|
4
|
-
|
|
5
|
-
- `ghapi.graphql`: Query GitHub's GraphQL API: schema-aware chained queries, one-request batching, and raw GraphQL
|
|
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."""
|
|
7
|
-
|
|
8
|
-
__version__ = "2.1.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|