Skip to content

Commit

Permalink
verbs
Browse files Browse the repository at this point in the history
  • Loading branch information
jph00 committed Nov 23, 2020
1 parent 3069f94 commit 6cafe13
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 271 deletions.
88 changes: 68 additions & 20 deletions 00_core.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
"from fastcore.utils import *\n",
"from fastcore.foundation import *\n",
"from fastcore.meta import *\n",
"from urllib import request\n",
"import pprint,inspect\n",
"\n",
"import pprint,inspect,json\n",
"from inspect import signature,Parameter\n",
"from ghapi.build_lib import build_funcs, GH_DOC_URL\n",
"from ghapi.metadata import funcs"
"from ghapi.metadata import funcs\n",
"from urllib.request import Request"
]
},
{
Expand All @@ -34,7 +34,7 @@
"source": [
"#export\n",
"GH_HOST = \"https://api.github.com\"\n",
"_DOC_URL = GH_DOC_URL"
"_DOC_URL = 'https://docs.github.com/'"
]
},
{
Expand Down Expand Up @@ -80,9 +80,8 @@
"def _call(self, *args, **kwargs):\n",
" # TODO: post data\n",
" for a,b in zip(args,self.params): kwargs[b]=a\n",
" kw = {p:kwargs[p] for p in self.params}\n",
" path = self.path.format(**kw)\n",
" return self.client(path)\n",
" path = self.path.format(**{p:kwargs[p] for p in self.params})\n",
" return self.client(path, self.verb, **{p:kwargs[p] for p in self.data if p in kwargs})\n",
"\n",
"_self_param = [Parameter('self', Parameter.POSITIONAL_OR_KEYWORD)]\n",
"\n",
Expand Down Expand Up @@ -129,6 +128,19 @@
" def _repr_markdown_(self): return \"\\n\".join(f'- [{k}]({_DOC_URL}{v.url})' for k,v in self.items())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def _send(url, verb, headers=None, **data):\n",
" \"Call GET or json-encoded POST on `url`, depending on `post`\"\n",
" if data: data = json.dumps(data).encode('ascii')\n",
" req = Request(url, headers=headers, data=data or None, method=verb)\n",
" return urljson(req)"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -137,11 +149,11 @@
"source": [
"#export\n",
"class GhApi:\n",
" def __init__(self, owner, repo, token):\n",
" def __init__(self, owner, repo, token=None):\n",
" funcs_ = L(funcs).starmap(GhVerb, client=self)\n",
" self._fs = {k:_GhVerbGroup(v) for k,v in groupby(funcs_, 'tag').items()}\n",
" self._headers = { 'Authorization' : 'token ' + token,\n",
" 'Accept': 'application/vnd.github.v3+json'}\n",
" self._headers = { 'Accept': 'application/vnd.github.v3+json' }\n",
" if token: self._headers['Authorization'] = 'token ' + token\n",
" self.owner,self.repo = owner,repo\n",
" self.repo_url = f\"{GH_HOST}/repos/{owner}/{repo}\"\n",
"\n",
Expand All @@ -151,10 +163,10 @@
" if k in self._fs: return self._fs[k]\n",
" raise AttributeError(k)\n",
"\n",
" def __call__(self, path, **data):\n",
" def __call__(self, path, verb, **data):\n",
" \"Call GitHub API `path`\"\n",
" path = f\"{self.repo_url}{path}\"\n",
" return dict2obj(do_request(path, headers=self._headers, **data))"
" return dict2obj(_send(path, verb.upper(), headers=self._headers, **data))"
]
},
{
Expand All @@ -178,18 +190,18 @@
"- node_id: MDM6UmVmMjI1NDYwNTk5OnJlZnMvaGVhZHMvbWFzdGVy\n",
"- url: https://api.github.com/repos/fastai/fastcore/git/refs/heads/master\n",
"- object: \n",
" - sha: d06d540f07dd51e7ec89b59dd802871e284653e2\n",
" - sha: b9e271018dade8bc8d32dc92b1c25c04f6d1f2f6\n",
" - type: commit\n",
" - url: https://api.github.com/repos/fastai/fastcore/git/commits/d06d540f07dd51e7ec89b59dd802871e284653e2"
" - url: https://api.github.com/repos/fastai/fastcore/git/commits/b9e271018dade8bc8d32dc92b1c25c04f6d1f2f6"
],
"text/plain": [
"- ref: refs/heads/master\n",
"- node_id: MDM6UmVmMjI1NDYwNTk5OnJlZnMvaGVhZHMvbWFzdGVy\n",
"- url: https://api.github.com/repos/fastai/fastcore/git/refs/heads/master\n",
"- object: \n",
" - sha: d06d540f07dd51e7ec89b59dd802871e284653e2\n",
" - sha: b9e271018dade8bc8d32dc92b1c25c04f6d1f2f6\n",
" - type: commit\n",
" - url: https://api.github.com/repos/fastai/fastcore/git/commits/d06d540f07dd51e7ec89b59dd802871e284653e2"
" - url: https://api.github.com/repos/fastai/fastcore/git/commits/b9e271018dade8bc8d32dc92b1c25c04f6d1f2f6"
]
},
"execution_count": null,
Expand All @@ -209,10 +221,46 @@
{
"data": {
"text/markdown": [
"[repos/create_webhook](https://docs.github.com/rest/reference/repos#create-a-repository-webhook)(name,config,events,active): Create a repository webhook"
"- type: Repository\n",
"- id: 264207336\n",
"- name: web\n",
"- active: True\n",
"- events: \n",
" - push\n",
"- config: \n",
" - url: http://example.com/foo\n",
" - insecure_ssl: 0\n",
" - content_type: form\n",
"- updated_at: 2020-11-23T03:10:03Z\n",
"- created_at: 2020-11-23T03:10:03Z\n",
"- url: https://api.github.com/repos/fastai/fastcore/hooks/264207336\n",
"- test_url: https://api.github.com/repos/fastai/fastcore/hooks/264207336/test\n",
"- ping_url: https://api.github.com/repos/fastai/fastcore/hooks/264207336/pings\n",
"- last_response: \n",
" - code: None\n",
" - status: unused\n",
" - message: None"
],
"text/plain": [
"[repos/create_webhook](https://docs.github.com/rest/reference/repos#create-a-repository-webhook)(name,config,events,active): Create a repository webhook"
"- type: Repository\n",
"- id: 264207336\n",
"- name: web\n",
"- active: True\n",
"- events: \n",
" - push\n",
"- config: \n",
" - url: http://example.com/foo\n",
" - insecure_ssl: 0\n",
" - content_type: form\n",
"- updated_at: 2020-11-23T03:10:03Z\n",
"- created_at: 2020-11-23T03:10:03Z\n",
"- url: https://api.github.com/repos/fastai/fastcore/hooks/264207336\n",
"- test_url: https://api.github.com/repos/fastai/fastcore/hooks/264207336/test\n",
"- ping_url: https://api.github.com/repos/fastai/fastcore/hooks/264207336/pings\n",
"- last_response: \n",
" - code: None\n",
" - status: unused\n",
" - message: None"
]
},
"execution_count": null,
Expand All @@ -221,7 +269,7 @@
}
],
"source": [
"api.repos.create_webhook"
"# api.repos.create_webhook(config={'url':'http://example.com/foo'})"
]
},
{
Expand Down
144 changes: 144 additions & 0 deletions 90_build_lib.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#default_exp build_lib"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#export\n",
"from fastcore.utils import *\n",
"from fastcore.foundation import *\n",
"import pprint"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Parse Open API Spec\n",
"\n",
"This library leverages the [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification) to create a python client for the GitHub API. The OpenAPI specification contains metadata on all of the endpoints and how to access them properly. Using this metadata, we can construct a python client dynamically that updates automatically along with the OpenAPI Spec. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#export\n",
"GH_OPENAPI_URL = 'https://github.com/github/rest-api-description/raw/main/descriptions/api.github.com/api.github.com.json?raw=true'\n",
"_DOC_URL = 'https://docs.github.com/'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#export\n",
"def build_funcs(pre, nm='ghapi/metadata.py', url=GH_OPENAPI_URL, docurl=_DOC_URL):\n",
" \"Build module funcs.py from an Open API spec and optionally filter by a path `pre`\"\n",
" def _get_detls(o):\n",
" data = nested_idx(o, *'requestBody content application/json schema properties'.split()) or {}\n",
" url = o['externalDocs']['url'][len(docurl):]\n",
" return (o['operationId'], o['summary'], url, list(data.keys()))\n",
" \n",
" js = urljson(url)\n",
" paths = {o[len(pre):]:v for o,v in js['paths'].items() if o.startswith(pre)}\n",
" _funcs = [(path, verb) + _get_detls(detls)\n",
" for path,verbs in paths.items() for verb,detls in verbs.items()]\n",
" Path(nm).write_text(\"funcs = \" + pprint.pformat(_funcs, width=360))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We build the module `metadata.py` with the github OpenAPI spec for only paths beginning with `/repos/{owner}/{repo}`:\n",
"\n",
"```python\n",
"build_funcs(pre='/repos/{owner}/{repo}', nm='ghapi/metadata.py')\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This python module contains a list of metadata for each endpoint, containing the path, verb, operation id, summary, documentation relative URL, and list of parameters (if any), e.g:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('/actions/artifacts/{artifact_id}',\n",
" 'delete',\n",
" 'actions/delete-artifact',\n",
" 'Delete an artifact',\n",
" 'rest/reference/actions#delete-an-artifact',\n",
" [])"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from ghapi.metadata import funcs\n",
"funcs[5]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Export -"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#hide\n",
"from nbdev.export import notebook2script\n",
"notebook2script('build_lib.ipynb')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Loading

0 comments on commit 6cafe13

Please sign in to comment.