You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			141 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			141 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
"""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"
 |