File size: 5,063 Bytes
d1ceb73 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
"""Tornado handlers for extension management."""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import dataclasses
import json
from urllib.parse import urlencode, urlunparse
from jupyter_server.base.handlers import APIHandler
from tornado import web
from jupyterlab.extensions.manager import ExtensionManager
class ExtensionHandler(APIHandler):
def initialize(self, manager: ExtensionManager):
super().initialize()
self.manager = manager
@web.authenticated
async def get(self):
"""GET query returns info on extensions
Query arguments:
refresh: [optional] Force refreshing the list of extensions - ["0", "1"]; default 0
query: [optional] Query to search for extensions - default None (i.e. returns installed extensions)
page: [optional] Result page - default 1 (min. 1)
per_page: [optional] Number of results per page - default 30 (max. 100)
"""
query = self.get_argument("query", None)
page = max(1, int(self.get_argument("page", "1")))
per_page = min(100, int(self.get_argument("per_page", "30")))
if self.get_argument("refresh", "0") == "1":
await self.manager.refresh(query, page, per_page)
extensions, last_page = await self.manager.list_extensions(query, page, per_page)
self.set_status(200)
if last_page is not None:
links = []
query_args = {"page": last_page, "per_page": per_page}
if query is not None:
query_args["query"] = query
last = urlunparse(
(
self.request.protocol,
self.request.host,
self.request.path,
"",
urlencode(query_args, doseq=True),
"",
)
)
links.append(f'<{last}>; rel="last"')
if page > 1:
query_args["page"] = max(1, page - 1)
prev = urlunparse(
(
self.request.protocol,
self.request.host,
self.request.path,
"",
urlencode(query_args, doseq=True),
"",
)
)
links.append(f'<{prev}>; rel="prev"')
if page < last_page:
query_args["page"] = min(page + 1, last_page)
next_ = urlunparse(
(
self.request.protocol,
self.request.host,
self.request.path,
"",
urlencode(query_args, doseq=True),
"",
)
)
links.append(f'<{next_}>; rel="next"')
query_args["page"] = 1
first = urlunparse(
(
self.request.protocol,
self.request.host,
self.request.path,
"",
urlencode(query_args, doseq=True),
"",
)
)
links.append(f'<{first}>; rel="first"')
self.set_header("Link", ", ".join(links))
self.finish(json.dumps(list(map(dataclasses.asdict, extensions))))
@web.authenticated
async def post(self):
"""POST query performs an action on a specific extension
Body arguments:
{
"cmd": Action to perform - ["install", "uninstall", "enable", "disable"]
"extension_name": Extension name
"extension_version": [optional] Extension version (used only for install action)
}
"""
data = self.get_json_body()
cmd = data["cmd"]
name = data["extension_name"]
version = data.get("extension_version")
if cmd not in ("install", "uninstall", "enable", "disable") or not name:
raise web.HTTPError(
422,
f"Could not process instruction {cmd!r} with extension name {name!r}",
)
ret_value = None
try:
if cmd == "install":
ret_value = await self.manager.install(name, version)
elif cmd == "uninstall":
ret_value = await self.manager.uninstall(name)
elif cmd == "enable":
ret_value = await self.manager.enable(name)
elif cmd == "disable":
ret_value = await self.manager.disable(name)
except Exception as e:
raise web.HTTPError(500, str(e)) from e
if ret_value.status == "error":
self.set_status(500)
else:
self.set_status(201)
self.finish(json.dumps(dataclasses.asdict(ret_value)))
# The path for lab extensions handler.
extensions_handler_path = r"/lab/api/extensions"
|