Skip to content

Commit

Permalink
Merge pull request #93 from appukuttan-shailesh/master
Browse files Browse the repository at this point in the history
Multiple changes
  • Loading branch information
appukuttan-shailesh authored Nov 19, 2020
2 parents 2db5d8f + c3dc9f8 commit f4d859e
Show file tree
Hide file tree
Showing 13 changed files with 352 additions and 384 deletions.
295 changes: 145 additions & 150 deletions hbp_validation_framework/__init__.py

Large diffs are not rendered by default.

20 changes: 12 additions & 8 deletions hbp_validation_framework/datastores.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import requests

import hbp_seafile
import ebrains_drive

mimetypes.init()

Expand All @@ -49,8 +49,8 @@ class CollabV2DataStore(object):
A class for uploading and downloading data from HBP Collaboratory v2 seafile storage.
"""

def __init__(self, project_id=None, base_folder="/", auth=None, **kwargs):
self.project_id = project_id
def __init__(self, collab_id=None, base_folder="/", auth=None, **kwargs):
self.collab_id = collab_id
self.base_folder = base_folder.strip("/")
self._auth = auth # we defer authorization until needed
self._authorized = False
Expand All @@ -62,9 +62,9 @@ def authorized(self):
def authorize(self, auth=None):
if auth is None:
auth = self._auth
self.client = hbp_seafile.connect(token=auth.token)
self.client = ebrains_drive.connect(token=auth.token)
self._authorized = True
self.repo = self.client.repos.get_repo_by_url(self.project_id)
self.repo = self.client.repos.get_repo_by_url(self.collab_id)

def upload_data(self, file_paths, overwrite=False):
if not self.authorized:
Expand Down Expand Up @@ -93,7 +93,8 @@ def upload_data(self, file_paths, overwrite=False):
filename = os.path.basename(relative_path)
seafdir = self.repo.get_dir(parent)
file_entity = seafdir.upload_local_file(local_path, overwrite=overwrite)
uploaded_file_paths.append(upload_path_prefix + file_entity.path)
uploaded_file_paths.append({"filepath": upload_path_prefix + file_entity.path, "filesize": file_entity.size})
# uploaded_file_paths.append(file_entity._get_download_link()) # this does not work as the link changes with token
return uploaded_file_paths

def _make_folders(self, folder_path, parent):
Expand Down Expand Up @@ -205,7 +206,7 @@ def load_data(self, remote_path):

class SwiftDataStore(object):
"""
A class for downloading data from CSCS Swift storage.
A class for uploading and downloading data from CSCS Swift storage.
Note: data from public containers can also be downloaded via `HTTPDataStore`
"""

Expand All @@ -228,7 +229,10 @@ def upload_data(self, file_paths, username="", container="", project=None, remot
container = input("Please enter target container name: ")
container_obj = Container(container, username, project=project)
remote_paths = container_obj.upload(file_paths, remote_directory=remote_directory, overwrite=overwrite)
return remote_paths
uploaded_file_paths = []
for ind, f in enumerate(file_paths):
uploaded_file_paths.append({"filepath": remote_paths[ind], "filesize": os.path.getsize(f)})
return uploaded_file_paths

def get_container(self, remote_path, username=""):
try:
Expand Down
85 changes: 35 additions & 50 deletions hbp_validation_framework/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ def run_test_offline(model="", test_config_file=""):
pickle.dump(score, file)
return test_result_file

def upload_test_result(username="", password=None, environment="production", test_result_file="", storage_project_id="", register_result=True, client_obj=None):
def upload_test_result(username="", password=None, environment="production", test_result_file="", storage_collab_id="", register_result=True, client_obj=None):
"""Register the result with the Validation Service
This method will register the validation result specified via the test result file
Expand All @@ -298,7 +298,7 @@ def upload_test_result(username="", password=None, environment="production", tes
be read (the latter is currently not implemented).
test_result_file : string
Absolute path of the test result file generated by :meth:`run_test_offline`
storage_project_id : string
storage_collab_id : string
Collab ID where output files should be stored; if empty, stored in model's host Collab.
register_result : boolean
Specify whether the test results are to be scored on the validation framework.
Expand All @@ -315,8 +315,8 @@ def upload_test_result(username="", password=None, environment="production", tes
Returns
-------
UUID
UUID of the test result that has been created.
dict
data of test result that has been created.
object
score object evaluated by the test.
Expand All @@ -340,15 +340,15 @@ def upload_test_result(username="", password=None, environment="production", tes
model_catalog = ModelCatalog.from_existing(client_obj)
else:
model_catalog = ModelCatalog(username, password, environment=environment)
model_instance_uuid = model_catalog.find_model_instance_else_add(score.model)
model_instance_uuid = model_catalog.find_model_instance_else_add(score.model)["id"]
model_instance_json = model_catalog.get_model_instance(instance_id=model_instance_uuid)
model_json = model_catalog.get_model(model_id=model_instance_json["model_id"])
model_host_project_id = model_json["project_id"]
model_host_collab_id = model_json["collab_id"]
model_name = model_json["name"]

if not storage_project_id:
storage_project_id = model_host_project_id
score.related_data["project_id"] = storage_project_id
if not storage_collab_id:
storage_collab_id = model_host_collab_id
score.related_data["collab_id"] = storage_collab_id

# Check if result with same hash has already been uploaded for
# this (model instance, test instance) combination; if yes, don't register result
Expand All @@ -369,14 +369,14 @@ def upload_test_result(username="", password=None, environment="production", tes

# `.replace(" ", "_")` used to avoid Collab storage path errors due to spaces
collab_folder = "validation_results/{}/{}_{}".format(datetime.now().strftime("%Y-%m-%d"),model_name.replace(" ", "_"), datetime.now().strftime("%Y%m%d-%H%M%S"))
collab_storage = CollabV2DataStore(project_id=storage_project_id,
collab_storage = CollabV2DataStore(collab_id=storage_collab_id,
base_folder=collab_folder,
auth=test_library.auth)

response = test_library.register_result(test_result=score, data_store=collab_storage)
return response, score

def run_test(username="", password=None, environment="production", model="", test_instance_id="", test_id="", test_alias="", test_version="", storage_project_id="", register_result=True, client_obj=None, **params):
def run_test(username="", password=None, environment="production", model="", test_instance_id="", test_id="", test_alias="", test_version="", storage_collab_id="", register_result=True, client_obj=None, **params):
"""Run validation test and register result
This will execute the following methods by relaying the output of one to the next:
Expand Down Expand Up @@ -406,7 +406,7 @@ def run_test(username="", password=None, environment="production", model="", tes
User-assigned unique identifier associated with test definition.
test_version : string
User-assigned identifier (unique for each test) associated with test instance.
storage_project_id : string
storage_collab_id : string
Collab ID where output files should be stored; if empty, stored in model's host Collab.
register_result : boolean
Specify whether the test results are to be scored on the validation framework.
Expand All @@ -425,24 +425,24 @@ def run_test(username="", password=None, environment="production", model="", tes
Returns
-------
UUID
UUID of the test result that has been created.
dict
data of test result that has been created.
object
score object evaluated by the test.
Examples
--------
>>> result_id, score = utils.run_test(username="HBP_USERNAME", password="HBP_PASSWORD" environment="production", model=cell_model, test_alias="basalg_msn_d1", test_version="1.0", storage_project_id="8123", register_result=True)
>>> result_id, score = utils.run_test(username="HBP_USERNAME", password="HBP_PASSWORD" environment="production", model=cell_model, test_alias="basalg_msn_d1", test_version="1.0", storage_collab_id="8123", register_result=True)
"""

test_config_file = prepare_run_test_offline(username=username, password=password, environment=environment, test_instance_id=test_instance_id, test_id=test_id, test_alias=test_alias, test_version=test_version, client_obj=client_obj, **params)
test_result_file = run_test_offline(model=model, test_config_file=test_config_file)
result_id, score = upload_test_result(username=username, password=password, environment=environment, test_result_file=test_result_file, storage_project_id=storage_project_id, register_result=register_result, client_obj=client_obj)
result_id, score = upload_test_result(username=username, password=password, environment=environment, test_result_file=test_result_file, storage_collab_id=storage_collab_id, register_result=register_result, client_obj=client_obj)
return result_id, score

def generate_HTML_report(username="", password=None, environment="production", model_list=[],
model_instance_list=[], test_list=[], test_instance_list=[],
result_list=[], project_id=None, client_obj=None):
result_list=[], show_links=True, client_obj=None):
"""Generates an HTML report for specified test results
This method will generate an HTML report for the specified test results.
Expand All @@ -467,9 +467,9 @@ def generate_HTML_report(username="", password=None, environment="production", m
List of test instance UUIDs for which score matrix is to be generated.
result_list : list
List of result UUIDs for which score matrix is to be generated.
project_id : string, optional
Collaboratory ID where hyperlinks to results are to be redirected.
If unspecified, these data units will not have clickable hyperlinks.
show_links : boolean, optional
To specify if hyperlinks to results are to be provided.
If false, these data units will not have clickable hyperlinks.
client_obj : ModelCatalog/TestLibrary object
Used to easily create a new ModelCatalog/TestLibrary object if either exist already.
Avoids need for repeated authentications; improves performance. Also, helps minimize
Expand Down Expand Up @@ -502,13 +502,6 @@ def generate_HTML_report(username="", password=None, environment="production", m
model_catalog = ModelCatalog(username, password, environment=environment)
test_library = TestLibrary.from_existing(model_catalog)

if project_id:
# check if app exists; if not then create
MCapp_navID = model_catalog.exists_in_collab_else_create(project_id)
model_catalog.set_app_config(project_id=project_id, app_id=MCapp_navID, only_if_new="True")
VFapp_navID = test_library.exists_in_collab_else_create(project_id)
test_library.set_app_config(project_id=project_id, app_id=VFapp_navID, only_if_new="True")

# retrieve all model instances from specified models
if model_list:
for entry in model_list:
Expand Down Expand Up @@ -543,8 +536,6 @@ def generate_HTML_report(username="", password=None, environment="production", m
# remove duplicate result UUIDs
result_list = list(collections.OrderedDict.fromkeys(result_list).keys())

# TODO: ensure atleast one valid result UUID to be evaluated; else create no report, alert user

# utilize each result entry
result_summary_table = [] # list of dicts, each with 4 keys -> result_id, model_label, test_label, score
list_results = []
Expand All @@ -569,11 +560,10 @@ def generate_HTML_report(username="", password=None, environment="production", m

model_label = (model["alias"] if model["alias"] else model["name"]) + " (" + str(model_instance["version"]) + ")"
test_label = (test["alias"] if test["alias"] else test["name"]) + " (" + str(test_instance["version"]) + ")"
if project_id:
# TODO: update URLs for Collab v2
result_url = "https://collab.humanbrainproject.eu/#/collab/{}/nav/{}?state=result.{}".format(str(project_id),str(VFapp_navID), r_id)
model_url = "https://collab.humanbrainproject.eu/#/collab/{}/nav/{}?state=model.{}".format(str(project_id),str(MCapp_navID), model["id"])
test_url = "https://collab.humanbrainproject.eu/#/collab/{}/nav/{}?state=test.{}".format(str(project_id),str(VFapp_navID), test["id"])
if show_links:
result_url = "https://model-catalog.brainsimulation.eu/#result_id.{}".format(r_id)
model_url = "https://model-catalog.brainsimulation.eu/#model_id.{}".format(model["id"])
test_url = "https://model-catalog.brainsimulation.eu/#test_id.{}".format(test["id"])
result_summary_table.append({"result_id": (r_id, result_url),
"model_label": (model_label, model_url),
"test_label": (test_label, test_url),
Expand Down Expand Up @@ -608,7 +598,7 @@ def generate_HTML_report(username="", password=None, environment="production", m

def generate_PDF_report(html_report_path=None, username="", password=None,
environment="production", model_list=[], model_instance_list=[],
test_list=[], test_instance_list=[], result_list=[], project_id=None,
test_list=[], test_instance_list=[], result_list=[], show_links=True,
only_results=False, client_obj=None):
"""Generates a PDF report for specified test results
Expand Down Expand Up @@ -639,9 +629,9 @@ def generate_PDF_report(html_report_path=None, username="", password=None,
List of test instance UUIDs for which score matrix is to be generated.
result_list : list
List of result UUIDs for which score matrix is to be generated.
project_id : string, optional
Collaboratory ID where hyperlinks to results are to be redirected.
If unspecified, these data units will not have clickable hyperlinks.
show_links : boolean, optional
To specify if hyperlinks to results are to be provided.
If false, these data units will not have clickable hyperlinks.
only_results : boolean, optional
Indicates whether output PDF should contain only result related info.
Set to `False` as default. When set to `True`, the PDF will have info
Expand Down Expand Up @@ -714,7 +704,7 @@ def generate_PDF_report(html_report_path=None, username="", password=None,
goto="temp")
return filepath, valid_result_uuids

def generate_score_matrix(username="", password=None, environment="production", model_list=[], model_instance_list=[], test_list=[], test_instance_list=[], result_list=[], project_id=None, client_obj=None):
def generate_score_matrix(username="", password=None, environment="production", model_list=[], model_instance_list=[], test_list=[], test_instance_list=[], result_list=[], show_links=True, client_obj=None):
"""Generates a styled pandas dataframe with score matrix
This method will generate a styled pandas dataframe for the specified test results.
Expand All @@ -741,9 +731,9 @@ def generate_score_matrix(username="", password=None, environment="production",
List of test instance UUIDs for which score matrix is to be generated.
result_list : list
List of result UUIDs for which score matrix is to be generated.
project_id : string, optional
Collaboratory ID where hyperlinks to results are to be redirected.
If unspecified, the scores will not have clickable hyperlinks.
show_links : boolean, optional
To specify if hyperlinks to results are to be provided.
If false, these data units will not have clickable hyperlinks.
client_obj : ModelCatalog/TestLibrary object
Used to easily create a new ModelCatalog/TestLibrary object if either exist already.
Avoids need for repeated authentications; improves performance. Also, helps minimize
Expand Down Expand Up @@ -785,11 +775,6 @@ def generate_score_matrix(username="", password=None, environment="production",
else:
test_library = TestLibrary(username, password, environment=environment)

if project_id:
# check if app exists; if not then create
VFapp_navID = test_library.exists_in_collab_else_create(project_id)
test_library.set_app_config(project_id=project_id, app_id=VFapp_navID, only_if_new="True")

# retrieve all model instances from specified models
if model_list:
for entry in model_list:
Expand Down Expand Up @@ -830,7 +815,7 @@ def generate_score_matrix(username="", password=None, environment="production",

excluded_results = [] # not latest entry for a particular model instance and test instance combination
for r_id in result_list:
result = test_library.get_result(result_id = r_id)["results"][0]
result = test_library.get_result(result_id = r_id)
# '#*#' is used as separator between score and result UUID (latter used for constructing hyperlink)
if result["test_instance_id"] in results_dict.keys():
if result["model_instance_id"] not in results_dict[result["test_instance_id"]].keys():
Expand Down Expand Up @@ -886,8 +871,8 @@ def make_clickable(value):
if not value:
return value
score, result_uuid = value.split('#*#')
if project_id:
result_url = "https://collab.humanbrainproject.eu/#/collab/{}/nav/{}?state=result.{}".format(str(project_id),str(VFapp_navID), result_uuid)
if show_links:
result_url = "https://model-catalog.brainsimulation.eu/#result_id.{}".format(result_uuid)
return '<a target="_blank" href="{}">{}</a>'.format(result_url,score)
else:
return score
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def package_files(base_dir, directory):

setup(
name='hbp_validation_framework',
version='0.6.0',
version='0.6.1',
packages=['hbp_validation_framework'],
package_data={'': json_files+template_files},
url='https://github.com/HumanBrainProject/hbp-validation-client',
Expand Down
1 change: 0 additions & 1 deletion test.txt

This file was deleted.

Loading

0 comments on commit f4d859e

Please sign in to comment.