Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions envs_manager/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# SPDX-FileCopyrightText: 2022-present Spyder Development Team and envs-manager contributors
#
# SPDX-License-Identifier: MIT
from envs_manager.jupyter import EnvManagerApp

def _jupyter_server_extension_points():
"""
Returns a list of dictionaries with metadata describing
where to find the `_load_jupyter_server_extension` function.
"""
return [{"module": "envs_manager.jupyter", "app": EnvManagerApp}]
79 changes: 79 additions & 0 deletions envs_manager/jupyter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from __future__ import annotations
import json
import typing as t

from traitlets import Unicode
from tornado import web
from jupyter_server.auth.decorator import authorized
from jupyter_server.extension.application import ExtensionApp
from jupyter_server.base.handlers import JupyterHandler

from envs_manager.manager import (
DEFAULT_BACKENDS_ROOT_PATH,
DEFAULT_BACKEND,
Manager,
ManagerActions
)


class EnvManagerHandler(JupyterHandler):
"""Handler to list available environments."""

_handler_action_regex = rf"(?P<action>{'|'.join(action.value for action in ManagerActions)})"

auth_resource = "envs_manager"

def get_manager(self) -> Manager:
"""Get the environment manager instance."""
return Manager(
backend=self.get_argument("backend", None) or self.settings["envs_manager_config"]["default_backend"],
root_path=self.settings["envs_manager_config"]["root_path"],
env_name=self.get_argument("env_name", None),
env_directory=self.get_argument("env_directory", None),
)

def get_options(self) -> dict[str, t.Any]:
return self.get_json_body() or {}

def write_json(self, data, status=200):
self.set_status(status)
self.set_header("Content-Type", "application/json")
self.finish(json.dumps(data))

@authorized
@web.authenticated
def post(self, action: str):
try:
manager = self.get_manager()
action_options = self.get_options()
self.write_json(
manager.run_action(ManagerActions(action), action_options),
status=200,
)
except Exception as e:
self.set_status(501)
self.finish(str(e))
self.log_exception(type(e), e, e.__traceback__)

class EnvManagerApp(ExtensionApp):
"""Jupyter extension for managing environments."""

name = "envs_manager"
extension_url = "/envs_manager"
open_browser = False

root_path = Unicode(
str(DEFAULT_BACKENDS_ROOT_PATH),
config=True,
help="Root path for the extension. Defaults to the Jupyter server root path.",
)

default_backend = Unicode(
DEFAULT_BACKEND,
config=True,
help="Default backend to use for managing environments.",
)

handlers = [
(rf"{extension_url}/{EnvManagerHandler._handler_action_regex}", EnvManagerHandler),
] # type: ignore[list-item]
5 changes: 3 additions & 2 deletions envs_manager/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import os
from pathlib import Path
from typing import TypedDict
from enum import Enum

from envs_manager.backends.api import BackendActionResult, BackendInstance
from envs_manager.backends.venv_interface import VEnvInterface
Expand All @@ -22,7 +23,7 @@
DEFAULT_ENVS_ROOT_PATH = DEFAULT_BACKENDS_ROOT_PATH / DEFAULT_BACKEND / "envs"


class ManagerActions:
class ManagerActions(Enum):
"""Enum with the possible actions that can be performed by the manager."""

CreateEnvironment = "create_environment"
Expand Down Expand Up @@ -118,7 +119,7 @@ def __init__(
)

def run_action(self, action: ManagerActions, action_options: dict | None = None):
method = getattr(self, action)
method = getattr(self, action.value)
if action_options is not None:
return method(**action_options)
else:
Expand Down
7 changes: 7 additions & 0 deletions jupyter-config/envs_manager.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"ServerApp": {
"jpserver_extensions": {
"envs_manager": true
}
}
}
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies = [
"py-rattler",
"pyyaml",
"requests",
"jupyter-server"
]
dynamic = ["version"]

Expand All @@ -52,9 +53,13 @@ pre-commit = [
[tool.hatch.version]
path = "envs_manager/__about__.py"


[tool.hatch.build.targets.sdist]
[tool.hatch.build.targets.wheel]

[tool.hatch.build.targets.wheel.shared-data]
"jupyter-config" = "etc/jupyter/jupyter_server_config.d"

[tool.hatch.envs.default]
dependencies = [
"pytest",
Expand Down
Loading