ghapi 2.0.7__tar.gz → 2.1.1__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.
Files changed (29) hide show
  1. {ghapi-2.0.7/ghapi.egg-info → ghapi-2.1.1}/PKG-INFO +3 -2
  2. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/__init__.py +1 -1
  3. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/_modidx.py +14 -0
  4. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/core.py +52 -13
  5. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/page.py +38 -12
  6. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/skill.py +2 -1
  7. {ghapi-2.0.7 → ghapi-2.1.1/ghapi.egg-info}/PKG-INFO +3 -2
  8. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi.egg-info/requires.txt +2 -1
  9. {ghapi-2.0.7 → ghapi-2.1.1}/pyproject.toml +2 -2
  10. {ghapi-2.0.7 → ghapi-2.1.1}/CONTRIBUTING.md +0 -0
  11. {ghapi-2.0.7 → ghapi-2.1.1}/LICENSE +0 -0
  12. {ghapi-2.0.7 → ghapi-2.1.1}/MANIFEST.in +0 -0
  13. {ghapi-2.0.7 → ghapi-2.1.1}/README.md +0 -0
  14. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/actions.py +0 -0
  15. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/all.py +0 -0
  16. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/auth.py +0 -0
  17. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/build_lib.py +0 -0
  18. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/cli.py +0 -0
  19. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/event.py +0 -0
  20. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/gh_spec.py +0 -0
  21. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/gql_spec.py +0 -0
  22. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/graphql.py +0 -0
  23. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/py.typed +0 -0
  24. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi/templates.py +0 -0
  25. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi.egg-info/SOURCES.txt +0 -0
  26. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi.egg-info/dependency_links.txt +0 -0
  27. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi.egg-info/entry_points.txt +0 -0
  28. {ghapi-2.0.7 → ghapi-2.1.1}/ghapi.egg-info/top_level.txt +0 -0
  29. {ghapi-2.0.7 → ghapi-2.1.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ghapi
3
- Version: 2.0.7
3
+ Version: 2.1.1
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
@@ -16,7 +16,7 @@ Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Requires-Dist: fastcore>=2.2.6
19
- Requires-Dist: fastspec>=0.1.7
19
+ Requires-Dist: fastspec>=0.2.0
20
20
  Requires-Dist: tomli; python_version < "3.11"
21
21
  Provides-Extra: dev
22
22
  Requires-Dist: fastgit; extra == "dev"
@@ -26,6 +26,7 @@ Requires-Dist: nbdev; extra == "dev"
26
26
  Requires-Dist: pyyaml; extra == "dev"
27
27
  Requires-Dist: pysym2md>=0.0.6; extra == "dev"
28
28
  Requires-Dist: llms-txt>=0.0.6; extra == "dev"
29
+ Requires-Dist: pyskills; extra == "dev"
29
30
  Dynamic: license-file
30
31
 
31
32
  # ghapi
@@ -5,4 +5,4 @@ Modules:
5
5
  - `ghapi.graphql`: Query GitHub's GraphQL API: schema-aware chained queries, one-request batching, and raw GraphQL
6
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
7
 
8
- __version__ = "2.0.7"
8
+ __version__ = "2.1.1"
@@ -74,6 +74,11 @@ d = { 'settings': { 'branch': 'main',
74
74
  'ghapi.core.GhTransport._post': ('core.html#ghtransport._post', 'ghapi/core.py'),
75
75
  'ghapi.core.GhTransport._pre': ('core.html#ghtransport._pre', 'ghapi/core.py'),
76
76
  'ghapi.core.GhTransport.request': ('core.html#ghtransport.request', 'ghapi/core.py'),
77
+ 'ghapi.core.PullRow': ('core.html#pullrow', 'ghapi/core.py'),
78
+ 'ghapi.core.PullRow.line': ('core.html#pullrow.line', 'ghapi/core.py'),
79
+ 'ghapi.core.PullRows': ('core.html#pullrows', 'ghapi/core.py'),
80
+ 'ghapi.core.PullRows.__init__': ('core.html#pullrows.__init__', 'ghapi/core.py'),
81
+ 'ghapi.core.PullRows.__repr__': ('core.html#pullrows.__repr__', 'ghapi/core.py'),
77
82
  'ghapi.core._CheckStatus': ('core.html#_checkstatus', 'ghapi/core.py'),
78
83
  'ghapi.core._CheckStatus._repr_markdown_': ('core.html#_checkstatus._repr_markdown_', 'ghapi/core.py'),
79
84
  'ghapi.core._IssueInfo': ('core.html#_issueinfo', 'ghapi/core.py'),
@@ -82,6 +87,7 @@ d = { 'settings': { 'branch': 'main',
82
87
  'ghapi.core._LiveDefaults.__contains__': ('core.html#_livedefaults.__contains__', 'ghapi/core.py'),
83
88
  'ghapi.core._LiveDefaults.get': ('core.html#_livedefaults.get', 'ghapi/core.py'),
84
89
  'ghapi.core._LiveDefaults.items': ('core.html#_livedefaults.items', 'ghapi/core.py'),
90
+ 'ghapi.core._age': ('core.html#_age', 'ghapi/core.py'),
85
91
  'ghapi.core._dur': ('core.html#_dur', 'ghapi/core.py'),
86
92
  'ghapi.core._filter_diff': ('core.html#_filter_diff', 'ghapi/core.py'),
87
93
  'ghapi.core._find_matches': ('core.html#_find_matches', 'ghapi/core.py'),
@@ -89,6 +95,7 @@ d = { 'settings': { 'branch': 'main',
89
95
  'ghapi.core._include': ('core.html#_include', 'ghapi/core.py'),
90
96
  'ghapi.core._listed': ('core.html#_listed', 'ghapi/core.py'),
91
97
  'ghapi.core._parse_tmpl': ('core.html#_parse_tmpl', 'ghapi/core.py'),
98
+ 'ghapi.core._pr_mark': ('core.html#_pr_mark', 'ghapi/core.py'),
92
99
  'ghapi.core._reduce_ctx': ('core.html#_reduce_ctx', 'ghapi/core.py'),
93
100
  'ghapi.core._run_subp': ('core.html#_run_subp', 'ghapi/core.py'),
94
101
  'ghapi.core._transdeps': ('core.html#_transdeps', 'ghapi/core.py'),
@@ -119,6 +126,7 @@ d = { 'settings': { 'branch': 'main',
119
126
  'ghapi.core.issue_template': ('core.html#issue_template', 'ghapi/core.py'),
120
127
  'ghapi.core.list_branches': ('core.html#list_branches', 'ghapi/core.py'),
121
128
  'ghapi.core.list_files': ('core.html#list_files', 'ghapi/core.py'),
129
+ 'ghapi.core.list_prs': ('core.html#list_prs', 'ghapi/core.py'),
122
130
  'ghapi.core.list_tags': ('core.html#list_tags', 'ghapi/core.py'),
123
131
  'ghapi.core.local_dep_graph': ('core.html#local_dep_graph', 'ghapi/core.py'),
124
132
  'ghapi.core.pr_file_diff': ('core.html#pr_file_diff', 'ghapi/core.py'),
@@ -150,10 +158,16 @@ d = { 'settings': { 'branch': 'main',
150
158
  'ghapi.graphql.GhGql.__init__': ('graphql.html#ghgql.__init__', 'ghapi/graphql.py'),
151
159
  'ghapi.graphql.GhGql.repo': ('graphql.html#ghgql.repo', 'ghapi/graphql.py')},
152
160
  'ghapi.page': { 'ghapi.page.GhApi.last_page': ('page.html#ghapi.last_page', 'ghapi/page.py'),
161
+ 'ghapi.page.GhApi.mark_done': ('page.html#ghapi.mark_done', 'ghapi/page.py'),
162
+ 'ghapi.page.NotifRow': ('page.html#notifrow', 'ghapi/page.py'),
163
+ 'ghapi.page.NotifRow.__repr__': ('page.html#notifrow.__repr__', 'ghapi/page.py'),
164
+ 'ghapi.page.NotifRows': ('page.html#notifrows', 'ghapi/page.py'),
165
+ 'ghapi.page.NotifRows.__repr__': ('page.html#notifrows.__repr__', 'ghapi/page.py'),
153
166
  'ghapi.page._Scanner': ('page.html#_scanner', 'ghapi/page.py'),
154
167
  'ghapi.page._Scanner.__getitem__': ('page.html#_scanner.__getitem__', 'ghapi/page.py'),
155
168
  'ghapi.page._Scanner.__init__': ('page.html#_scanner.__init__', 'ghapi/page.py'),
156
169
  'ghapi.page._Scanner.scan': ('page.html#_scanner.scan', 'ghapi/page.py'),
170
+ 'ghapi.page._notif_mark': ('page.html#_notif_mark', 'ghapi/page.py'),
157
171
  'ghapi.page._parse_link_hdr': ('page.html#_parse_link_hdr', 'ghapi/page.py'),
158
172
  'ghapi.page.gh_notifs': ('page.html#gh_notifs', 'ghapi/page.py'),
159
173
  'ghapi.page.paged': ('page.html#paged', 'ghapi/page.py'),
@@ -6,12 +6,12 @@ Docs: https://ghapi.fast.ai/core.html.md"""
6
6
 
7
7
  # %% auto #0
8
8
  __all__ = ['GH_HOST', 'pspec', 'img_md_pat', 'EMPTY_TREE_SHA', 'GhTransport', 'GhSyncTransport', 'print_summary', 'gh_patch',
9
- 'GhApi', 'call_gh', 'date2gh', 'gh2date', 'delete_release', 'create_release', 'list_tags', 'list_branches',
10
- 'create_branch_empty', 'delete_tag', 'delete_branch', 'get_branch', 'commit_tree', 'list_files',
11
- 'get_content', 'create_or_update_file', 'create_file', 'delete_file', 'update_contents', 'enable_pages',
12
- 'read_issue', 'read_pr', 'pr_file_diff', 'issue_template', 'issue_body', 'CheckRun', 'CommitStatus',
13
- 'GhRows', 'check_status', 'pr_status', 'failed_step_log', 'dep_key', 'local_dep_graph', 'dep_closure',
14
- 'dep_order', 'dep_dependents', 'dep_graph', 'APIError']
9
+ 'GhApi', 'call_gh', 'date2gh', 'gh2date', 'GhRows', 'delete_release', 'create_release', 'list_tags',
10
+ 'list_branches', 'create_branch_empty', 'delete_tag', 'delete_branch', 'get_branch', 'commit_tree',
11
+ 'list_files', 'get_content', 'create_or_update_file', 'create_file', 'delete_file', 'update_contents',
12
+ 'enable_pages', 'read_issue', 'read_pr', 'pr_file_diff', 'PullRow', 'PullRows', 'list_prs', 'issue_template',
13
+ 'issue_body', 'CheckRun', 'CommitStatus', 'check_status', 'pr_status', 'failed_step_log', 'dep_key',
14
+ 'local_dep_graph', 'dep_closure', 'dep_order', 'dep_dependents', 'dep_graph', 'APIError']
15
15
 
16
16
  # %% ../nbs/00_core.ipynb #5b5cba7b
17
17
  from contextvars import ContextVar
@@ -26,7 +26,7 @@ from fastspec.errors import APIError
26
26
  import mimetypes,base64
27
27
  from collections import Counter
28
28
  from urllib.parse import quote
29
- from datetime import datetime
29
+ from datetime import datetime, timezone
30
30
  import os, shutil, tempfile, subprocess, fnmatch, html
31
31
  import asyncio
32
32
 
@@ -178,6 +178,11 @@ def gh2date(dtstr:str)->datetime:
178
178
  "Convert date string `dtstr` received from a GitHub API operation to a UTC `datetime`"
179
179
  return datetime.fromisoformat(dtstr.replace('Z', ''))
180
180
 
181
+ # %% ../nbs/00_core.ipynb #7876622c
182
+ class GhRows(L):
183
+ "Result rows whose bare display is one actionable line each"
184
+ def __repr__(self): return '\n'.join(map(repr, self))
185
+
181
186
  # %% ../nbs/00_core.ipynb #16068542
182
187
  img_md_pat = re.compile(r'!\[(?P<alt>.*?)\]\((?P<url>[^\s]+)\)')
183
188
 
@@ -427,13 +432,13 @@ async def read_issue(self:GhApi, issue_number:int):
427
432
  res = dict(title=iss.title, body=iss.body or '', is_pr=pr is not None, # chkstyle: ignore-node
428
433
  comments=await self.issues.list_comments(issue_number))
429
434
  if pr is not None:
430
- res['diff'] = await self.pulls.get(issue_number, _headers={'Accept': 'application/vnd.github.v3.diff'})
435
+ res['diff'] = await self.pulls.get(issue_number, headers_={'Accept': 'application/vnd.github.v3.diff'})
431
436
  res['review_comments'] = await self.pulls.list_review_comments(issue_number)
432
437
  res['reviews'] = await self.pulls.list_reviews(issue_number)
433
438
  else:
434
439
  evts = await self.issues.list_events(issue_number)
435
440
  sha = first(e.commit_id for e in evts if e.commit_id)
436
- if sha: res['diff'] = await self.repos.get_commit(sha, _headers={'Accept': 'application/vnd.github.v3.diff'})
441
+ if sha: res['diff'] = await self.repos.get_commit(sha, headers_={'Accept': 'application/vnd.github.v3.diff'})
437
442
  return _IssueInfo(dict2obj(res))
438
443
 
439
444
  # %% ../nbs/00_core.ipynb #ccf9d458
@@ -499,6 +504,44 @@ async def pr_file_diff(
499
504
  if f.filename == filename: return f"## {f.filename} (+{f.additions} -{f.deletions})\n\n```diff\n{html.unescape(f.patch)}\n```"
500
505
  return f"File `{filename}` not found in PR #{pr_number}"
501
506
 
507
+ # %% ../nbs/00_core.ipynb #2c94c2c8
508
+ def _age(s):
509
+ "Compact age of ISO-8601 timestamp `s`"
510
+ secs = (datetime.now(timezone.utc) - datetime.fromisoformat(s.replace('Z', '+00:00'))).total_seconds()
511
+ for n,u in ((31536000,'y'), (2592000,'mo'), (604800,'w'), (86400,'d'), (3600,'h')):
512
+ if secs >= n: return f'{int(secs//n)}{u}'
513
+ return f'{int(secs//60)}m'
514
+
515
+ def _pr_mark(r):
516
+ if r.get('merged_at'): return 'merged '
517
+ if r.state == 'closed': return 'closed '
518
+ if r.get('draft'): return 'draft '
519
+ return ''
520
+
521
+ class PullRow(AttrDict):
522
+ "One pull request as an actionable line"
523
+ def line(self, maxlen=120): return f'#{self.number} {_age(self.updated_at)} {_pr_mark(self)}{truncstr(self.title, maxlen)}'
524
+ __repr__ = line
525
+
526
+ class PullRows(GhRows):
527
+ "Pull request rows, displayed with titles truncated to `maxlen`"
528
+ def __init__(self, items, maxlen=120):
529
+ super().__init__(items)
530
+ self.maxlen = maxlen
531
+ def __repr__(self): return '\n'.join(o.line(self.maxlen) for o in self)
532
+
533
+ @gh_patch
534
+ async def list_prs(
535
+ self:GhApi,
536
+ state='open', # 'open', 'closed', or 'all'
537
+ maxlen=120, # Title characters shown per row
538
+ per_page=100, # PRs per request (100 max)
539
+ page=1, # Page of results, for repos with more than `per_page` PRs
540
+ )->PullRows:
541
+ "Pull requests as one-line rows, most recently updated first"
542
+ prs = await self.pulls.list(state=state, sort='updated', direction='desc', per_page=per_page, page=page)
543
+ return PullRows([PullRow(o) for o in prs], maxlen=maxlen)
544
+
502
545
  # %% ../nbs/00_core.ipynb #55a976ea
503
546
  def _parse_tmpl(name, txt):
504
547
  "Parse issue template `txt`: yml forms into section labels for `issue_body`; md templates kept as `raw`"
@@ -551,10 +594,6 @@ class CheckRun(AttrDict):
551
594
  class CommitStatus(AttrDict):
552
595
  def __repr__(self): return f'{self.context}: {self.state}'
553
596
 
554
- class GhRows(L):
555
- "Result rows whose bare display is one actionable line each"
556
- def __repr__(self): return '\n'.join(map(repr, self))
557
-
558
597
  class _CheckStatus(AttrDict):
559
598
  def _repr_markdown_(self):
560
599
  runs = self.check_runs
@@ -5,11 +5,13 @@ Docs: https://ghapi.fast.ai/page.html.md"""
5
5
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/03_page.ipynb.
6
6
 
7
7
  # %% auto #0
8
- __all__ = ['paged', 'parse_link_hdr', 'pages', 'sync_paged', 'sync_pages', 'gh_notifs']
8
+ __all__ = ['paged', 'parse_link_hdr', 'pages', 'sync_paged', 'sync_pages', 'NotifRow', 'NotifRows', 'gh_notifs']
9
9
 
10
10
  # %% ../nbs/03_page.ipynb #6a0bf465
11
11
  from fastcore.all import *
12
12
  from .core import *
13
+ from .core import _age
14
+ from fastspec.errors import APIError
13
15
 
14
16
  import re, asyncio
15
17
  from datetime import datetime, timedelta, timezone
@@ -87,17 +89,41 @@ def sync_pages(oper, n_pages, *args, per_page=100, n_workers=16, **kwargs):
87
89
  range(n_pages), threadpool=True, n_workers=n_workers))
88
90
 
89
91
  # %% ../nbs/03_page.ipynb #58141083
92
+ class NotifRow(AttrDict):
93
+ "One notification thread as an actionable line"
94
+ def __repr__(self):
95
+ s = self.subject
96
+ num = s.url.rpartition('/')[2] if s.url else ''
97
+ kind = ('PR' if s.type=='PullRequest' else s.type) + (f' #{num}' if num.isdigit() else '')
98
+ return f'{self.id} {_age(self.updated_at)} {self.reason} {self.repository.full_name} {self.get("mark","")}{kind}: {s.title}'
99
+
100
+ class NotifRows(GhRows):
101
+ "Notification rows; displays 'no notifications' when empty"
102
+ def __repr__(self): return super().__repr__() or 'no notifications'
103
+
104
+ def _notif_mark(sub):
105
+ "`[merged] `/`[closed] ` marker for a fetched subject; empty for open or unfetchable subjects"
106
+ if not sub: return ''
107
+ if sub.get('merged_at'): return '[merged] '
108
+ if sub.get('state') == 'closed': return '[closed] '
109
+ return ''
110
+
90
111
  async def gh_notifs(days=5, reasons=('mention', 'review_requested', 'author', 'assign'), include_read=False, per_page=100):
91
- "Get GitHub notifications from the past `days`, formatted as a summary string"
112
+ "Notifications from the past `days` (all available if None) as `NotifRows`, marked `[closed]`/`[merged]` when the subject is no longer open; `reasons=None` includes every reason"
113
+ api = GhApi()
92
114
  since = (datetime.now(timezone.utc) - timedelta(days=days)).isoformat() if days else None
93
- notifs = L([o async for o in paged(GhApi().activity.list_notifications_for_authenticated_user, all=include_read, since=since, per_page=per_page)]).concat()
115
+ notifs = L([o async for o in paged(api.activity.list_notifications_for_authenticated_user, all=include_read, since=since, per_page=per_page)]).concat()
94
116
  if reasons: notifs = notifs.filter(lambda n: n.reason in reasons)
95
- lines = []
96
- for n in notifs:
97
- repo, kind = n.repository.full_name, n.subject.type
98
- num = n.subject.url.split('/')[-1] if n.subject.url else '?'
99
- url = f"https://github.com/{repo}/pull/{num}" if kind == 'PullRequest' else f"https://github.com/{repo}/issues/{num}" if kind == 'Issue' else n.subject.url
100
- lines.append(f"- [{kind} #{num}]({url}) {repo} — {n.subject.title} ({n.reason})")
101
- scope = f"past {days} days" if days else "all available"
102
- reason_txt = ", ".join(reasons) if reasons else "all reasons"
103
- return f"**{len(lines)} notifications** ({scope}; {reason_txt})\n\n" + "\n".join(lines)
117
+ async def _get(u):
118
+ if not u: return None
119
+ try: return await api(u, 'GET')
120
+ except APIError: return None # deleted or inaccessible subjects lose their mark, not the whole listing
121
+ subs = await asyncio.gather(*(_get(n.subject.url) for n in notifs))
122
+ for n, s in zip(notifs, subs): n['mark'] = _notif_mark(s)
123
+ return NotifRows(NotifRow(o) for o in notifs)
124
+
125
+ # %% ../nbs/03_page.ipynb #abc91f9e
126
+ @patch
127
+ async def mark_done(self:GhApi, *ids):
128
+ "Mark notification threads as done, removing them from the inbox (the API cannot list done threads back)"
129
+ await asyncio.gather(*(self.activity.mark_thread_as_done(i) for i in ids))
@@ -87,11 +87,12 @@ Once the PR exists, the fork branch is the source of truth, and the local clone
87
87
 
88
88
  # Gotchas
89
89
 
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.
90
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`.
91
92
  - Rate limits: register `limit_cb` on `GhApi(...)` to get called back whenever the remaining quota changes, or check `api.limit_rem` any time.
92
93
  - HTTP errors raise `fastspec.errors.APIError`, which carries `.status_code` and the endpoint called.
93
94
  - `per_page` maxes out at 100; beyond that, use `paged`/`pages` rather than manually looping `page=`.
94
- - 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.
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.
95
96
  - `GITHUB_TOKEN` unset means unauthenticated (heavily rate-limited, no write access) -- `GhApi()` warns but doesn't raise.
96
97
  """
97
98
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ghapi
3
- Version: 2.0.7
3
+ Version: 2.1.1
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
@@ -16,7 +16,7 @@ Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Requires-Dist: fastcore>=2.2.6
19
- Requires-Dist: fastspec>=0.1.7
19
+ Requires-Dist: fastspec>=0.2.0
20
20
  Requires-Dist: tomli; python_version < "3.11"
21
21
  Provides-Extra: dev
22
22
  Requires-Dist: fastgit; extra == "dev"
@@ -26,6 +26,7 @@ Requires-Dist: nbdev; extra == "dev"
26
26
  Requires-Dist: pyyaml; extra == "dev"
27
27
  Requires-Dist: pysym2md>=0.0.6; extra == "dev"
28
28
  Requires-Dist: llms-txt>=0.0.6; extra == "dev"
29
+ Requires-Dist: pyskills; extra == "dev"
29
30
  Dynamic: license-file
30
31
 
31
32
  # ghapi
@@ -1,5 +1,5 @@
1
1
  fastcore>=2.2.6
2
- fastspec>=0.1.7
2
+ fastspec>=0.2.0
3
3
 
4
4
  [:python_version < "3.11"]
5
5
  tomli
@@ -12,3 +12,4 @@ nbdev
12
12
  pyyaml
13
13
  pysym2md>=0.0.6
14
14
  llms-txt>=0.0.6
15
+ pyskills
@@ -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.6', 'fastspec>=0.1.7', 'tomli; python_version < "3.11"']
15
+ dependencies = ['fastcore>=2.2.6', 'fastspec>=0.2.0', 'tomli; python_version < "3.11"']
16
16
 
17
17
  [project.urls]
18
18
  Repository = "https://github.com/fastai/ghapi"
@@ -25,7 +25,7 @@ ghapi = "ghapi._modidx:d"
25
25
  ghapi = "ghapi.skill"
26
26
 
27
27
  [project.optional-dependencies]
28
- dev = ['fastgit', 'matplotlib', 'nbclassic', 'nbdev', 'pyyaml', 'pysym2md>=0.0.6', 'llms-txt>=0.0.6']
28
+ dev = ['fastgit', 'matplotlib', 'nbclassic', 'nbdev', 'pyyaml', 'pysym2md>=0.0.6', 'llms-txt>=0.0.6', 'pyskills']
29
29
 
30
30
 
31
31
  [project.scripts]
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