airavata-api/airavata-client-sdks/airavata-python-sdk/airavata_experiments/__init__.py (70 lines of code) (raw):
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import annotations
from . import base, plan
from .auth import login, logout
from .runtime import list_runtimes, Runtime
from typing import Any
__all__ = ["login", "logout", "list_runtimes", "base", "plan"]
def display_runtimes(runtimes: list[Runtime]) -> None:
"""
Display runtimes in a tabular format
"""
import pandas as pd
records = []
for runtime in runtimes:
record = dict(id=runtime.id, **runtime.args)
records.append(record)
d = get_display_fn()
d(pd.DataFrame(records).set_index("id"))
def display_experiments(experiments: list[base.Experiment]) -> None:
"""
Display experiments in a tabular format
"""
import pandas as pd
records = []
for experiment in experiments:
record = dict(name=experiment.name, application=experiment.application.app_id, num_tasks=len(experiment.tasks))
for k, v in experiment.inputs.items():
record[k] = ", ".join(v) if isinstance(v, list) else str(v)
records.append(record)
d = get_display_fn()
d(pd.DataFrame(records).set_index("name"))
def display_plans(plans: list[plan.Plan]) -> None:
"""
Display plans in a tabular format
"""
from IPython.display import HTML
html = """
<table border='1'>
<tr>
<th><b>Plan Id</b></th>
<th><b>Task Id</b></th>
<th><b>State</b></th>
<th><b>Name</b></th>
<th><b>App</b></th>
<th><b>Inputs</b></th>
<th><b>Cluster</b></th>
<th><b>Group</b></th>
<th><b>Category</b></th>
<th><b>Queue</b></th>
<th><b>Nodes</b></th>
<th><b>CPUs</b></th>
<th><b>GPUs</b></th>
<th><b>Time</b></th>
</tr>
"""
for plan in plans:
for task in plan.tasks:
html += generate_task_row(plan.id or "N/A", task)
html += "<tr></tr>"
html += "</table>"
script = """
<script type="text/javascript">
document.querySelectorAll('.hover-container').forEach(item => {
item.addEventListener('mouseover', () => item.querySelector('.hover-content').style.visibility = 'visible');
item.addEventListener('mouseout', () => item.querySelector('.hover-content').style.visibility = 'hidden');
});
</script>
"""
d = get_display_fn()
d(HTML(html + script))
def generate_task_row(plan_id: str, task: plan.Task):
"""
Generate a row for the task
"""
task_id, task_state = task.status() if task.ref else ("N/A", "N/A")
return f"""
<tr>
<td>{plan_id[:8]}...</td>
<td>{task_id}</td>
<td>{task_state}</td>
<td>{task.name}</td>
<td>{task.app_id}</td>
<td>
<div style="position:relative;" class="hover-container">
[Hover]
<div class="hover-content" style="visibility:hidden; position:absolute; top:20px; left:0; background:white; border:1px solid black; padding:5px; z-index:10;">
{generate_inputs_table(task.inputs)}
</div>
</div>
</td>
<td>{task.runtime.args.get("cluster", "N/A")}</td>
<td>{task.runtime.args.get("group", "N/A")}</td>
<td>{task.runtime.args.get("category", "N/A")}</td>
<td>{task.runtime.args.get("queue_name", "N/A")}</td>
<td>{task.runtime.args.get("node_count", "N/A")}</td>
<td>{task.runtime.args.get("cpu_count", "N/A")}</td>
<td>{task.runtime.args.get("gpu_count", "N/A")}</td>
<td>{task.runtime.args.get("walltime", "N/A")}</td>
</tr>
"""
def generate_inputs_table(inputs: dict):
html = """
<table border='1'>
<tr><th><b>Input</b></th><th><b>Type</b></th><th><b>Value</b></th></tr>
"""
for k, v in inputs.items():
html += f"""<tr><th>{k}</th><th>{v.get("type")}</th><th>{v.get("value")}</th></tr>"""
html += "</table>"
return html
def get_display_fn() -> Any:
try:
from IPython.core.getipython import get_ipython
from IPython.display import display as d
if get_ipython() is not None and d is not None:
return d
else:
raise Exception("Not in IPython environment")
except:
return print
def display(arg):
if isinstance(arg, list):
if all(isinstance(x, Runtime) for x in arg):
return display_runtimes(arg)
if all(isinstance(x, base.Experiment) for x in arg):
return display_experiments(arg)
if all(isinstance(x, plan.Plan) for x in arg):
return display_plans(arg)
else:
if isinstance(arg, Runtime):
return display_runtimes([arg])
if isinstance(arg, base.Experiment):
return display_experiments([arg])
if isinstance(arg, plan.Plan):
return display_plans([arg])
raise NotImplementedError(f"Cannot display object of type {type(arg)}")