diff --git a/openeo/internal/jupyter.py b/openeo/internal/jupyter.py new file mode 100644 index 000000000..7a8d28a26 --- /dev/null +++ b/openeo/internal/jupyter.py @@ -0,0 +1,61 @@ +import json + +SCRIPT_URL = 'https://cdn.jsdelivr.net/npm/@openeo/vue-components@2.0.0-rc.2/assets/openeo.min.js' +COMPONENT_MAP = { + 'file-format': 'format', + 'file-formats': 'formats', + 'service-type': 'service', + 'service-types': 'services', + 'udf-runtime': 'runtime', + 'udf-runtimes': 'runtimes', +} + +def render_component(component: str, data = None, parameters: dict = {}): + # Set the data as the corresponding parameter in the Vue components + key = COMPONENT_MAP.get(component, component) + if data != None: + parameters[key] = data + + # Construct HTML, load Vue Components source files only if the openEO HTML tag is not yet defined + return """ + + + + + """.format( + script = SCRIPT_URL, + component = component, + props = json.dumps(parameters) + ) + +# These classes are proxies to visualize openEO responses nicely in Jupyter +# To show the actual list or dict in Jupyter, use repr() or print() + +class VisualDict(dict): + + def __init__(self, component: str, data : dict, parameters: dict = {}): + dict.__init__(self, data) + + self.component = component + self.parameters = parameters + + def _repr_html_(self): + return render_component(self.component, self, self.parameters) + + +class VisualList(list): + + def __init__(self, component: str, data : list, parameters: dict = {}): + list.__init__(self, data) + + self.component = component + self.parameters = parameters + + def _repr_html_(self): + return render_component(self.component, self, self.parameters) \ No newline at end of file diff --git a/openeo/metadata.py b/openeo/metadata.py index 8ced84a60..a3a319be6 100644 --- a/openeo/metadata.py +++ b/openeo/metadata.py @@ -3,6 +3,7 @@ from typing import List, Union, Tuple, Callable from openeo.util import deep_get +from openeo.internal.jupyter import render_component class MetadataException(Exception): @@ -392,3 +393,6 @@ def add_dimension(self, name: str, label: Union[str, float], type: str = None) - else: dim = Dimension(type=type or "other", name=name) return self._clone_and_update(dimensions=self._dimensions + [dim]) + + def _repr_html_(self): + return render_component('collection', data = self._orig_metadata) diff --git a/openeo/rest/connection.py b/openeo/rest/connection.py index dc565ba7c..859b195bd 100644 --- a/openeo/rest/connection.py +++ b/openeo/rest/connection.py @@ -31,6 +31,7 @@ from openeo.rest.rest_capabilities import RESTCapabilities from openeo.rest.udp import RESTUserDefinedProcess, Parameter from openeo.util import ensure_list, legacy_alias, dict_no_none +from openeo.internal.jupyter import VisualDict, VisualList _log = logging.getLogger(__name__) @@ -522,7 +523,8 @@ def list_collections(self) -> List[dict]: :return: list of collection meta data dictionaries """ - return self.get('/collections').json()["collections"] + data = self.get('/collections').json()["collections"] + return VisualList("collections", data = data) def list_collection_ids(self) -> List[str]: """ @@ -539,7 +541,7 @@ def capabilities(self) -> RESTCapabilities: :return: data_dict: Dict All available data types """ if "capabilities" not in self._capabilities_cache: - self._capabilities_cache["capabilities"] = RESTCapabilities(self.get('/').json()) + self._capabilities_cache["capabilities"] = RESTCapabilities(self.get('/').json(), self._orig_url) return self._capabilities_cache["capabilities"] @@ -558,7 +560,7 @@ def list_file_formats(self) -> dict: """ if "file_formats" not in self._capabilities_cache: self._capabilities_cache["file_formats"] = self.get('/file_formats').json() - return self._capabilities_cache["file_formats"] + return VisualDict("file-formats", data = self._capabilities_cache["file_formats"]) def list_service_types(self) -> dict: """ @@ -566,7 +568,19 @@ def list_service_types(self) -> dict: :return: data_dict: Dict All available service types """ - return self.get('/service_types').json() + if "service_types" not in self._capabilities_cache: + self._capabilities_cache["service_types"] = self.get('/service_types').json() + return VisualDict("service-types", data = self._capabilities_cache["service_types"]) + + def list_udf_runtimes(self) -> dict: + """ + Loads all available UDF runtimes. + + :return: data_dict: Dict All available UDF runtimes + """ + if "udf_runtimes" not in self._capabilities_cache: + self._capabilities_cache["udf_runtimes"] = self.get('/udf_runtimes').json() + return VisualDict("udf-runtimes", data = self._capabilities_cache["udf_runtimes"]) def list_services(self) -> dict: """ @@ -585,7 +599,8 @@ def describe_collection(self, name) -> dict: :param name: String Id of the collection :return: data_dict: Dict Detailed information about the collection """ - return self.get('/collections/{}'.format(name)).json() + data = self.get('/collections/{}'.format(name)).json() + return VisualDict("collection", data = data) def collection_metadata(self, name) -> CollectionMetadata: return CollectionMetadata(metadata=self.describe_collection(name)) @@ -597,7 +612,8 @@ def list_processes(self) -> List[dict]: :return: processes_dict: Dict All available processes of the back end. """ - return self.get('/processes').json()["processes"] + data = self.get('/processes').json()["processes"] + return VisualList("processes", data = data) def list_jobs(self) -> dict: """ diff --git a/openeo/rest/rest_capabilities.py b/openeo/rest/rest_capabilities.py index e1c151b07..8cbc4bd5f 100644 --- a/openeo/rest/rest_capabilities.py +++ b/openeo/rest/rest_capabilities.py @@ -1,12 +1,14 @@ from openeo.capabilities import Capabilities +from openeo.internal.jupyter import render_component class RESTCapabilities(Capabilities): """Represents REST capabilities of a connection / back end.""" - def __init__(self, data: dict): + def __init__(self, data: dict, url: str = None): super(RESTCapabilities, self).__init__(data) self.capabilities = data + self.url = url def api_version(self) -> str: """ Get openEO version.""" @@ -32,3 +34,6 @@ def currency(self): def list_plans(self): """ List all billing plans.""" return self.capabilities.get('billing', {}).get('plans') + + def _repr_html_(self): + return render_component("capabilities", data = self.capabilities, parameters = {"url": self.url})