Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update WIPP extension to use new Python API Client #35

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.formatting.provider": "black"
}
25 changes: 15 additions & 10 deletions jupyterlab_wipp/jupyterlab_wipp/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import os
from pathlib import Path

from ._version import __version__
Expand All @@ -8,22 +9,17 @@
with (HERE / "labextension" / "package.json").open() as fid:
data = json.load(fid)

def _jupyter_labextension_paths():
return [{
"src": "labextension",
"dest": data["name"]
}]

def _jupyter_labextension_paths():
return [{"src": "labextension", "dest": data["name"]}]


from .handlers import setup_handlers
from .wipp import Wipp
from wipp_client import Wipp


def _jupyter_server_extension_points():
return [{
"module": "jupyterlab_wipp"
}]
return [{"module": "jupyterlab_wipp"}]


def _load_jupyter_server_extension(server_app):
Expand All @@ -34,10 +30,19 @@ def _load_jupyter_server_extension(server_app):
server_app: jupyterlab.labapp.LabApp
JupyterLab application instance
"""
wipp_ui_url = os.getenv("WIPP_UI_URL") if "WIPP_UI_URL" in os.environ else ""

server_app.web_app.settings["wipp_urls"] = {
"notebooks_ui_url": os.path.join(wipp_ui_url, "notebooks/"),
"imagescollections_ui_url": os.path.join(wipp_ui_url, "images-collections/"),
"imagescollection_ui_url": os.path.join(wipp_ui_url, "images-collection/"),
"csvcollections_ui_url": os.path.join(wipp_ui_url, "csv-collections/"),
}

server_app.web_app.settings["wipp"] = Wipp()
setup_handlers(server_app.web_app)
server_app.log.info("Registered jupyterlab_wipp extension at URL path /wipp")


# For backward compatibility with notebook server - useful for Binder/JupyterHub
load_jupyter_server_extension = _load_jupyter_server_extension

146 changes: 116 additions & 30 deletions jupyterlab_wipp/jupyterlab_wipp/handlers.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,55 @@
import os
import json
import shutil
import binascii
import requests
from jupyter_server.base.handlers import APIHandler
from jupyter_server.utils import url_path_join
import tornado
import json


def gen_random_object_id():
"""
Generate random ObjectID in MongoDB format
"""
timestamp = "{0:x}".format(int(time.time()))
rest = binascii.b2a_hex(os.urandom(8)).decode("ascii")
return timestamp + rest


class WippHandler(APIHandler):
@property
def wipp(self):
return self.settings["wipp"]

@property
def urls(self):
return self.settings["wipp_urls"]


class InfoCheckHandler(WippHandler):
@tornado.web.authenticated
def get(self):
response = self.wipp.check_api_is_live()
self.finish(json.dumps(response))


class WippUiUrls(WippHandler):
@tornado.web.authenticated
def get(self):
"""
GET request handler, returns relevant WIPP UI URLs
"""
self.finish(json.dumps({
'root': self.wipp.wipp_ui_url,
'notebooks': self.wipp.notebooks_ui_url,
'imagescollections': self.wipp.imagescollections_ui_url,
'imagescollection': self.wipp.imagescollection_ui_url,
'csvcollections': self.wipp.csvcollections_ui_url
}))
self.finish(
json.dumps(
{
"notebooks": self.urls["notebooks_ui_url"],
"imagescollections": self.urls["imagescollections_ui_url"],
"imagescollection": self.urls["imagescollection_ui_url"],
"csvcollections": self.urls["csvcollections_ui_url"],
}
)
)


class WippRegisterNotebook(WippHandler):
Expand All @@ -45,34 +67,87 @@ def post(self):
"""

data = json.loads(self.request.body.decode("utf-8"))
if all(key in data for key in ("path","name","description")):
temp_notebooks_path = (
os.getenv("WIPP_NOTEBOOKS_PATH")
if "WIPP_NOTEBOOKS_PATH" in os.environ
else "/opt/shared/wipp/temp/notebooks"
)

if all(key in data for key in ("path", "name", "description")):
try:
response = self.wipp.register_notebook(data["path"], data["name"], data["description"])
self.finish(json.dumps(response))
api_route = (
os.getenv("WIPP_API_INTERNAL_URL")
if "WIPP_API_INTERNAL_URL" in os.environ
else "http://wipp-backend:8080/api"
)
notebooks_api_route = os.path.join(api_route, "notebooks")

