You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by di...@apache.org on 2019/10/29 17:27:37 UTC
[airavata-sandbox] branch master updated: Jupyter lab integrations
This is an automated email from the ASF dual-hosted git repository.
dimuthuupe pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-sandbox.git
The following commit(s) were added to refs/heads/master by this push:
new 29d4fa0 Jupyter lab integrations
29d4fa0 is described below
commit 29d4fa039daaacab6f44822c1ba25f2ccb3451fa
Author: Dimuthu Wannipurage <di...@gmail.com>
AuthorDate: Tue Oct 29 13:27:21 2019 -0400
Jupyter lab integrations
---
.../jhub_airavata_authenticator/__init__.py | 0
.../jhub_airavata_authenticator/airavata_auth.py | 9 +
.../jhub_airavata_authenticator/setup.py | 51 ++++
.../jhub_airavata_authenticator/version.py | 10 +
.../jupyter_airavata_data_store/__init__.py | 0
.../airavata_file_operations.py | 120 ++++++++++
.../jupyter_airavata_data_store/checkpoint.py | 44 ++++
.../jupyter_airavata_data_store/content_manager.py | 262 +++++++++++++++++++++
.../jupyter_airavata_data_store/ipycompact.py | 92 ++++++++
.../jupyter_airavata_data_store/setup.py | 51 ++++
.../jupyter_airavata_data_store/version.py | 10 +
11 files changed, 649 insertions(+)
diff --git a/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/jhub_airavata_authenticator/__init__.py b/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/jhub_airavata_authenticator/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/jhub_airavata_authenticator/airavata_auth.py b/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/jhub_airavata_authenticator/airavata_auth.py
new file mode 100644
index 0000000..dde3d1a
--- /dev/null
+++ b/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/jhub_airavata_authenticator/airavata_auth.py
@@ -0,0 +1,9 @@
+from tornado import gen
+from jupyterhub.auth import Authenticator
+
+class Airav:ataAuthenticator(Authenticator):
+
+ @gen.coroutine
+ def authenticate(self, handler, data):
+ if data['username'] == 'admin':
+ return data['username']
\ No newline at end of file
diff --git a/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/setup.py b/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/setup.py
new file mode 100644
index 0000000..8aa0e43
--- /dev/null
+++ b/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/setup.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+from __future__ import print_function
+
+import os
+import sys
+
+from setuptools import setup
+
+pjoin = os.path.join
+here = os.path.abspath(os.path.dirname(__file__))
+
+# Get the current package version.
+version_ns = {}
+with open(pjoin(here, 'version.py')) as f:
+ exec(f.read(), {}, version_ns)
+
+setup_args = dict(
+ name = 'jhub_airavata_authenticator',
+ packages = ['jhub_airavata_authenticator'],
+ version = version_ns['__version__'],
+ description = """Airavata Authenticator: An Authenticator for Jupyterhub that authenticates against Airavata user store.""",
+ long_description = "",
+ author = "Dimuthu Wannipurage (https://github.com/DImuthuUpe)",
+ author_email = "dimuthu.upeksha2@gmail.com",
+ url = "https://github.com/DImuthuUpe/jhub_airavata_authenticator",
+ license = "Apache 2.0",
+ platforms = "Linux, Mac OS X",
+ keywords = ['Authenticator', 'Airavata'],
+ classifiers = [
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: System Administrators',
+ 'Intended Audience :: Science/Research',
+ 'License :: Apache 2.0',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 3',
+ ],
+)
+
+# setuptools requirements
+if 'setuptools' in sys.modules:
+ setup_args['install_requires'] = install_requires = []
+ install_requires.append('jupyterhub')
+ install_requires.append('lxml')
+
+def main():
+ setup(**setup_args)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/version.py b/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/version.py
new file mode 100644
index 0000000..65c9a51
--- /dev/null
+++ b/jupyter-lab-integrations/auth-plugin/jhub_airavata_authenticator/version.py
@@ -0,0 +1,10 @@
+version_info = (
+ 0,
+ 0,
+ 1,
+ #'dev', # comment-out this line for a release
+)
+__version__ = '.'.join(map(str, version_info[:3]))
+
+if len(version_info) > 3:
+ __version__ = '%s-%s' % (__version__, version_info[3])
\ No newline at end of file
diff --git a/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/__init__.py b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/airavata_file_operations.py b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/airavata_file_operations.py
new file mode 100644
index 0000000..e06d4a1
--- /dev/null
+++ b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/airavata_file_operations.py
@@ -0,0 +1,120 @@
+import os
+from pathlib import Path
+from airavata.api import Airavata
+from thrift import Thrift
+from thrift.transport import TSocket, TSSLSocket
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol
+from airavata.model.security.ttypes import AuthzToken
+
+
+class AiravataFileOperations:
+
+ basePath = "/tmp/a"
+ gateway = "default"
+ storageResourceId = "192.168.99.105_3bf6b8d9-67a6-4faf-b201-68550eeeb978"
+ user = "default-admin"
+
+ def __init__(self):
+ try:
+ self.socket = TSSLSocket.TSSLSocket('192.168.99.105', 9930, validate=False)
+
+ except Thrift.TException as tx:
+ print('%s' % (tx.message))
+
+ def is_file(self, path):
+ absPath = self.appendPaths(self.basePath, path)
+ transport = TTransport.TBufferedTransport(self.socket)
+ transport.open()
+ protocol = TBinaryProtocol.TBinaryProtocol(transport)
+ client = Airavata.Client(protocol)
+
+ fileStructure = client.getFileDetailsFromStorage(AuthzToken(""), self.gateway, self.storageResourceId, self.user, absPath)
+
+ transport.close()
+ return fileStructure.isFile and fileStructure.isExist
+
+ def file_exists(self, path):
+ absPath = self.appendPaths(self.basePath, path)
+ print("airavata_file_operations.file_exists " + absPath)
+
+ transport = TTransport.TBufferedTransport(self.socket)
+ transport.open()
+ protocol = TBinaryProtocol.TBinaryProtocol(transport)
+ client = Airavata.Client(protocol)
+
+ fileStructure = client.getFileDetailsFromStorage(AuthzToken(""), self.gateway, self.storageResourceId, self.user, absPath)
+
+ transport.close()
+
+ return fileStructure.isFile and fileStructure.isExist
+
+ def dir_exists(self, path):
+ absPath = self.appendPaths(self.basePath, path)
+ print("airavata_file_operations.dir_exists " + absPath)
+
+ transport = TTransport.TBufferedTransport(self.socket)
+ transport.open()
+ protocol = TBinaryProtocol.TBinaryProtocol(transport)
+ client = Airavata.Client(protocol)
+
+ fileStructure = client.getFileDetailsFromStorage(AuthzToken(""), self.gateway, self.storageResourceId, self.user, absPath)
+
+ transport.close()
+ return (not fileStructure.isFile) and (fileStructure.isExist)
+
+ def ls_dir(self, path):
+ # returns a list of paths of the all the files inside the directory
+ absPath = self.appendPaths(self.basePath, path)
+
+ transport = TTransport.TBufferedTransport(self.socket)
+ transport.open()
+ protocol = TBinaryProtocol.TBinaryProtocol(transport)
+ client = Airavata.Client(protocol)
+
+ fileStructures = client.listDirectoryFromStorage(AuthzToken(""), self.gateway, self.storageResourceId, self.user, absPath)
+ fileList = []
+ for fileStructure in fileStructures:
+ fileList.append(fileStructure.path.replace(self.basePath, "", 1))
+
+ transport.close()
+ return fileList
+
+ def read_file(self, path):
+ absPath = self.appendPaths(self.basePath, path)
+ print("airavata_file_operations.read_file " + absPath)
+ transport = TTransport.TBufferedTransport(self.socket)
+ transport.open()
+ protocol = TBinaryProtocol.TBinaryProtocol(transport)
+ client = Airavata.Client(protocol)
+
+ fileStructure = client.downloadFileFromStorage(AuthzToken(""), self.gateway, self.storageResourceId, self.user, absPath)
+ print(fileStructure)
+ transport.close()
+ return fileStructure.content.decode("utf-8")
+
+ def write_file(self, path, content):
+ absPath = self.appendPaths(self.basePath, path)
+ print("airavata_file_operations.write_file " + absPath)
+
+ transport = TTransport.TBufferedTransport(self.socket)
+ transport.open()
+ protocol = TBinaryProtocol.TBinaryProtocol(transport)
+ client = Airavata.Client(protocol)
+
+ client.uploadFileToStorage(AuthzToken(""), self.gateway, self.storageResourceId, self.user, bytearray(content, "utf-8"), absPath, "text")
+ transport.close()
+
+ def create_dir(self, path):
+ Path(self.basePath + path).mkdir()
+
+ def rename_file(self, oldPath, newPath):
+ os.renames(self.basePath + oldPath, self.basePath + newPath)
+
+ def delete_file(self, path):
+ os.remove(self.basePath + path)
+
+ def appendPaths(self, first, second):
+ if second.startswith("/"):
+ second = second[1:]
+ return first + "/" + second
diff --git a/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/checkpoint.py b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/checkpoint.py
new file mode 100644
index 0000000..95da23f
--- /dev/null
+++ b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/checkpoint.py
@@ -0,0 +1,44 @@
+from jupyter_airavata_data_store.ipycompact import Checkpoints, GenericCheckpointsMixin
+
+class AiravataCheckpoints(GenericCheckpointsMixin, Checkpoints):
+
+ def create_notebook_checkpoint(self, nb, path):
+ """Create a checkpoint of the current state of a notebook
+ Returns a checkpoint_id for the new checkpoint.
+ """
+ self.log.info("Airavata.checkpounts.create_notebook_checkpoint: ('%s')", path)
+
+ def create_file_checkpoint(self, content, format, path):
+ """Create a checkpoint of the current state of a file
+ Returns a checkpoint_id for the new checkpoint.
+ """
+ self.log.info("Airavata.checkpounts.create_file_checkpoint: ('%s')", path)
+
+ def delete_checkpoint(self, checkpoint_id, path):
+ """delete a checkpoint for a file"""
+ self.log.info("Airavata.checkpounts.delete_checkpoint: ('%s') ('%s')", checkpoint_id, path)
+
+ def get_checkpoint_content(self, checkpoint_id, path):
+ """Get the content of a checkpoint."""
+ self.log.info("Airavata.checkpounts.get_checkpoint_content: ('%s') ('%s')", checkpoint_id, path)
+
+ def get_notebook_checkpoint(self, checkpoint_id, path):
+ self.log.info("Airavata.checkpounts.get_notebook_checkpoint: ('%s') ('%s')", checkpoint_id, path)
+
+ def get_file_checkpoint(self, checkpoint_id, path):
+ self.log.info("Airavata.checkpounts.get_file_checkpoint: ('%s') ('%s')", checkpoint_id, path)
+
+ def list_checkpoints(self, path):
+ """Return a list of checkpoints for a given file"""
+ self.log.info("Airavata.checkpounts.list_checkpoints: ('%s')", path)
+
+ def rename_all_checkpoints(self, old_path, new_path):
+ """Rename all checkpoints for old_path to new_path."""
+ self.log.info("Airavata.checkpounts.rename_all_checkpoints: ('%s') ('%s')", old_path, new_path)
+
+ def delete_all_checkpoints(self, path):
+ """Delete all checkpoints for the given path."""
+ self.log.info("Airavata.checkpounts.delete_all_checkpoints: ('%s')", path)
+
+
+
diff --git a/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/content_manager.py b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/content_manager.py
new file mode 100644
index 0000000..d26bdb3
--- /dev/null
+++ b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/content_manager.py
@@ -0,0 +1,262 @@
+import datetime
+import mimetypes
+import json
+
+import os
+from notebook.services.contents.largefilemanager import LargeFileManager
+from jupyter_airavata_data_store.ipycompact import ContentsManager
+from jupyter_airavata_data_store.ipycompact import GenericFileCheckpoints, reads, from_dict
+from tornado.web import HTTPError
+from jupyter_airavata_data_store.airavata_file_operations import AiravataFileOperations
+from jupyter_airavata_data_store.checkpoint import AiravataCheckpoints
+
+DUMMY_CREATED_DATE = datetime.datetime.fromtimestamp(86400)
+NBFORMAT_VERSION = 4
+
+class AiaravataContentManager(ContentsManager):
+
+ fileOperations = AiravataFileOperations()
+
+ def file_exists(self, path =''):
+ # Does a file exist at the given path?
+ self.log.info("AiaravataContentManager.file_exists: ('%s')", path)
+ return self.fileOperations.file_exists(path)
+
+ def dir_exists(self, path):
+ # Does a directory exist at the given path?
+ self.log.info("AiaravataContentManager.dir_exists: path('%s')", path)
+ result = self.fileOperations.dir_exists(path)
+ print(result)
+ return result
+
+ def get(self, path, content=True, type=None, format=None):
+ # Get a file or directory model.
+ self.log.info("AiaravataContentManager.get path('%s') type(%s) format(%s)", path, type, format)
+ path = path.strip('/')
+
+ if type is None:
+ type = self.guess_type(path)
+ try:
+ func = {
+ "directory": self._get_directory,
+ "notebook": self._get_notebook,
+ "file": self._get_file,
+ }[type]
+ except KeyError:
+ raise ValueError("Unknown type passed: '{}'".format(type))
+
+ return func(path=path, content=content, format=format)
+
+ def save(self, model, path):
+ """Save a file or directory model to path.
+ """
+ self.log.info("AiaravataContentManager: save %s: '%s'", model, path)
+ if "type" not in model:
+ self.do_error("No model type provided", 400)
+ if "content" not in model and model["type"] != "directory":
+ self.do_error("No file content provided", 400)
+
+ if model["type"] not in ("file", "directory", "notebook"):
+ self.do_error("Unhandled contents type: %s" % model["type"], 400)
+
+ try:
+ if model["type"] == "notebook":
+ validation_message = self._save_notebook(model, path)
+ elif model["type"] == "file":
+ validation_message = self._save_file(model, path)
+ else:
+ validation_message = self._save_directory(path)
+ except Exception as e:
+ self.log.error("Error while saving file: %s %s", path, e, exc_info=True)
+ self.do_error("Unexpected error while saving file: %s %s" % (path, e), 500)
+
+ model = self.get(path, type=model["type"], content=False)
+ if validation_message is not None:
+ model["message"] = validation_message
+ return model
+
+ def rename_file(self, old_path, new_path):
+ """Rename a file or directory.
+ NOTE: This method is unfortunately named on the base class. It
+ actually moves a file or a directory.
+ """
+ self.log.info("AiaravataContentManager: Init rename of '%s' to '%s'", old_path, new_path)
+ if self.file_exists(new_path) or self.dir_exists(new_path):
+ self.already_exists(new_path)
+ elif self.file_exists(old_path) or self.dir_exists(old_path):
+ self.log.info("AiaravataContentManager: Actually renaming '%s' to '%s'", old_path,
+ new_path)
+ self.fileOperations.rename_file(old_path, new_path)
+ else:
+ self.no_such_entity(old_path)
+
+ def delete_file(self, path):
+ """Delete the file or directory at path.
+ """
+ self.log.info("AiaravataContentManager: delete_file '%s'", path)
+ if self.file_exists(path) or self.dir_exists(path):
+ self.fileOperations.delete_file(path)
+ else:
+ self.no_such_entity(path)
+
+ def is_hidden(self, path):
+ """Is path a hidden directory or file?
+ """
+ self.log.info("AiaravataContentManager: is_hidden '%s'", path)
+ return False
+
+ def _checkpoints_class_default(self):
+ return AiravataCheckpoints
+
+ def do_error(self, msg, code=500):
+ raise HTTPError(code, msg)
+
+ def no_such_entity(self, path):
+ self.do_error("No such entity: [{path}]".format(path=path), 404)
+
+ def already_exists(self, path):
+ thing = "File" if self.file_exists(path) else "Directory"
+ self.do_error(u"{thing} already exists: [{path}]".format(thing=thing, path=path), 409)
+
+ def guess_type(self, path, allow_directory=True):
+ """
+ Guess the type of a file.
+ If allow_directory is False, don't consider the possibility that the
+ file is a directory.
+ Parameters
+ ----------
+ obj: s3.Object or string
+ """
+ if path.endswith(".ipynb"):
+ return "notebook"
+ elif allow_directory and self.dir_exists(path):
+ return "directory"
+ else:
+ return "file"
+
+ def _get_directory(self, path, content=True, format=None):
+ self.log.info("AiaravataContentManager.get_directory: path('%s') content(%s) format(%s)", path, content, format)
+ return self._directory_model_from_path(path, content=content)
+
+ def _get_notebook(self, path, content=True, format=None):
+ self.log.info("AiaravataContentManager.get_notebook: path('%s') type(%s) format(%s)", path, content, format)
+ return self._notebook_model_from_path(path, content=content, format=format)
+
+ def _get_file(self, path, content=True, format=None):
+ self.log.info("AiaravataContentManager.get_file: path('%s') type(%s) format(%s)", path, content, format)
+ return self._file_model_from_path(path, content=content, format=format)
+
+ def _directory_model_from_path(self, path, content=False):
+ self.log.info("AiaravataContentManager._directory_model_from_path: path('%s') type(%s)", path, content)
+ model = base_directory_model(path)
+ if content:
+ if not self.dir_exists(path):
+ self.no_such_entity(path)
+ model["format"] = "json"
+ dir_content = self.fileOperations.ls_dir(path)
+ model["content"] = self._convert_file_records(dir_content)
+ return model
+
+ def _notebook_model_from_path(self, path, content=False, format=None):
+ """
+ Build a notebook model from database record.
+ """
+ model = base_model(path)
+ model["type"] = "notebook"
+ if self.fileOperations.is_file(path):
+ model["last_modified"] = model["created"] = DUMMY_CREATED_DATE
+ else:
+ model["last_modified"] = model["created"] = DUMMY_CREATED_DATE
+ if content:
+ if not self.fileOperations.file_exists(path):
+ self.no_such_entity(path)
+ print("step 2")
+ file_content = self.fileOperations.read_file(path)
+ nb_content = reads(file_content, as_version=NBFORMAT_VERSION)
+ self.mark_trusted_cells(nb_content, path)
+ model["format"] = "json"
+ model["content"] = nb_content
+ self.validate_notebook_model(model)
+ return model
+
+ def _file_model_from_path(self, path, content=False, format=None):
+ """
+ Build a file model from database record.
+ """
+ model = base_model(path)
+ model["type"] = "file"
+ if self.fileOperations.file_exists(path):
+ model["last_modified"] = model["created"] = DUMMY_CREATED_DATE
+ else:
+ model["last_modified"] = model["created"] = DUMMY_CREATED_DATE
+ if content:
+ print("step 1")
+ content = self.fileOperations.read_file(path)
+
+ model["format"] = format or "text"
+ model["content"] = content
+ model["mimetype"] = mimetypes.guess_type(path)[0] or "text/plain"
+ if format == "base64":
+ model["format"] = format or "base64"
+ from base64 import b64decode
+ model["content"] = b64decode(content)
+ print("step 3")
+
+ return model
+
+ def _convert_file_records(self, paths):
+ """
+ Applies _notebook_model_from_s3_path or _file_model_from_s3_path to each entry of `paths`,
+ depending on the result of `guess_type`.
+ """
+ ret = []
+ for path in paths:
+ type_ = self.guess_type(path, allow_directory=True)
+ if type_ == "notebook":
+ ret.append(self._notebook_model_from_path(path, False))
+ elif type_ == "file":
+ ret.append(self._file_model_from_path(path, False, None))
+ elif type_ == "directory":
+ ret.append(self._directory_model_from_path(path, False))
+ else:
+ self.do_error("Unknown file type %s for file '%s'" % (type_, path), 500)
+ return ret
+
+ def _save_notebook(self, model, path):
+ nb_contents = from_dict(model['content'])
+ self.check_and_sign(nb_contents, path)
+ file_contents = json.dumps(model["content"])
+ self.fileOperations.write_file(path, file_contents)
+ self.validate_notebook_model(model)
+ return model.get("message")
+
+ def _save_file(self, model, path):
+ file_contents = model["content"]
+ file_format = model.get('format')
+ self.fileOperations.write_file(path, file_contents)
+
+ def _save_directory(self, path):
+ self.fileOperations.create_dir(path)
+
+
+def base_model(path):
+ return {
+ "name": path.rsplit('/', 1)[-1],
+ "path": path,
+ "writable": True,
+ "last_modified": None,
+ "created": None,
+ "content": None,
+ "format": None,
+ "mimetype": None,
+ }
+
+
+def base_directory_model(path):
+ model = base_model(path)
+ model.update(
+ type="directory",
+ last_modified=DUMMY_CREATED_DATE,
+ created=DUMMY_CREATED_DATE,)
+ return model
+
diff --git a/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/ipycompact.py b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/ipycompact.py
new file mode 100644
index 0000000..a146c5c
--- /dev/null
+++ b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/jupyter_airavata_data_store/ipycompact.py
@@ -0,0 +1,92 @@
+"""
+Utilities for managing IPython 3/4 compat.
+Taken from: https://github.com/quantopian/pgcontents/blob/master/pgcontents/utils/ipycompat.py
+"""
+import IPython
+
+SUPPORTED_VERSIONS = {3, 4, 5, 6}
+IPY_MAJOR = IPython.version_info[0]
+if IPY_MAJOR not in SUPPORTED_VERSIONS:
+ raise ImportError("IPython version %d is not supported." % IPY_MAJOR)
+
+IPY3 = (IPY_MAJOR == 3)
+
+if IPY3:
+ from IPython.config import Config
+ from IPython.html.services.contents.manager import ContentsManager
+ from IPython.html.services.contents.checkpoints import (
+ Checkpoints,
+ GenericCheckpointsMixin,)
+ from IPython.html.services.contents.filemanager import FileContentsManager
+ from IPython.html.services.contents.filecheckpoints import (GenericFileCheckpoints)
+ from IPython.html.services.contents.tests.test_manager import (TestContentsManager)
+ from IPython.html.services.contents.tests.test_contents_api import (APITest)
+ from IPython.html.utils import to_os_path
+ from IPython.nbformat import from_dict, reads, writes
+ from IPython.nbformat.v4.nbbase import (
+ new_code_cell,
+ new_markdown_cell,
+ new_notebook,
+ new_raw_cell,)
+ from IPython.nbformat.v4.rwbase import strip_transient
+ from IPython.utils.traitlets import (
+ Any,
+ Bool,
+ Dict,
+ Instance,
+ Integer,
+ HasTraits,
+ Unicode,)
+else:
+ from traitlets.config import Config
+ from notebook.services.contents.checkpoints import (
+ Checkpoints,
+ GenericCheckpointsMixin,)
+ from notebook.services.contents.filemanager import FileContentsManager
+ from notebook.services.contents.filecheckpoints import (GenericFileCheckpoints)
+ from notebook.services.contents.manager import ContentsManager
+ from notebook.services.contents.tests.test_manager import (TestContentsManager)
+ from notebook.services.contents.tests.test_contents_api import (APITest)
+ from notebook.utils import to_os_path
+ from nbformat import from_dict, reads, writes
+ from nbformat.v4.nbbase import (
+ new_code_cell,
+ new_markdown_cell,
+ new_notebook,
+ new_raw_cell,)
+ from nbformat.v4.rwbase import strip_transient
+ from traitlets import (
+ Any,
+ Bool,
+ Dict,
+ Instance,
+ Integer,
+ HasTraits,
+ Unicode,)
+
+__all__ = [
+ 'APITest',
+ 'Any',
+ 'Bool',
+ 'Checkpoints',
+ 'Config',
+ 'ContentsManager',
+ 'Dict',
+ 'FileContentsManager',
+ 'GenericCheckpointsMixin',
+ 'GenericFileCheckpoints',
+ 'HasTraits',
+ 'Instance',
+ 'Integer',
+ 'TestContentsManager',
+ 'Unicode',
+ 'from_dict',
+ 'new_code_cell',
+ 'new_markdown_cell',
+ 'new_notebook',
+ 'new_raw_cell',
+ 'reads',
+ 'strip_transient',
+ 'to_os_path',
+ 'writes',
+]
\ No newline at end of file
diff --git a/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/setup.py b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/setup.py
new file mode 100644
index 0000000..268e24b
--- /dev/null
+++ b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/setup.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+from __future__ import print_function
+
+import os
+import sys
+
+from setuptools import find_packages, setup
+
+pjoin = os.path.join
+here = os.path.abspath(os.path.dirname(__file__))
+
+# Get the current package version.
+version_ns = {}
+with open(pjoin(here, 'version.py')) as f:
+ exec(f.read(), {}, version_ns)
+
+setup_args = dict(
+ name = 'jupyter_airavata_data_store',
+ packages = find_packages(include=['jupyter_airavata_data_store', 'jupyter_airavata_data_store.*']),
+ version = version_ns['__version__'],
+ description = """Jupyter Airavata Data Store: This overrides default Jupyter filesystem based storage with Airavata storage utilizing Airavata data catalog APIs.""",
+ long_description = "",
+ author = "Dimuthu Wannipurage (https://github.com/DImuthuUpe)",
+ author_email = "dimuthu.upeksha2@gmail.com",
+ url = "https://github.com/DImuthuUpe/jupyter_airavata_data_store",
+ license = "Apache 2.0",
+ platforms = "Linux, Mac OS X",
+ keywords = ['Data Store', 'Airavata', 'Jupyter'],
+ classifiers = [
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: System Administrators',
+ 'Intended Audience :: Science/Research',
+ 'License :: Apache 2.0',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 3',
+ ],
+)
+
+# setuptools requirements
+if 'setuptools' in sys.modules:
+ setup_args['install_requires'] = install_requires = []
+ install_requires.append('jupyterhub')
+ install_requires.append('lxml')
+
+def main():
+ setup(**setup_args)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/version.py b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/version.py
new file mode 100644
index 0000000..65c9a51
--- /dev/null
+++ b/jupyter-lab-integrations/datastore-plugin/jupyter_airavata_data_store/version.py
@@ -0,0 +1,10 @@
+version_info = (
+ 0,
+ 0,
+ 1,
+ #'dev', # comment-out this line for a release
+)
+__version__ = '.'.join(map(str, version_info[:3]))
+
+if len(version_info) > 3:
+ __version__ = '%s-%s' % (__version__, version_info[3])
\ No newline at end of file