Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Geoweaver API + Better UI Response (Pandas + IPython Widgets) #24

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Empty file added pygeoweaver/interactive/list.py
Empty file.
3 changes: 0 additions & 3 deletions pygeoweaver/sc_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
from pygeoweaver.constants import *
from pygeoweaver.utils import (
download_geoweaver_jar,
get_geoweaver_jar_path,
get_java_bin_path,
get_root_dir,
check_ipython,
)

Expand Down
52 changes: 5 additions & 47 deletions pygeoweaver/sc_detail.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,27 @@
"""
Detail subcommand
"""

import subprocess

import requests
from pygeoweaver.constants import *

from pygeoweaver.utils import (
download_geoweaver_jar,
get_geoweaver_jar_path,
get_java_bin_path,
get_root_dir,
get_detail
)


def detail_workflow(workflow_id):
if not workflow_id:
raise RuntimeError("Workflow id is missing")
download_geoweaver_jar()
subprocess.run(
[
get_java_bin_path(),
"-jar",
get_geoweaver_jar_path(),
"detail",
f"--workflow-id={workflow_id}",
],
cwd=f"{get_root_dir()}/",
)
return get_detail(workflow_id, 'workflow')


def detail_process(process_id):
if not process_id:
raise RuntimeError("Process id is missing")
download_geoweaver_jar()
subprocess.run(
[
get_java_bin_path(),
"-jar",
get_geoweaver_jar_path(),
"detail",
f"--process-id={process_id}",
],
cwd=f"{get_root_dir()}/",
)
return get_detail(process_id, 'process')


def detail_host(host_id):
if not host_id:
raise RuntimeError("Host id is missing")
download_geoweaver_jar()
subprocess.run(
[
get_java_bin_path(),
"-jar",
get_geoweaver_jar_path(),
"detail",
f"--host-id={host_id}",
],
cwd=f"{get_root_dir()}/",
)
return get_detail(host_id, 'host')


