From 7becdea3636cbd18878637efeb96f55a4e40f6d7 Mon Sep 17 00:00:00 2001 From: Five Grant <5@fivegrant.com> Date: Tue, 17 Oct 2023 12:40:00 -0500 Subject: [PATCH] Refactor integration dashboard display for TA1 (#7) * Start on graph creation * Render graph * Render to near parity * Render text correctly * Render scenario names on feature tables * Render as boxes * Round tables * Update README usage * Remove TODOs * Update screenshot --- Makefile | 2 +- README.md | 19 +- dashboard/{utils => }/formatting.py | 0 dashboard/sections.py | 89 ++++++++ dashboard/{utils => }/storage.py | 10 +- dashboard/ui/pages/1_TA1.py | 101 +++------ dashboard/ui/pages/2_TA3.py | 4 +- dashboard/utils/__init__.py | 0 docker/Dockerfile | 5 +- poetry.lock | 321 +++++++++++++++++++++++++++- pyproject.toml | 2 + 11 files changed, 461 insertions(+), 92 deletions(-) rename dashboard/{utils => }/formatting.py (100%) create mode 100644 dashboard/sections.py rename dashboard/{utils => }/storage.py (77%) delete mode 100644 dashboard/utils/__init__.py diff --git a/Makefile b/Makefile index 00c0bc5..26ca574 100755 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ dev-init:.env PHONY:up up: .env docker build -f docker/Dockerfile -t integration-dashboard . - docker run --name dashboard -p8501:8501 -e USE_LOCAL='TRUE' -d integration-dashboard + docker run --env-file ./.env --name dashboard -p8501:8501 -d integration-dashboard PHONY:down diff --git a/README.md b/README.md index 478cfc8..c6fb928 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ Specifically, the dashboard indicates Currently, the dashboard is testing `knowledge-middleware` integration but other services and TAs might be checked in the future. -![TA1 Dashboard Screenshot](https://github.com/DARPA-ASKEM/integration-dashboard/assets/14170067/da57d762-6e22-4130-ad34-ff790ef590e2) +![TA1 Dashboard Screenshot](https://github.com/DARPA-ASKEM/integration-dashboard/assets/14170067/90e84a0b-ea0e-4d51-81b5-0c9b714a9713) + ## Usage @@ -17,25 +18,19 @@ but other services and TAs might be checked in the future. To view the current status, start the [Streamlit](https://streamlit.io/) app by running: ``` +cp sample.env .env +# Change `.env` as needed make up ``` -Upon execution, you can pass the following environment variables (with `docker run` do `-e ENV_NAME='ENV_VAL'` for each variable). +### Options - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`: Standard credentials for reading and writing to S3 - `BUCKET`: The bucket you'd like to read and write to. +- `USE_LOCAL`: Read from the gitignore files in `output/ta*` instead of S3. - +## Developing To set up the project for development, run ``` make dev-init ``` -To add a new report, run from [`knowledge-middleware`](https://github.com/DARPA-ASKEM/knowledge-middleware) (NOT THIS REPO) -``` -# REMINDER: RUN THIS IN `knowledge-middleware` -poetry run poe report -``` -This uploads a `report_{datetime}.json` to S3 which the dashboard reads -off of directly. - - diff --git a/dashboard/utils/formatting.py b/dashboard/formatting.py similarity index 100% rename from dashboard/utils/formatting.py rename to dashboard/formatting.py diff --git a/dashboard/sections.py b/dashboard/sections.py new file mode 100644 index 0000000..a1f341e --- /dev/null +++ b/dashboard/sections.py @@ -0,0 +1,89 @@ +from pyvis.network import Network +import networkx as nx +import pandas as pd +import streamlit as st +import streamlit.components.v1 as components + +from dashboard.formatting import custom_title + + +def render_scenario_viewer(scenarios): + st.write(f"### Scenario Viewer") + scenario_name = st.selectbox("Select a pipeline:", list(scenarios.keys())) + scenario = scenarios[scenario_name] + + graph = nx.DiGraph() + steps = scenario["steps"] + total_time = 0 + for step_name, step_details in steps.items(): + total_time += step_details["time"] + status_color = 'green' if step_details['success'] else 'red' + graph.add_node(step_name, color=status_color) + shape = scenario["shape"] + for link in shape: + graph.add_edge(link["from"], link["to"]) + nx.set_node_attributes(graph, "box", "shape") + pipeline = Network(notebook=False, directed=True) + pipeline.from_nx(graph) + pipeline.options = { + 'layout': { + 'hierarchical': { + 'enabled': True, + 'direction': 'LR', + 'sortMethod': 'directed' + }, + }, + } + display = pipeline.generate_html() + + + st.write(f"### {scenario_name}") + st.text(scenario["description"]) + st.metric("Total Time", round(total_time,2)) + components.html(display, height=800, width=800) + + +def render_section_scenario_status(scenarios): + st.write(f"### Scenario Status") + status_data = { + "Scenario": list(scenarios.keys()), + "Success": [scenario["success"] for scenario in scenarios.values()], + "Total Time": [ + round(sum([step["time"] for step in scenario["steps"].values()]),2) + for scenario in scenarios.values() + ] + } + df = pd.DataFrame(status_data) + df.replace({False: "❌", True: "✅"}, inplace=True) + st.dataframe(df, hide_index=True) + + +def get_feature_table(scenarios, feature): + results = {} + step_names = set() + for scenario_name, scenario in scenarios.items(): + for step_name, step in scenario["steps"].items(): + step_names.add(step_name) + results[(scenario_name, step_name)] = step[feature] + df = pd.DataFrame(index=list(scenarios.keys()), columns=list(step_names)) + for (scenario_name, step_name), result in results.items(): + df.at[scenario_name, step_name] = result + return df + +def render_section_integration_status(scenarios): + st.write(f"### Integration Status") + df = get_feature_table(scenarios, "success") + df.replace({False: "❌", True: "✅", None: ""}, inplace=True) + st.dataframe(df) + +def render_section_time(scenarios): + st.write(f"### Execution Time") + df = get_feature_table(scenarios, "time") + df = df.applymap(lambda t: round(t,2), ) # `df.round(2)` is ineffective + st.dataframe(df) + + +def render_section_accuracy(scenarios): + st.write(f"### Accuracy") + df = get_feature_table(scenarios, "accuracy") + st.dataframe(df) diff --git a/dashboard/utils/storage.py b/dashboard/storage.py similarity index 77% rename from dashboard/utils/storage.py rename to dashboard/storage.py index bf65734..440256e 100644 --- a/dashboard/utils/storage.py +++ b/dashboard/storage.py @@ -7,6 +7,8 @@ import streamlit as st +from dashboard.formatting import custom_title + BUCKET = os.environ.get("BUCKET") USE_LOCAL = os.environ.get("USE_LOCAL", "FALSE").lower() == "true" s3 = boto3.client("s3") @@ -54,4 +56,10 @@ def select_report(ta): st.stop() timestamp_to_filename = {format_timestamp_from_filename(f): f for f in report_files} selected_timestamp = st.selectbox("Select a report", sorted(timestamp_to_filename.keys(), reverse=True)) - return report_files[timestamp_to_filename[selected_timestamp]] \ No newline at end of file + report = report_files[timestamp_to_filename[selected_timestamp]] + # TODO: Remove conditional once TA1 and TA3 match + if ta == "ta1": + for scenario in report["scenarios"].values(): + scenario["steps"] = { custom_title(name): step for name, step in scenario["steps"].items()} + scenario["shape"] = [ {"from": custom_title(edge["from"]), "to": custom_title(edge["to"])} for edge in scenario["shape"]] + return report \ No newline at end of file diff --git a/dashboard/ui/pages/1_TA1.py b/dashboard/ui/pages/1_TA1.py index d91ddc8..d9e771d 100644 --- a/dashboard/ui/pages/1_TA1.py +++ b/dashboard/ui/pages/1_TA1.py @@ -7,88 +7,43 @@ import streamlit as st import pandas as pd -from dashboard.utils.storage import select_report -from dashboard.utils.formatting import custom_title +from dashboard.storage import select_report +from dashboard.formatting import custom_title +from dashboard.sections import ( + render_scenario_viewer, + render_section_scenario_status, + render_section_integration_status, + render_section_time, + render_section_accuracy +) -# Let the user select a report based on formatted timestamps st.title("TA1 Integration Dashboard") -# Let the user select a report based on formatted timestamps report = select_report("ta1") -if "scenarios" not in report: # OLD FORMAT - report_scenarios = report - services = None -else: # NEW FORMAT - report_scenarios = report["scenarios"] - services = report["services"] - - -test_results = defaultdict(lambda: defaultdict()) - -for scenario, content in report_scenarios.items(): - for operation, tests in content["operations"].items(): - for name, result in tests.items(): - test_results[name][(content["name"], operation)] = result - -scenarios = [report_scenarios[scenario]["name"] for scenario in report_scenarios.keys()] -operations = list(reduce(lambda left, right: left.union(right), [set(content["operations"].keys()) for content in report_scenarios.values()], set())) -tests = sorted([i for i in test_results.keys() if i != "Logs"], reverse=True) -tests.append("Logs") - - -dataframes = {name: pd.DataFrame(index=scenarios, columns=operations) for name in tests} - st.sidebar.markdown(""" # TA1 TA1 integration status and quality metrics. - -The current metrics are: -- Status of `knowledge-middleware` integration -- F-score for conversion of code/equations to AMR -- Execution time -- Application logs """) -""" -### Tests Overview - -* `Equations to AMR`: tests the ability to send a set of equations to `SKEMA` and to receive a valid AMR as response. Currently only LaTeX is tested. -* `Code to AMR`: tests the ability to send a code snippet (model core dynamics) to `SKEMA` and to receive a valid AMR as response. Currently only Python is tested. -* `PDF Extraction`: tests the ability to send a PDF’s text content to `SKEMA` and to receive metadata extractions and groundings in response. -* `Profile Dataset`: tests the ability to send a CSV dataset and corresponding documentation to `MIT` and to receive a “data card” in response. -* `PDF to Text`: tests the ability to send a PDF to `Cosmos` and to receive extracted text in response. -* `Profile Model`: tests the ability to send a valid AMR and corresponding documentation to `MIT` and to receive a “model card” in response. - -Currently tests are run against SKEMA, MIT and Cosmos public instances. -""" - -if services is not None: - st.write("### Service Info") - service_names = list(services.keys()) - service_data = { - "Service": service_names, - "Source": [services[name]["source"] for name in service_names], - "Version": [services[name]["version"] for name in service_names], - } - st.dataframe(pd.DataFrame(service_data), hide_index=True) - - -st.write("### Scenario Overview") -scenarios_overview = "" -for kk, vv in sorted(report_scenarios.items(), key=lambda item: item[1]['name']): - scenarios_overview += f"- **{vv['name']}**: {vv['description']}\n" -st.write(scenarios_overview) - -for test in tests: - df = dataframes[test] - results = test_results[test] - for (scenario_name, operation), result in results.items(): - df.at[scenario_name, operation] = result - st.write(f"### {test}") - df.replace({False: "❌", True: "✅", None: ""}, inplace=True) - df.columns = [custom_title(col) for col in df.columns] - df = df.sort_index() - df \ No newline at end of file +services = report["services"] +st.write("## Service Info") +service_names = list(services.keys()) +service_data = { + "Service": service_names, + "Source": [services[name]["source"] for name in service_names], + "Version": [services[name]["version"] for name in service_names], +} +st.dataframe(pd.DataFrame(service_data), hide_index=True) + + +scenarios = report["scenarios"] + +st.write("## Testing") +render_section_scenario_status(scenarios) +render_section_integration_status(scenarios) +render_section_time(scenarios) +render_section_accuracy(scenarios) +render_scenario_viewer(scenarios) diff --git a/dashboard/ui/pages/2_TA3.py b/dashboard/ui/pages/2_TA3.py index 3627b0f..6294fb9 100644 --- a/dashboard/ui/pages/2_TA3.py +++ b/dashboard/ui/pages/2_TA3.py @@ -8,8 +8,8 @@ import streamlit as st import pandas as pd -from dashboard.utils.storage import select_report -from dashboard.utils.formatting import custom_title +from dashboard.storage import select_report +from dashboard.formatting import custom_title st.title("TA3 Integration Dashboard") diff --git a/dashboard/utils/__init__.py b/dashboard/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/docker/Dockerfile b/docker/Dockerfile index e47a0b1..539ccd8 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,9 +6,10 @@ RUN poetry config virtualenvs.create false COPY pyproject.toml pyproject.toml COPY poetry.lock poetry.lock COPY README.md README.md -COPY dashboard dashboard +RUN poetry install --no-root -RUN poetry install +COPY dashboard dashboard +RUN poetry install --only-root COPY .streamlit .streamlit COPY outputs outputs diff --git a/poetry.lock b/poetry.lock index f389721..9744f15 100644 --- a/poetry.lock +++ b/poetry.lock @@ -54,6 +54,34 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"] test = ["anyio[trio]", "coverage[toml] (>=7)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] trio = ["trio (>=0.22)"] +[[package]] +name = "appnope" +version = "0.1.3" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = "*" +files = [ + {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, + {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, +] + +[[package]] +name = "asttokens" +version = "2.4.0" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = "*" +files = [ + {file = "asttokens-2.4.0-py2.py3-none-any.whl", hash = "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69"}, + {file = "asttokens-2.4.0.tar.gz", hash = "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e"}, +] + +[package.dependencies] +six = ">=1.12.0" + +[package.extras] +test = ["astroid", "pytest"] + [[package]] name = "async-timeout" version = "4.0.3" @@ -83,6 +111,17 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib- tests = ["attrs[tests-no-zope]", "zope-interface"] tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +[[package]] +name = "backcall" +version = "0.2.0" +description = "Specifications for callback functions passed in to an API" +optional = false +python-versions = "*" +files = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] + [[package]] name = "blinker" version = "1.6.2" @@ -327,6 +366,31 @@ files = [ [package.extras] toml = ["tomli"] +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "executing" +version = "2.0.0" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = "*" +files = [ + {file = "executing-2.0.0-py2.py3-none-any.whl", hash = "sha256:06df6183df67389625f4e763921c6cf978944721abf3e714000200aab95b0657"}, + {file = "executing-2.0.0.tar.gz", hash = "sha256:0ff053696fdeef426cda5bd18eacd94f82c91f49823a2e9090124212ceea9b08"}, +] + +[package.extras] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] + [[package]] name = "fakeredis" version = "2.18.0" @@ -470,6 +534,63 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "ipython" +version = "8.16.1" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.9" +files = [ + {file = "ipython-8.16.1-py3-none-any.whl", hash = "sha256:0852469d4d579d9cd613c220af7bf0c9cc251813e12be647cb9d463939db9b1e"}, + {file = "ipython-8.16.1.tar.gz", hash = "sha256:ad52f58fca8f9f848e256c629eff888efc0528c12fe0f8ec14f33205f23ef938"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "sys_platform == \"darwin\""} +backcall = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pickleshare = "*" +prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5" + +[package.extras] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] + +[[package]] +name = "jedi" +version = "0.19.1" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, +] + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + [[package]] name = "jinja2" version = "3.1.2" @@ -498,6 +619,22 @@ files = [ {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, ] +[[package]] +name = "jsonpickle" +version = "3.0.2" +description = "Python library for serializing any arbitrary object graph into JSON" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jsonpickle-3.0.2-py3-none-any.whl", hash = "sha256:4a8442d97ca3f77978afa58068768dba7bff2dbabe79a9647bc3cdafd4ef019f"}, + {file = "jsonpickle-3.0.2.tar.gz", hash = "sha256:e37abba4bfb3ca4a4647d28bb9f4706436f7b46c8a8333b4a718abafa8e46b37"}, +] + +[package.extras] +docs = ["jaraco.packaging (>=3.2)", "rst.linker (>=1.9)", "sphinx"] +testing = ["ecdsa", "feedparser", "gmpy2", "numpy", "pandas", "pymongo", "pytest (>=3.5,!=3.7.3)", "pytest-black-multipy", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-flake8 (>=1.1.1)", "scikit-learn", "sqlalchemy"] +testing-libs = ["simplejson", "ujson"] + [[package]] name = "jsonschema" version = "4.19.0" @@ -642,6 +779,20 @@ files = [ {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, ] +[[package]] +name = "matplotlib-inline" +version = "0.1.6" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.5" +files = [ + {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, + {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, +] + +[package.dependencies] +traitlets = "*" + [[package]] name = "mdurl" version = "0.1.2" @@ -653,6 +804,24 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] +[[package]] +name = "networkx" +version = "3.1" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.8" +files = [ + {file = "networkx-3.1-py3-none-any.whl", hash = "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36"}, + {file = "networkx-3.1.tar.gz", hash = "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61"}, +] + +[package.extras] +default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"] +developer = ["mypy (>=1.1)", "pre-commit (>=3.2)"] +doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.13)", "sphinx (>=6.1)", "sphinx-gallery (>=0.12)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"] +test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] + [[package]] name = "numpy" version = "1.25.2" @@ -687,6 +856,16 @@ files = [ {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, ] +[[package]] +name = "nx" +version = "0.0.0" +description = "" +optional = false +python-versions = "*" +files = [ + {file = "nx-0.0.0-py3-none-any.whl", hash = "sha256:5e434ddf4ded47ff83624db8cbc085022e7ba49a6c5d3214873823ceeff5a098"}, +] + [[package]] name = "packaging" version = "23.1" @@ -756,6 +935,21 @@ sql-other = ["SQLAlchemy (>=1.4.36)"] test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] xml = ["lxml (>=4.8.0)"] +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + [[package]] name = "pastel" version = "0.2.1" @@ -767,6 +961,31 @@ files = [ {file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"}, ] +[[package]] +name = "pexpect" +version = "4.8.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pickleshare" +version = "0.7.5" +description = "Tiny 'shelve'-like database with concurrency support" +optional = false +python-versions = "*" +files = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] + [[package]] name = "pillow" version = "9.5.0" @@ -879,6 +1098,20 @@ tomli = ">=1.2.2" [package.extras] poetry-plugin = ["poetry (>=1.0,<2.0)"] +[[package]] +name = "prompt-toolkit" +version = "3.0.39" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, + {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, +] + +[package.dependencies] +wcwidth = "*" + [[package]] name = "protobuf" version = "4.24.2" @@ -901,6 +1134,31 @@ files = [ {file = "protobuf-4.24.2.tar.gz", hash = "sha256:7fda70797ddec31ddfa3576cbdcc3ddbb6b3078b737a1a87ab9136af0570cd6e"}, ] +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + [[package]] name = "pyarrow" version = "13.0.0" @@ -1275,6 +1533,22 @@ files = [ [package.dependencies] tzdata = {version = "*", markers = "python_version >= \"3.6\""} +[[package]] +name = "pyvis" +version = "0.3.2" +description = "A Python network graph visualization library" +optional = false +python-versions = ">3.6" +files = [ + {file = "pyvis-0.3.2-py3-none-any.whl", hash = "sha256:5720c4ca8161dc5d9ab352015723abb7a8bb8fb443edeb07f7a322db34a97555"}, +] + +[package.dependencies] +ipython = ">=5.3.0" +jinja2 = ">=2.9.6" +jsonpickle = ">=1.4.1" +networkx = ">=1.11" + [[package]] name = "redis" version = "4.6.0" @@ -1572,6 +1846,25 @@ files = [ {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + [[package]] name = "streamlit" version = "1.26.0" @@ -1679,6 +1972,21 @@ files = [ {file = "tornado-6.3.3.tar.gz", hash = "sha256:e7d8db41c0181c80d76c982aacc442c0783a2c54d6400fe028954201a2e032fe"}, ] +[[package]] +name = "traitlets" +version = "5.11.2" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.8" +files = [ + {file = "traitlets-5.11.2-py3-none-any.whl", hash = "sha256:98277f247f18b2c5cabaf4af369187754f4fb0e85911d473f72329db8a7f4fae"}, + {file = "traitlets-5.11.2.tar.gz", hash = "sha256:7564b5bf8d38c40fa45498072bf4dc5e8346eb087bbf1e2ae2d8774f6a0f078e"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.5.1)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] + [[package]] name = "typing-extensions" version = "4.7.1" @@ -1796,6 +2104,17 @@ files = [ [package.extras] watchmedo = ["PyYAML (>=3.10)"] +[[package]] +name = "wcwidth" +version = "0.2.8" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.8-py2.py3-none-any.whl", hash = "sha256:77f719e01648ed600dfa5402c347481c0992263b81a027344f3e1ba25493a704"}, + {file = "wcwidth-0.2.8.tar.gz", hash = "sha256:8705c569999ffbb4f6a87c6d1b80f324bd6db952f5eb0b95bc07517f4c1813d4"}, +] + [[package]] name = "zipp" version = "3.16.2" @@ -1814,4 +2133,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "ef1cfc083f45810fccf9a7b2d4b4f759423e289ef101021158ff66523e368829" +content-hash = "c10600f6e73225cde82a44148bb8dbca33a64f254cab7d9f702ee00d0b7ce80d" diff --git a/pyproject.toml b/pyproject.toml index bf512a8..b246fa3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,8 @@ streamlit = "^1.26.0" poethepoet = "^0.22.1" service-test-tools = {git = "https://github.com/jataware/service-test-tools"} boto3 = "^1.28.43" +pyvis = "^0.3.2" +nx = "^0.0.0" [tool.poetry.group.ta1.dependencies] knowledge-middleware = {git = "https://github.com/DARPA-ASKEM/knowledge-middleware"}