Skip to content

Commit

Permalink
feat(schematic): move visualization operations endpoints (#2252)
Browse files Browse the repository at this point in the history
* add new endpoints

* added two endpoints

* add new endpoints

* redid exception handling for new endpoints
  • Loading branch information
andrewelamb authored Oct 25, 2023
1 parent 53e48d8 commit c3af47b
Show file tree
Hide file tree
Showing 27 changed files with 1,029 additions and 36 deletions.
1 change: 1 addition & 0 deletions apps/schematic/api/.openapi-generator-ignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ schematic_api/test/test_storage_controller.py
schematic_api/test/test_schema_controller.py
schematic_api/test/test_manifest_validation_controller.py
schematic_api/test/test_versions_controller.py
schematic_api/test/test_tangled_tree_controller.py
tox.ini
2 changes: 1 addition & 1 deletion apps/schematic/api/.openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ schematic_api/controllers/manifest_validation_controller.py
schematic_api/controllers/schema_controller.py
schematic_api/controllers/security_controller_.py
schematic_api/controllers/storage_controller.py
schematic_api/controllers/tangled_tree_controller.py
schematic_api/controllers/versions_controller.py
schematic_api/encoder.py
schematic_api/models/__init__.py
Expand Down Expand Up @@ -39,6 +40,5 @@ schematic_api/models/validation_rules_page.py
schematic_api/models/validation_rules_page_all_of.py
schematic_api/openapi/openapi.yaml
schematic_api/test/__init__.py
schematic_api/test/test_manifest_validation_controller.py
schematic_api/typing_utils.py
schematic_api/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import os
import io
import json
import urllib.request
import shutil
from typing import Union, Any, Optional

import pandas as pd
Expand All @@ -13,24 +11,11 @@

from schematic_api.models.manifest_validation_result import ManifestValidationResult
from schematic_api.models.basic_error import BasicError
from schematic_api.controllers.utils import handle_exceptions, get_access_token


def download_schema_file_as_jsonld(schema_url: str) -> str:
"""Downloads a schema and saves it as temp file
Args:
schema_url (str): The URL of the schema
Returns:
str: The path fo the schema jsonld file
"""
with urllib.request.urlopen(schema_url) as response:
with tempfile.NamedTemporaryFile(
delete=False, suffix=".model.jsonld"
) as tmp_file:
shutil.copyfileobj(response, tmp_file)
return tmp_file.name
from schematic_api.controllers.utils import (
handle_exceptions,
get_access_token,
download_schema_file_as_jsonld,
)


def save_manifest_json_string_as_csv(manifest_json_string: str) -> str:
Expand Down
32 changes: 32 additions & 0 deletions apps/schematic/api/schematic_api/controllers/schema_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,25 @@
from schematic_api.controllers import schema_controller_impl


def get_component(component_label, schema_url, include_index=None): # noqa: E501
"""Get all the attributes associated with a specific data model component formatted as a dataframe (stored as a JSON String).
Get all the attributes associated with a specific data model component formatted as a dataframe (stored as a JSON String). # noqa: E501
:param component_label: The label of a component in a schema
:type component_label: str
:param schema_url: The URL of a schema in jsonld form
:type schema_url: str
:param include_index: Whether to include the indexes of the dataframe in the returned JSON string.
:type include_index: bool
:rtype: Union[str, Tuple[str, int], Tuple[str, int, Dict[str, str]]
"""
return schema_controller_impl.get_component(
component_label, schema_url, include_index
)


def get_connected_nodes(schema_url, relationship_type): # noqa: E501
"""Gets a list of connected node pairs
Expand Down Expand Up @@ -79,6 +98,19 @@ def get_property_label(
)


def get_schema_attributes(schema_url): # noqa: E501
"""Get all the attributes associated with a data model formatted as a dataframe (stored as a JSON String).
Get all the attributes associated with a data model formatted as a dataframe (stored as a JSON String). # noqa: E501
:param schema_url: The URL of a schema in jsonld form
:type schema_url: str
:rtype: Union[str, Tuple[str, int], Tuple[str, int, Dict[str, str]]
"""
return schema_controller_impl.get_schema_attributes(schema_url)


def list_node_dependencies(
node_label, schema_url, return_display_names=None, return_ordered_by_schema=None
): # noqa: E501
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from typing import Union, Any

from schematic.schemas.generator import SchemaGenerator, SchemaExplorer # type: ignore
from schematic.visualization.attributes_explorer import AttributesExplorer # type: ignore

from schematic_api.models.basic_error import BasicError
from schematic_api.models.node_properties_page import NodePropertiesPage
Expand All @@ -12,7 +13,37 @@
from schematic_api.models.node import Node
from schematic_api.models.connected_nodes_page import ConnectedNodesPage
from schematic_api.models.connected_nodes import ConnectedNodes
from schematic_api.controllers.utils import handle_exceptions
from schematic_api.controllers.utils import (
handle_exceptions,
download_schema_file_as_jsonld,
)


@handle_exceptions
def get_component(
component_label: str, schema_url: str, include_index: bool = False
) -> tuple[Union[str, BasicError], int]:
"""
Get all the attributes associated with a specific data model component formatted as a
dataframe (stored as a JSON String).
Args:
component_label (str): The label of the component
schema_url (str): The URL of the schema in json form
include_index (bool): Whether to include the indexes of the dataframe
Returns:
tuple[Union[str, BasicError], int]: A tuple
The first item is either the component or an error object
The second item is the response status
"""
schema_path = download_schema_file_as_jsonld(schema_url)
explorer = AttributesExplorer(schema_path)
result: Union[str, BasicError] = explorer.parse_component_attributes(
component=component_label, save_file=False, include_index=include_index
)
status = 200
return result, status


def get_connected_nodes_from_schematic(
Expand Down Expand Up @@ -162,6 +193,27 @@ def get_property_label(
return result, status


@handle_exceptions
def get_schema_attributes(schema_url: str) -> tuple[Union[str, BasicError], int]:
"""
Get all the attributes associated with a data model formatted as a dataframe
(stored as a JSON String).
Args:
schema_url (str): The URL of the schema in json form
Returns:
tuple[Union[str, BasicError], int]: A tuple
The first item is either the sttraibutes or an error object
The second item is the response status
"""
schema_path = download_schema_file_as_jsonld(schema_url)
explorer = AttributesExplorer(schema_path)
result: Union[str, BasicError] = explorer.parse_attributes(save_file=False)
status = 200
return result, status


def get_node_properties_from_schematic(
node_label: str,
schema_url: str,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import connexion
import six
from typing import Dict
from typing import Tuple
from typing import Union

from schematic_api.models.basic_error import BasicError # noqa: E501
from schematic_api import util
from schematic_api.controllers import tangled_tree_controller_impl


def get_tangled_tree_layers(schema_url, figure_type=None): # noqa: E501
"""Get tangled tree node layers to display for a given data model and figure type
Get tangled tree node layers to display for a given data model and figure type # noqa: E501
:param schema_url: The URL of a schema in jsonld form
:type schema_url: str
:param figure_type: Figure type to generate.
:type figure_type: str
:rtype: Union[str, Tuple[str, int], Tuple[str, int, Dict[str, str]]
"""
return tangled_tree_controller_impl.get_tangled_tree_layers(schema_url, figure_type)


def get_tangled_tree_text(schema_url, figure_type=None, text_format=None): # noqa: E501
"""Get tangled tree plain or higlighted text to display for a given data model, text formatting and figure type
Get tangled tree plain or higlighted text to display for a given data model, text formatting and figure type # noqa: E501
:param schema_url: The URL of a schema in jsonld form
:type schema_url: str
:param figure_type: Figure type to generate.
:type figure_type: str
:param text_format: Text formatting type.
:type text_format: str
:rtype: Union[object, Tuple[object, int], Tuple[object, int, Dict[str, str]]
"""
return tangled_tree_controller_impl.get_tangled_tree_text(
schema_url, figure_type, text_format
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""Tangled tree controllers"""

from typing import Literal, Union

from schematic.visualization.tangled_tree import TangledTree # type: ignore

from schematic_api.models.basic_error import BasicError
from schematic_api.controllers.utils import (
handle_exceptions,
download_schema_file_as_jsonld,
)


@handle_exceptions
def get_tangled_tree_layers(
schema_url: str, figure_type: Literal["component", "dependency"] = "component"
) -> tuple[Union[str, BasicError], int]:
"""Gets layers for a tangled tree visualization.
Args:
schema_url (str): The URL to the schema file
figure_type (Literal["component", "dependency"]): Figure type to generate.
Returns:
tuple[Union[str, BasicError], int]: A tuple
The first item is either the layers or an error object
The second item is the response status
"""
schema_path = download_schema_file_as_jsonld(schema_url)
tangled_tree = TangledTree(schema_path, figure_type)
# Currently TangledTree.get_tangled_tree_layers() returns either an empty list if
# save_file=False or a list of one string if save_file=False.
# The API should output just the string.
# TangledTree.get_tangled_tree_layers() will likely get changed in the future to return
# just a string.
layers_list: list[str] = tangled_tree.get_tangled_tree_layers(save_file=False)
if len(layers_list) == 0:
raise ValueError("TangledTree.get_tangled_tree_layers() returned an empty list")
result: Union[str, BasicError] = layers_list[0]
status = 200

return result, status


@handle_exceptions
def get_tangled_tree_text(
schema_url: str,
figure_type: Literal["component", "dependency"] = "component",
text_format: Literal["plain", "highlighted"] = "plain",
) -> tuple[Union[str, BasicError], int]:
"""Gets text for a tangled tree visualization.
Args:
schema_url (str): The URL to the schema file
figure_type (Literal["component", "dependency"]): Figure type to generate.
text_format (Literal["plain", "highlighted"]): Determines the type of text
rendering to return
Returns:
tuple[Union[str, BasicError], int]: A tuple
The first item is either the text or an error object
The second item is the response status
"""
schema_path = download_schema_file_as_jsonld(schema_url)
tangled_tree = TangledTree(schema_path, figure_type)
result: Union[str, BasicError] = tangled_tree.get_text_for_tangled_tree(
text_format, save_file=False
)
status = 200

return result, status
20 changes: 20 additions & 0 deletions apps/schematic/api/schematic_api/controllers/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from typing import Callable, Union, Any, Optional
import urllib.request
import shutil
import tempfile

from flask import request # type: ignore
from synapseclient.core.exceptions import ( # type: ignore
Expand Down Expand Up @@ -61,3 +64,20 @@ def func(*args: Any, **kwargs: Any) -> tuple[Union[Any, BasicError], int]:
return res, status

return func


def download_schema_file_as_jsonld(schema_url: str) -> str:
"""Downloads a schema and saves it as temp file
Args:
schema_url (str): The URL of the schema
Returns:
str: The path fo the schema jsonld file
"""
with urllib.request.urlopen(schema_url) as response:
with tempfile.NamedTemporaryFile(
delete=False, suffix=".model.jsonld"
) as tmp_file:
shutil.copyfileobj(response, tmp_file)
return tmp_file.name
Loading

0 comments on commit c3af47b

Please sign in to comment.