# Append default path
notebook_path = os.path.join(os.environ["HOME"], data["path"])

# Generate random ObjectID for notebook
object_id = gen_random_object_id()

# Create destination folder in WIPP
dest_folder = os.path.join(temp_notebooks_path, object_id)
if not os.path.exists(dest_folder):
os.makedirs(dest_folder)

# Copy notebook to destination folder in WIPP
dest_path = os.path.join(dest_folder, "notebook.ipynb")
shutil.copy(notebook_path, dest_path)

# Send API request to WIPP to register notebook
url = os.path.join(notebooks_api_route, "import")
querystring = {
"folderName": object_id,
"name": data["name"],
"description": data["description"],
}
response = requests.request("POST", url, params=querystring)

result = {"code": response.status_code}
if response.status_code == 200:
response_json = response.json()

# Append workflow URL information
response_json["url"] = self.notebooks_ui_url

result["info"] = response_json
elif response.status_code == 400:
result["error"] = response.text

self.finish(json.dumps(result))
except:
self.write_error(500)
else:
self.write_error(400)


class WippImageCollections(WippHandler):
@tornado.web.authenticated
def get(self):
"""
GET request handler, returns an array of WIPP Image Collections
"""

try:
response = self.wipp.get_image_collections()
self.finish(json.dumps(response))
response = [
collection.dict(by_alias=True)
for collection in self.wipp.get_image_collections()
]

self.finish(json.dumps(response, default=str))
except:
self.write_error(500)


class WippImageCollectionsSearch(WippHandler):
@tornado.web.authenticated
def post(self):
"""
POST request handler
Returns an array of WIPP Image Collection which have requested string in the name
Returns an array of WIPP Image Collection which have requested string in the name

Input format:
{
Expand All @@ -83,13 +158,16 @@ def post(self):
data = json.loads(self.request.body.decode("utf-8"))
if "name" in data.keys():
try:
response = self.wipp.search_image_collections(data["name"])
self.finish(json.dumps(response))
response = [
collection.dict(by_alias=True)
for collection in self.wipp.search_image_collections(data["name"])
]
self.finish(json.dumps(response, default=str))
except:
self.write_error(500)
else:
self.write_error(400)


class WippCsvCollections(WippHandler):
@tornado.web.authenticated
Expand All @@ -98,17 +176,22 @@ def get(self):
GET request handler, returns an array of WIPP Csv Collections
"""
try:
response = self.wipp.get_csv_collections()
self.finish(json.dumps(response))
response = [
collection.dict(by_alias=True)
for collection in self.wipp.get_csv_collections()
]

self.finish(json.dumps(response, default=str))
except:
self.write(500)


class WippCsvCollectionsSearch(WippHandler):
@tornado.web.authenticated
def post(self):
"""
POST request handler
Returns an array of WIPP Csv Collection which have requested string in the name
Returns an array of WIPP Csv Collection which have requested string in the name

Input format:
{
Expand All @@ -119,8 +202,11 @@ def post(self):
data = json.loads(self.request.body.decode("utf-8"))
if "name" in data.keys():
try:
response = self.wipp.search_csv_collections(data["name"])
self.finish(json.dumps(response))
response = [
collection.dict(by_alias=True)
for collection in self.wipp.search_csv_collections(data["name"])
]
self.finish(json.dumps(response, default=str))
except:
self.write_error(500)
else:
Expand All @@ -129,13 +215,13 @@ def post(self):

def setup_handlers(web_app):
handlers = [
('/wipp/info', InfoCheckHandler),
('/wipp/ui_urls', WippUiUrls),
('/wipp/register', WippRegisterNotebook),
('/wipp/imageCollections', WippImageCollections),
('/wipp/imageCollections/search', WippImageCollectionsSearch),
('/wipp/csvCollections', WippCsvCollections),
('/wipp/csvCollections/search', WippCsvCollectionsSearch)
("/wipp/info", InfoCheckHandler),
("/wipp/ui_urls", WippUiUrls),
("/wipp/register", WippRegisterNotebook),
("/wipp/imageCollections", WippImageCollections),
("/wipp/imageCollections/search", WippImageCollectionsSearch),
("/wipp/csvCollections", WippCsvCollections),
("/wipp/csvCollections/search", WippCsvCollectionsSearch),
]

base_url = web_app.settings["base_url"]
Expand Down
Loading