From c0f05e0c7c0b01192a981e77b9cb744149634725 Mon Sep 17 00:00:00 2001 From: Stephan Zwicknagl Date: Fri, 2 Feb 2024 12:35:33 -1000 Subject: [PATCH] Fix tests and CI/CD workflows For consistent test results, teardown code was added to the pytest setup of the flask app. The CI/CD workflows were updated to use the latest versions of the actions. The path of the colorPalette.json file was changed and the file is now included in the setup file of the backend. --- .github/workflows/build_and_test.yml | 54 +++++++++---------- .github/workflows/publish_pypi.yml | 4 +- backend/setup.cfg | 3 ++ .../server/{static => }/colorPalette.json | 0 backend/src/viasp/server/startup.py | 30 +++++------ backend/src/viasp/shared/defaults.py | 6 +-- backend/test/conftest.py | 29 +++++++--- backend/test/test_clingraph.py | 16 +++--- docs/viasp/colorPalette.rst | 2 +- examples/quickstart.py | 4 ++ frontend/src/demo/App.js | 2 +- 11 files changed, 88 insertions(+), 62 deletions(-) rename backend/src/viasp/server/{static => }/colorPalette.json (100%) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index f6ebb948..51d80671 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -14,15 +14,15 @@ jobs: runs-on: "ubuntu-latest" steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' - name: Cache dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.pythonLocation }} key: ${{ env.pythonLocation }}-${{ hashFiles('requirements.txt') }} @@ -37,16 +37,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '19' + node-version: '20' - name: Cache node_modules id: cache-node-modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ./frontend/node_modules key: node-modules-${{ hashFiles('./frontend/package-lock.json') }} @@ -61,27 +61,27 @@ jobs: needs: [ python, node ] steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' - name: Get python packages from cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.pythonLocation }} key: ${{ env.pythonLocation }}-${{ hashFiles('requirements.txt') }} id: cache - name: Setup node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '19' + node-version: '20' - name: Get node from cache id: cache-node-modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ./frontend/node_modules key: node-modules-${{ hashFiles('./frontend/package-lock.json') }} @@ -102,7 +102,7 @@ jobs: kill -9 $PID - name: Upload frontend to GitHub - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: retention-days: 7 name: frontend-${{ github.sha }} @@ -114,15 +114,15 @@ jobs: needs: python steps: - name: Checking out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' - name: Get python packages from cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.pythonLocation }} key: ${{ env.pythonLocation }}-${{ hashFiles('requirements.txt') }} @@ -133,7 +133,7 @@ jobs: run: python -m build --sdist --wheel --outdir dist/; - name: Upload backend to GitHub - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: retention-days: 7 name: backend-${{ github.sha }} @@ -145,19 +145,19 @@ jobs: needs: build-backend steps: - name: Checking out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: backend-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' - name: Get python packages from cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.pythonLocation }} key: ${{ env.pythonLocation }}-${{ hashFiles('requirements.txt') }} @@ -184,23 +184,23 @@ jobs: needs: [ build-backend, frontend ] steps: - name: Checking out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get backend artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: backend-${{ github.sha }} - name: Get frontend artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: frontend-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' - name: Get python packages from cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.pythonLocation }} key: ${{ env.pythonLocation }}-${{ hashFiles('requirements.txt') }} diff --git a/.github/workflows/publish_pypi.yml b/.github/workflows/publish_pypi.yml index 0069c117..99a39130 100644 --- a/.github/workflows/publish_pypi.yml +++ b/.github/workflows/publish_pypi.yml @@ -64,12 +64,12 @@ jobs: uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' - name: Cache conda env - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.pythonLocation }} key: ${{ env.pythonLocation }}-${{ hashFiles('requirements.txt') }} diff --git a/backend/setup.cfg b/backend/setup.cfg index 5bbae3ce..44610ab7 100644 --- a/backend/setup.cfg +++ b/backend/setup.cfg @@ -29,6 +29,9 @@ install_requires = [options.packages.find] where = src +[options.package_data] +viasp = server/colorPalette.json + [options.entry_points] console_scripts = viasp_server = viasp.__main__:backend diff --git a/backend/src/viasp/server/static/colorPalette.json b/backend/src/viasp/server/colorPalette.json similarity index 100% rename from backend/src/viasp/server/static/colorPalette.json rename to backend/src/viasp/server/colorPalette.json diff --git a/backend/src/viasp/server/startup.py b/backend/src/viasp/server/startup.py index 46cead12..1ae05822 100644 --- a/backend/src/viasp/server/startup.py +++ b/backend/src/viasp/server/startup.py @@ -15,6 +15,7 @@ import shutil from subprocess import Popen from time import time +import json import viasp_dash from dash import Dash, jupyter_dash @@ -22,15 +23,15 @@ from viasp import clingoApiClient from viasp.shared.defaults import (DEFAULT_BACKEND_HOST, DEFAULT_BACKEND_PORT, - DEFAULT_BACKEND_PROTOCOL, CLINGRAPH_PATH, - GRAPH_PATH, PROGRAM_STORAGE_PATH, STDIN_TMP_STORAGE_PATH, - COLOR_PALETTE) + DEFAULT_BACKEND_PROTOCOL, CLINGRAPH_PATH, + GRAPH_PATH, PROGRAM_STORAGE_PATH, + STDIN_TMP_STORAGE_PATH, COLOR_PALETTE_PATH) def run(host=DEFAULT_BACKEND_HOST, port=DEFAULT_BACKEND_PORT): """ create the dash app, set layout and start the backend on host:port """ - + # if running in binder, get proxy information # and set the backend URL, which will be used # by the frontend @@ -40,17 +41,16 @@ def run(host=DEFAULT_BACKEND_HOST, port=DEFAULT_BACKEND_PORT): _default_server_url = _jupyter_config['server_url'] _default_requests_pathname_prefix = ( - _jupyter_config['base_subpath'].rstrip('/') + '/proxy/' + str(port) - ) + _jupyter_config['base_subpath'].rstrip('/') + '/proxy/' + + str(port)) - backend_url = _default_server_url+_default_requests_pathname_prefix + backend_url = _default_server_url + _default_requests_pathname_prefix elif 'google.colab' in sys.modules: - from google.colab.output import eval_js # type: ignore - backend_url=eval_js(f"google.colab.kernel.proxyPort({port})") + from google.colab.output import eval_js # type: ignore + backend_url = eval_js(f"google.colab.kernel.proxyPort({port})") else: backend_url = f"{DEFAULT_BACKEND_PROTOCOL}://{host}:{port}" - command = ["viasp_server", "--host", host, "--port", str(port)] # if 'ipykernel_launcher.py' in sys.argv[0]: @@ -60,12 +60,12 @@ def run(host=DEFAULT_BACKEND_HOST, port=DEFAULT_BACKEND_PORT): log = open('viasp.log', 'w', encoding="utf-8") viasp_backend = Popen(command, stdout=log, stderr=log) + color_palette = json.load( + open(COLOR_PALETTE_PATH, "r")) app = Dash(__name__) - app.layout = viasp_dash.ViaspDash( - id="myID", - backendURL=backend_url, - colorPalette=COLOR_PALETTE - ) + app.layout = viasp_dash.ViaspDash(id="myID", + backendURL=backend_url, + colorPalette=color_palette) app.title = "viASP" # make sure the backend is up, before continuing with other modules diff --git a/backend/src/viasp/shared/defaults.py b/backend/src/viasp/shared/defaults.py index 65bfe650..ae8cf87d 100644 --- a/backend/src/viasp/shared/defaults.py +++ b/backend/src/viasp/shared/defaults.py @@ -1,6 +1,5 @@ import pathlib import os -import json DEFAULT_BACKEND_PROTOCOL = "http" DEFAULT_BACKEND_HOST = "localhost" @@ -9,8 +8,9 @@ DEFAULT_BACKEND_URL = f"{DEFAULT_BACKEND_PROTOCOL}://{DEFAULT_BACKEND_HOST}:{DEFAULT_BACKEND_PORT}" SHARED_PATH = pathlib.Path(__file__).parent.resolve() GRAPH_PATH = SHARED_PATH / "viasp_graph_storage.db" -STATIC_PATH = pathlib.Path(__file__).parent.parent.resolve() / "server/static/" +SERVER_PATH = pathlib.Path(__file__).parent.parent.resolve() / "server/" +STATIC_PATH = os.path.join(SERVER_PATH, "static") CLINGRAPH_PATH = os.path.join(STATIC_PATH, "clingraph") PROGRAM_STORAGE_PATH = SHARED_PATH / "prg.lp" STDIN_TMP_STORAGE_PATH = SHARED_PATH / "viasp_stdin_tmp.lp" -COLOR_PALETTE = json.load(open(os.path.join(STATIC_PATH, "colorPalette.json"), "r")) \ No newline at end of file +COLOR_PALETTE_PATH = SERVER_PATH / "colorPalette.json" diff --git a/backend/test/conftest.py b/backend/test/conftest.py index 9d25ddfb..9236eb86 100644 --- a/backend/test/conftest.py +++ b/backend/test/conftest.py @@ -146,23 +146,40 @@ def client_with_a_single_node_graph(get_sort_program_and_get_all_graphs, a_1) -> @pytest.fixture(params=["program_simple", "program_multiple_sorts", "program_recursive"]) -def client_with_a_graph(request, get_sort_program_and_get_all_graphs) -> Generator[Tuple[FlaskClient, ProgramAnalyzer, List[Tuple[Mapping, str, str, int]], str], Any, Any]: +def client_with_a_graph( + request, get_sort_program_and_get_all_graphs +) -> Generator[Tuple[FlaskClient, ProgramAnalyzer, List[Tuple[ + Mapping, str, str, int]], str], Any, Any]: app = create_app_with_registered_blueprints(app_bp, api_bp, dag_bp) program = request.getfixturevalue(request.param) - serializable_graphs, analyzer = get_sort_program_and_get_all_graphs(program) + serializable_graphs, analyzer = get_sort_program_and_get_all_graphs( + program) with app.test_client() as client: for serializable_graph, hash, sorted_program, _ in serializable_graphs: - client.post("graph", json={"data": serializable_graph, "hash": hash, "sort": sorted_program}) + client.post("graph", + json={ + "data": serializable_graph, + "hash": hash, + "sort": sorted_program + }) yield client, analyzer, serializable_graphs, program + _ = client.delete("/control/clingraph") + _ = client.post("/control/models/clear") + _ = client.delete("/graph/clear") @pytest.fixture -def client_with_a_clingraph(client_with_a_graph, get_clingo_stable_models) -> Generator[Tuple[FlaskClient, ProgramAnalyzer, List[Tuple[Mapping, str, str, int]], str], Any, Any]: +def client_with_a_clingraph( + client_with_a_graph, get_clingo_stable_models +) -> Generator[Tuple[FlaskClient, ProgramAnalyzer, List[Tuple[ + Mapping, str, str, int]], str], Any, Any]: client, analyzer, serializable_graphs, program = client_with_a_graph - _ = client.delete("/control/clingraph") serialized = get_clingo_stable_models(program) - _ = client.post("/control/models", json=serialized, headers={'Content-Type': 'application/json'}) + print(f"Marking models: {serialized}", flush=True) + _ = client.post("/control/models", + json=serialized, + headers={'Content-Type': 'application/json'}) yield client, analyzer, serializable_graphs, program diff --git a/backend/test/test_clingraph.py b/backend/test/test_clingraph.py index 2307af4d..77259d80 100644 --- a/backend/test/test_clingraph.py +++ b/backend/test/test_clingraph.py @@ -98,13 +98,15 @@ def test_clingraph_edges(client_with_a_clingraph): assert res.status_code == 200 assert res.data == b'ok' + res = client.post(f"/graph/edges", + json={ + "shownRecursion": [], + "usingClingraph": "true" + }) + assert res.status_code == 200 + assert type(res.json) == list if "{b(X)}" in program: - res = client.post(f"/graph/edges", - json={ - "shownRecursion": [], - "usingClingraph": "true" - }) - assert res.status_code == 200 - assert type(res.json) == list # program_simple and program_multiple_sorts assert len(res.json) == 12 + else: + assert len(res.json) == 2 diff --git a/docs/viasp/colorPalette.rst b/docs/viasp/colorPalette.rst index 059559ae..39aa8289 100644 --- a/docs/viasp/colorPalette.rst +++ b/docs/viasp/colorPalette.rst @@ -2,7 +2,7 @@ Color Palette ================= -The color Palette of viASP's frontend is defined by the file `/server/static/colorPalette.json`. +The color Palette of viASP's frontend is defined by the file `/server/colorPalette.json`. The default file contains the following JSON object: diff --git a/examples/quickstart.py b/examples/quickstart.py index 32a0ac8a..11d5ddd3 100644 --- a/examples/quickstart.py +++ b/examples/quickstart.py @@ -19,6 +19,10 @@ def main(): ctl.viasp.mark(m) print(handle.get()) ctl.viasp.show() + ctl.viasp.clingraph(viz_encoding="viz_hamiltonian.lp", + engine="dot", + graphviz_type="graph") + app = startup.run() diff --git a/frontend/src/demo/App.js b/frontend/src/demo/App.js index 53c62914..d2732c11 100644 --- a/frontend/src/demo/App.js +++ b/frontend/src/demo/App.js @@ -1,6 +1,6 @@ /* eslint no-magic-numbers: 0 */ import React from 'react'; -import colorPaletteData from '../../../backend/src/viasp/server/static/colorPalette.json'; +import colorPaletteData from '../../../backend/src/viasp/server/colorPalette.json'; import { ViaspDash } from '../lib';