Things on this page are fragmentary and immature notes/thoughts of the author. Please read with your own judgement!
Comments¶
There seem to be issues with the library. It is suggested that you call GitHub REST APIs directly, which is very straightforwad. For more discussions on GitHub APIs, please refer to GitHub API .
!pip3 install ghapiDefaulting to user installation because normal site-packages is not writeable
Collecting ghapi
Downloading ghapi-0.1.20-py3-none-any.whl (53 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 54.0/54.0 KB 1.2 MB/s eta 0:00:00a 0:00:01
Collecting fastcore
Downloading fastcore-1.4.2-py3-none-any.whl (60 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 60.1/60.1 KB 1.7 MB/s eta 0:00:00
Requirement already satisfied: pip in /usr/local/lib/python3.8/dist-packages (from ghapi) (22.0.4)
Requirement already satisfied: packaging in /usr/local/lib/python3.8/dist-packages (from ghapi) (21.3)
Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /usr/local/lib/python3.8/dist-packages (from packaging->ghapi) (3.0.8)
Installing collected packages: fastcore, ghapi
Successfully installed fastcore-1.4.2 ghapi-0.1.20
from ghapi.all import GhApi
api = GhApi(owner="dclong", token="ghp_xxxxxxxxxxxxxxxxxxxxxxxxx")Methods of GhApi¶
[m for m in dir(api) if not m.startswith("_")]['actions',
'activity',
'apps',
'billing',
'checks',
'code_scanning',
'codes_of_conduct',
'codespaces',
'create_branch_empty',
'create_gist',
'create_release',
'debug',
'delete_branch',
'delete_release',
'delete_tag',
'dependabot',
'dependency_graph',
'emojis',
'enable_pages',
'enterprise_admin',
'fetch_events',
'full_docs',
'func_dict',
'get_branch',
'get_content',
'gh_host',
'gists',
'git',
'gitignore',
'groups',
'headers',
'interactions',
'issues',
'last_page',
'licenses',
'limit_cb',
'limit_rem',
'list_branches',
'list_events',
'list_events_parallel',
'list_files',
'list_tags',
'markdown',
'meta',
'migrations',
'oauth_authorizations',
'orgs',
'packages',
'projects',
'pulls',
'rate_limit',
'reactions',
'repos',
'scim',
'search',
'secret_scanning',
'teams',
'update_contents',
'upload_file',
'users']GhApi.repos¶
api.reposLoading...
repos = api.repos.list_for_org("legendu-net", per_page=100)len(repos)61Get all Docker related repositories in the org legendu-net.
repos_docker = [repo.name for repo in repos.items if repo.name.startswith("docker-")]
repos_docker['docker-rstudio',
'docker-ubuntu_cn',
'docker-jupyterlab',
'docker-jupyterhub-rb',
'docker-r-base',
'docker-r-pop',
'docker-jupyterhub-rp',
'docker-jupyterhub-toree',
'docker-python',
'docker-jdk',
'docker-dryscrape',
'docker-nodejs',
'docker-typescript',
'docker-jupyterhub-ts',
'docker-jupyterhub-ds',
'docker-base',
'docker-xubuntu-py',
'docker-samba',
'docker-conda',
'docker-conda-yarn',
'docker-jupyter',
'docker-jupyterhub',
'docker-jupyterhub-jdk',
'docker-jupyterhub-antlr4',
'docker-python-jdk',
'docker-nfs',
'docker-conda-build',
'docker-mlflow',
'docker-python-nodejs',
'docker-jupyterhub-sagemath',
'docker-lubuntu',
'docker-lubuntu-jdk',
'docker-jupyterhub-julia',
'docker-jupyterhub-almond',
'docker-jupyterlab-quickopen',
'docker-deepin',
'docker-deepin_b',
'docker-deepin_cn',
'docker-ldeepin',
'docker-lubuntu-pyside2',
'docker-jupyterhub-selenium-firefox',
'docker-jupyterhub-selenium-chrome',
'docker-vscode-server',
'docker-gitpod',
'docker-jupyterhub-cuda',
'docker-jupyterhub-cuda-dev',
'docker-jupyterhub-pytorch',
'docker-jupyterhub-more',
'docker-rustpython',
'docker-rust',
'docker-python-portable',
'docker-pypy',
'docker-rust-utils',
'docker-tensorboard',
'docker-evcxr_jupyter',
'docker-jupyterhub-golang',
'docker-jupyterhub-kotlin']GhApi.Actions¶
api.actionsLoading...
[m for m in dir(api.actions) if "secret" in m]['add_selected_repo_to_org_secret',
'create_or_update_environment_secret',
'create_or_update_org_secret',
'create_or_update_repo_secret',
'delete_environment_secret',
'delete_org_secret',
'delete_repo_secret',
'get_environment_secret',
'get_org_secret',
'get_repo_secret',
'list_environment_secrets',
'list_org_secrets',
'list_repo_secrets',
'list_selected_repos_for_org_secret',
'remove_selected_repo_from_org_secret',
'set_selected_repos_for_org_secret']List secrets in the repository dclong/blog.
api.actions.list_repo_secrets(owner="dclong", repo="blog")Loading...
api.actions.list_repo_secrets(owner="legendu-net", repo="xinstall")Loading...
api.actions.get_repo_secret("xinstall", "PYPI_XINSTALL")Loading...
api.actions.get_repo_secret("docker_image_builder", "DOCKERHUB_USERNAME")Loading...
api.actions.list_repo_secrets(owner="legendu-net", repo="xinstall")Loading...
api.actions.list_repo_secrets(owner="legendu-net", repo="docker-jupyterhub-cuda")Loading...
List secrets in the repository legendu-net/xinstall.
?api.actions.delete_repo_secretSignature: api.actions.delete_repo_secret(repo, secret_name)
Type: _GhVerb
String form:
actions.delete_repo_secret(repo, secret_name)
https://docs.github.com/rest/reference/actions#delete-a-repository-secret
File: ~/.local/lib/python3.8/site-packages/ghapi/core.py
Docstring: Delete a repository secret
api.actions.delete_repo_secret(
owner="legendu-net", repo="docker-jupyterhub-cuda", secret_name="GITHUBACTIONS"
)---------------------------------------------------------------------------
HTTPError Traceback (most recent call last)
Input In [150], in <cell line: 1>()
----> 1 api.actions.delete_repo_secret(owner="legendu-net", repo="docker-jupyterhub-cuda", secret_name="GITHUBACTIONS")
File ~/.local/lib/python3.8/site-packages/ghapi/core.py:63, in _GhVerb.__call__(self, headers, *args, **kwargs)
60 kwargs = {k:v for k,v in kwargs.items() if v is not None}
61 route_p,query_p,data_p = [{p:kwargs[p] for p in o if p in kwargs}
62 for o in (self.route_ps,self.params,d)]
---> 63 return self.client(self.path, self.verb, headers=headers, route=route_p, query=query_p, data=data_p)
File ~/.local/lib/python3.8/site-packages/ghapi/core.py:112, in GhApi.__call__(self, path, verb, headers, route, query, data)
110 if route:
111 for k,v in route.items(): route[k] = quote(str(route[k]))
--> 112 res,self.recv_hdrs = urlsend(path, verb, headers=headers or None, debug=self.debug, return_headers=True,
113 route=route or None, query=query or None, data=data or None)
114 if 'X-RateLimit-Remaining' in self.recv_hdrs:
115 newlim = self.recv_hdrs['X-RateLimit-Remaining']
File ~/.local/lib/python3.8/site-packages/fastcore/net.py:212, in urlsend(url, verb, headers, route, query, data, json_data, return_json, return_headers, debug)
209 if route and route.get('archive_format', None):
210 return urlread(req, decode=False, return_json=False, return_headers=return_headers)
--> 212 return urlread(req, return_json=return_json, return_headers=return_headers)
File ~/.local/lib/python3.8/site-packages/fastcore/net.py:111, in urlread(url, data, headers, decode, return_json, return_headers, timeout, **kwargs)
109 "Retrieve `url`, using `data` dict or `kwargs` to `POST` if present"
110 try:
--> 111 with urlopen(url, data=data, headers=headers, timeout=timeout, **kwargs) as u: res,hdrs = u.read(),u.headers
112 except HTTPError as e:
113 if 400 <= e.code < 500: raise ExceptionsHTTP[e.code](e.url, e.hdrs, e.fp) from None
File ~/.local/lib/python3.8/site-packages/fastcore/net.py:105, in urlopen(url, data, headers, timeout, **kwargs)
103 if not isinstance(data, (str,bytes)): data = urlencode(data)
104 if not isinstance(data, bytes): data = data.encode('ascii')
--> 105 return _opener.open(urlwrap(url, data=data, headers=headers), timeout=timeout)
File /usr/lib/python3.8/urllib/request.py:531, in OpenerDirector.open(self, fullurl, data, timeout)
529 for processor in self.process_response.get(protocol, []):
530 meth = getattr(processor, meth_name)
--> 531 response = meth(req, response)
533 return response
File /usr/lib/python3.8/urllib/request.py:640, in HTTPErrorProcessor.http_response(self, request, response)
637 # According to RFC 2616, "2xx" code indicates that the client's
638 # request was successfully received, understood, and accepted.
639 if not (200 <= code < 300):
--> 640 response = self.parent.error(
641 'http', request, response, code, msg, hdrs)
643 return response
File /usr/lib/python3.8/urllib/request.py:563, in OpenerDirector.error(self, proto, *args)
561 http_err = 0
562 args = (dict, proto, meth_name) + args
--> 563 result = self._call_chain(*args)
564 if result:
565 return result
File /usr/lib/python3.8/urllib/request.py:502, in OpenerDirector._call_chain(self, chain, kind, meth_name, *args)
500 for handler in handlers:
501 func = getattr(handler, meth_name)
--> 502 result = func(*args)
503 if result is not None:
504 return result
File /usr/lib/python3.8/urllib/request.py:734, in HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
729 newurl = urljoin(req.full_url, newurl)
731 # XXX Probably want to forget about the state of the current
732 # request, although that might interact poorly with other
733 # handlers that also use handler-specific request attributes
--> 734 new = self.redirect_request(req, fp, code, msg, headers, newurl)
735 if new is None:
736 return
File /usr/lib/python3.8/urllib/request.py:672, in HTTPRedirectHandler.redirect_request(self, req, fp, code, msg, headers, newurl)
669 m = req.get_method()
670 if (not (code in (301, 302, 303, 307) and m in ("GET", "HEAD")
671 or code in (301, 302, 303) and m == "POST")):
--> 672 raise HTTPError(req.full_url, code, msg, headers, fp)
674 # Strictly (according to RFC 2616), 301 or 302 in response to
675 # a POST MUST NOT cause a redirection without confirmation
676 # from the user (of urllib.request, in this case). In practice,
(...)
681 # redundant with the more complete encoding done in http_error_302(),
682 # but it is kept for compatibility with other callers.
683 newurl = newurl.replace(' ', '%20')
HTTPError: HTTP Error 307: Temporary RedirectGhApi.issues¶
api.issues.list()Unexpected exception formatting exception. Falling back to standard exception
Traceback (most recent call last):
File "/usr/local/lib/python3.8/dist-packages/IPython/core/interactiveshell.py", line 3397, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "/tmp/ipykernel_3545/1632110837.py", line 1, in <cell line: 1>
api.issues.list()
File "/home/dclong/.local/lib/python3.8/site-packages/ghapi/core.py", line 63, in __call__
return self.client(self.path, self.verb, headers=headers, route=route_p, query=query_p, data=data_p)
File "/home/dclong/.local/lib/python3.8/site-packages/ghapi/core.py", line 112, in __call__
res,self.recv_hdrs = urlsend(path, verb, headers=headers or None, debug=self.debug, return_headers=True,
File "/home/dclong/.local/lib/python3.8/site-packages/fastcore/net.py", line 212, in urlsend
return urlread(req, return_json=return_json, return_headers=return_headers)
File "/home/dclong/.local/lib/python3.8/site-packages/fastcore/net.py", line 113, in urlread
if 400 <= e.code < 500: raise ExceptionsHTTP[e.code](e.url, e.hdrs, e.fp) from None
fastcore.basics.HTTP404NotFoundError: HTTP Error 404: Not Found
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/dist-packages/IPython/core/interactiveshell.py", line 1989, in showtraceback
if hasattr(value, "_render_traceback_"):
File "/usr/lib/python3.8/tempfile.py", line 606, in __getattr__
file = self.__dict__['file']
KeyError: 'file'
api.issuesLoading...
api.oauth_authorizationsLoading...
api.secret_scanningLoading...