def get_process_code(process_id):
from pygeoweaver.constants import GEOWEAVER_DEFAULT_ENDPOINT_URL
r = requests.post(
f"{GEOWEAVER_DEFAULT_ENDPOINT_URL}/web/detail",
data={"type": "process", "id": process_id},
Expand Down
6 changes: 3 additions & 3 deletions pygeoweaver/sc_find.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def get_process_by_name(process_name):
pd.set_option("display.max_columns", None) # Display all columns
pd.set_option("display.max_rows", None) # Display all rows
pd.set_option("display.expand_frame_repr", False) # Prevent truncation of columns
pd.DataFrame(matching_processes)
return pd.DataFrame(matching_processes)


def get_process_by_id(process_id):
Expand All @@ -34,7 +34,7 @@ def get_process_by_id(process_id):
pd.set_option("display.max_columns", None) # Display all columns
pd.set_option("display.max_rows", None) # Display all rows
pd.set_option("display.expand_frame_repr", False) # Prevent truncation of columns
pd.DataFrame(matching_processes)
return pd.DataFrame(matching_processes)


def get_process_by_language(language):
Expand All @@ -51,4 +51,4 @@ def get_process_by_language(language):
pd.set_option("display.max_columns", None) # Display all columns
pd.set_option("display.max_rows", None) # Display all rows
pd.set_option("display.expand_frame_repr", False) # Prevent truncation of columns
pd.DataFrame(matching_processes)
return pd.DataFrame(matching_processes)
31 changes: 16 additions & 15 deletions pygeoweaver/sc_import.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import subprocess
import os.path

import requests
from pygeoweaver.utils import (
download_geoweaver_jar,
get_geoweaver_jar_path,
get_java_bin_path,
get_root_dir,
)


Expand All @@ -14,20 +13,22 @@ def import_workflow(workflow_zip_file_path):
<workflow_zip_file_path>
Geoweaver workflow zip file path
"""
from pygeoweaver import GEOWEAVER_DEFAULT_ENDPOINT_URL
if not workflow_zip_file_path:
raise RuntimeError("Workflow zip file path is missing")
download_geoweaver_jar()
subprocess.run(
[
get_java_bin_path(),
"-jar",
get_geoweaver_jar_path(),
"import",
"workflow",
workflow_zip_file_path,
],
cwd=f"{get_root_dir()}/",
)
file_upload_servlet = f"{GEOWEAVER_DEFAULT_ENDPOINT_URL}/FileUploadServlet"
preload_url = f"{GEOWEAVER_DEFAULT_ENDPOINT_URL}/web/preload/workflow"
load_url = f"{GEOWEAVER_DEFAULT_ENDPOINT_URL}/web/load/workflow"
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
file_name = os.path.basename(workflow_zip_file_path)
_id, _ = os.path.splitext(file_name)
files = {'file': (file_name, open(workflow_zip_file_path, 'rb'))}
requests.post(url=file_upload_servlet, files=files) # upload
requests.post(url=preload_url, headers=headers, data={'id': _id, 'filename': file_name}) # preload
requests.post(url=load_url, headers=headers, data={'id': _id, 'filename': file_name}) # load
return 'Import success.'


def import_workflow_from_github(git_repo_url):
pass
1 change: 0 additions & 1 deletion pygeoweaver/sc_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from pygeoweaver.sc_export import *
from pygeoweaver.sc_history import *
from pygeoweaver.sc_import import *
from pygeoweaver.sc_list import *
from pygeoweaver.sc_run import *
from pygeoweaver.server import *
from pygeoweaver.sc_resetpassword import *
Expand Down
69 changes: 51 additions & 18 deletions pygeoweaver/sc_list.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,55 @@
import json

import requests
import subprocess

from IPython.core.display import display, HTML

from pygeoweaver.constants import *
from pygeoweaver.utils import (
download_geoweaver_jar,
get_geoweaver_jar_path,
get_java_bin_path,
get_root_dir,
check_ipython,
check_ipython, create_table,
)
import pandas as pd


def list_hosts():
from IPython import get_ipython
ip = get_ipython()
download_geoweaver_jar()
subprocess.run(
[get_java_bin_path(), "-jar", get_geoweaver_jar_path(), "list", "--host"],
cwd=f"{get_root_dir()}/",
)
url = f"{GEOWEAVER_DEFAULT_ENDPOINT_URL}/web/list"
form_data = {'type': 'host'}
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
data = requests.post(url=url, headers=headers, data=form_data)

if ip is not None:
# Running in a Jupyter Notebook, display as HTML table
data_json = data.json()
table_html = create_table(data_json)
return display(HTML(table_html))
else:
# Not running in a Jupyter Notebook, display as Pandas DataFrame
data_json = data.json()
df = pd.DataFrame(data_json)
return df


def list_processes():
from IPython import get_ipython
ip = get_ipython()
download_geoweaver_jar()
subprocess.run(["chmod", "+x", get_geoweaver_jar_path()], cwd=f"{get_root_dir()}/")
subprocess.run(
[get_java_bin_path(), "-jar", get_geoweaver_jar_path(), "list", "--process"],
cwd=f"{get_root_dir()}/",
)
url = f"{GEOWEAVER_DEFAULT_ENDPOINT_URL}/web/list"
form_data = {'type': 'process'}
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
data = requests.post(url=url, headers=headers, data=form_data)

if ip is not None:
data_json = data.json()
table_html = create_table(data_json)
display(HTML(table_html))
else:
data_json = data.json()
df = pd.DataFrame(data_json)
return df


def list_processes_in_workflow(workflow_id):
Expand All @@ -47,8 +69,19 @@ def list_processes_in_workflow(workflow_id):


def list_workflows():
from IPython import get_ipython
ip = get_ipython()
download_geoweaver_jar()
subprocess.run(
[get_java_bin_path(), "-jar", get_geoweaver_jar_path(), "list", "--workflow"],
cwd=f"{get_root_dir()}/",
)
url = f"{GEOWEAVER_DEFAULT_ENDPOINT_URL}/web/list"
form_data = {'type': 'workflow'}
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
data = requests.post(url=url, headers=headers, data=form_data)

if ip is not None:
data_json = data.json()
table_html = create_table(data_json)
display(HTML(table_html))
else:
data_json = data.json()
df = pd.DataFrame(data_json)
return df
3 changes: 2 additions & 1 deletion pygeoweaver/sc_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def run_process(
process_id,
],
cwd=f"{get_root_dir()}/",
)
) # TODO: need to re-implement password encryption same as Geoweaver codebase to change this


def run_workflow(
Expand Down Expand Up @@ -171,3 +171,4 @@ def run_workflow(
if environment_list:
command.extend(["-e", environment_list])
subprocess.run(command, cwd=f"{get_root_dir()}/")
# TODO: need to re-implement password encryption same as Geoweaver codebase to change this
56 changes: 56 additions & 0 deletions pygeoweaver/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import json
import os
import sys
import shutil
import logging
import subprocess

import pandas as pd
import requests
import platform

from IPython import get_ipython
import ipywidgets as widgets
from IPython.display import display, HTML


def get_home_dir():
Expand Down Expand Up @@ -146,3 +151,54 @@ def copy_files(source_folder, destination_folder):
)
os.makedirs(os.path.dirname(destination_file), exist_ok=True)
shutil.copy2(source_file, destination_file)


def create_table(data, max_length=100):
Copy link
Member

@ZihengSun ZihengSun Oct 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this is a good idea. Also, a table is not impressive improvement comparing to all the other libraries. What we need is a widget that have button and dropdown, selection, text editors, or things similar that. Here is some example: https://medium.com/codex/fancy-world-of-ipywidgets-e3301de58bd7

Overall, people like interactive experiences. Not just a static table. If it is only a simple HTML table, the pandas dataframe output will do it.

table_html = "<table><tr>"

# Create table headers
if len(data) > 0:
for key in data[0].keys():
table_html += f"<th>{key}</th>"
table_html += "</tr>"

# Create table rows
for row in data:
table_html += "<tr>"
for value in row.values():
# Truncate and add ellipses if the value is too long
display_value = str(value)[:max_length] + '...' if len(str(value)) > max_length else str(value)
table_html += f"<td>{display_value}</td>"
table_html += "</tr>"
else:
table_html += "<td>No Data</td></tr>"

table_html += "</table>"

return table_html


def get_detail(id, type):


from pygeoweaver.constants import GEOWEAVER_DEFAULT_ENDPOINT_URL

if not id:
raise RuntimeError("Workflow id is missing")
download_geoweaver_jar()
url = f"{GEOWEAVER_DEFAULT_ENDPOINT_URL}/web/detail"
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
form_data = {'type': type, 'id': id}
d = requests.post(url=url, data=form_data, headers=headers)
d = d.json()
d['nodes'] = json.loads(d['nodes'])
try:
from IPython import get_ipython
if 'IPKernelApp' in get_ipython().config:
table_html = create_table([d])
table_output = widgets.Output()
with table_output:
display(HTML(table_html))
display(table_output)
except:
return pd.DataFrame([d])
Loading