-
Notifications
You must be signed in to change notification settings - Fork 0
MVP #1
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
Open
Nigma-Ks
wants to merge
45
commits into
mvp
Choose a base branch
from
run-runstrat-in-docker
base: mvp
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
MVP #1
Changes from all commits
Commits
Show all changes
45 commits
Select commit
Hold shift + click to select a range
ad42a88
add: .idea files to gitignore
Nigma-Ks b862616
feat(dockerfile): add build PySymGym dockerfile
Nigma-Ks f7f9218
fix: make building on macos dockerfile
Nigma-Ks 7ec2f7a
fix: add runstrat test and fix errors occured
Nigma-Ks ab1faa4
add func that runs test case in docker
Nigma-Ks 715cb65
feat(run_runstrat): run ExecutionTreeContributedCoverage strategy and…
Nigma-Ks d35f886
remove runstrat test from docker
Nigma-Ks 4186072
feat(frontend form)
Nigma-Ks e97dabd
add backend-frontend connection to upload onnx model
Nigma-Ks 6604dcd
refactor net7 to net8, run runstrat ai strat
Nigma-Ks efad1b8
feat(frontend): form data uploads on submit
Nigma-Ks 85dccff
new data on new submit
Nigma-Ks 6c897f2
feat: function to send results on email
Nigma-Ks 12192f0
feat add building container and loading dataset script
Nigma-Ks b9f3910
add email validation
Nigma-Ks 12f6bfd
feat: comparison with baseline, field experiment name in form
Nigma-Ks 32f0a55
refactor: runstrat and compstrat cmds to template methods
Nigma-Ks 25dc258
fix model onnx uploads with model.onnx name
Nigma-Ks d685996
fix docker cmd
Nigma-Ks 3cf7ef7
refactor: split main logic into separate services
Nigma-Ks d237399
refactor: move image name to build file and make it const
Nigma-Ks f409623
feat: unique directories for each launch
Nigma-Ks f9372a1
load dataset
Nigma-Ks 3d8dd92
remove tmp dirs after submit handling
Nigma-Ks 45c31e6
add parallel execution of pipeline using Celery
Nigma-Ks 3194fe4
add tmp dir to gitignore
Nigma-Ks 55cf00d
docker build no cache to update pysymgym
Nigma-Ks b154e18
refactor Methods class, move build and fetch functions to app_setup
Nigma-Ks 2259ff3
feat add tests
Nigma-Ks a9883ee
add requirements file
Nigma-Ks 7161f36
add test workflow: build project without docker and run some tests
Nigma-Ks 7c39925
fix remove pytest args
Nigma-Ks 7c0cc41
fix: resolve module imports in tests
Nigma-Ks 48181b6
add building pysymgym workflow
Nigma-Ks 7ddae70
fix: resolve backend module path
Nigma-Ks 345af3d
fix misprint
Nigma-Ks 00200e9
run all tests in docker.yml
Nigma-Ks 9eeb486
add .env file for tests
Nigma-Ks bc45f70
refactor change docker test result dir to pytest tmp_path
Nigma-Ks 0ef4977
docs: add detailed README with installation instructions
Nigma-Ks 96159f4
refactor(tests): pytest tmp_path instead of TMP_DIR
Nigma-Ks 8231805
refactor(Methods): change Methods methods names
Nigma-Ks 785f136
remove workflow without docker
Nigma-Ks 5233bbb
fetch_dataset function uploads dataset from docker image, ruff format
Nigma-Ks dc069c4
refactor: join paths
Nigma-Ks File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| name: Build project and run tests | ||
|
|
||
| on: [ push, pull_request ] | ||
|
|
||
| jobs: | ||
| build-and-test: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Python 3.14 | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: '3.14' | ||
| cache: 'pip' | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| python -m pip install --upgrade pip | ||
| pip install -r requirements.txt | ||
|
|
||
| - name: Build dockerfile and update dataset | ||
| run: | | ||
| python -m backend.launch_service.app_setup | ||
|
|
||
| - name: Create .env file for tests | ||
| run: | | ||
| cat > .env << EOF | ||
| EMAIL=test@example.com | ||
| APP_PASSWORD=test_password_123 | ||
| EOF | ||
|
|
||
| - name: Run Python tests | ||
| run: | | ||
| python -m pytest -v |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,71 @@ | ||
| # PySymBench | ||
| Infrastructure for models comparison and evalustion | ||
| Infrastructure for **model comparison and evaluation in symbolic execution workflows**. | ||
|
|
||
| This project is a **local web application** designed to compare symbolic execution results of an uploaded trained model (in `.onnx` format) on a selected dataset with a **baseline symbolic execution approach (non-AI)**. | ||
|
|
||
| The system uses **PySymGym tools** to run symbolic execution on the dataset and evaluate the results. After execution completes, the results are sent to the **email address you provide**. | ||
|
|
||
| # Installation | ||
|
|
||
| The repository contains **both frontend and backend components**, and **both must be launched** for the application to work. | ||
|
|
||
| --- | ||
|
|
||
| ## Email Communication (Gmail) | ||
|
|
||
| To enable email delivery of results, create a `.env` file containing your Gmail credentials: | ||
|
|
||
| ``` | ||
| EMAIL=your_email@gmail.com | ||
| APP_PASSWORD=your_app_password | ||
| ``` | ||
|
|
||
| `EMAIL` — your Gmail address | ||
| `APP_PASSWORD` — your Gmail **App Password** (not your regular account password) | ||
|
|
||
| --- | ||
|
|
||
| ## Backend Setup | ||
|
|
||
| 1. Install **Python 3.14** and **Docker**, then install the project dependencies: | ||
|
|
||
| ``` | ||
| pip install -r requirements.txt | ||
| ``` | ||
|
|
||
| 2. Run the application setup script (this builds a Docker container with the **PySymGym repository** and downloads the required dataset): | ||
|
|
||
| ``` | ||
| python -m backend.launch_service.app_setup | ||
| ``` | ||
|
|
||
| 3. Start the **Celery broker (Redis)**: | ||
|
|
||
| ``` | ||
| docker run --name redis-for-celery -p 6379:6379 -d redis | ||
| ``` | ||
|
|
||
| 4. Start the **Celery worker** and the **application server**: | ||
|
|
||
| ``` | ||
| celery -A backend.utils.task worker --loglevel=info && uvicorn backend.main:app | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Frontend Setup | ||
|
|
||
| 1. Install **Node.js** with **npm**. | ||
|
|
||
| 2. Install frontend dependencies: | ||
|
|
||
| ``` | ||
| cd frontend | ||
| npm install | ||
| ``` | ||
|
|
||
| 3. Start the frontend development server: | ||
|
|
||
| ``` | ||
| npm run build | ||
| ``` |
Empty file.
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import os | ||
|
|
||
|
|
||
| def get_tmp_thread_files(uid): | ||
| return [get_thread_filepath(uid, UPLOAD_DIR), get_thread_filepath(uid, RESULTS_DIR)] | ||
|
|
||
|
|
||
| def get_thread_filepath(uid, filepath): | ||
| base_prefix = TMP_FILE_DIR + "/" | ||
| new_prefix = f"{TMP_FILE_DIR}/{uid}" | ||
| return filepath.replace(base_prefix, new_prefix) | ||
|
|
||
|
|
||
| DOCKER_DIR = os.path.join(os.getcwd(), "docker") | ||
| BASE_DIR = os.path.join(os.getcwd(), "backend") | ||
| TMP_FILE_DIR = os.path.join(BASE_DIR, "tmp") | ||
|
|
||
| RESOURCES_DIR = os.path.join(BASE_DIR, "resources") | ||
| UPLOAD_DIR = os.path.join(TMP_FILE_DIR, "uploads") | ||
| RESULTS_DIR = os.path.join(TMP_FILE_DIR, "results") | ||
|
|
||
| DATASET_FILE = os.path.join(RESOURCES_DIR, "dataset.json") | ||
| LAUNCH_INFO_FILE = os.path.join(UPLOAD_DIR, "launch_info.csv") | ||
| MODEL_ONNX_FILE = os.path.join(UPLOAD_DIR, "model.onnx") | ||
| METHODS_TS_FILE = os.path.join( | ||
| BASE_DIR, "../frontend/src/components/components/Methods.ts" | ||
| ) | ||
| COMPSTRAT_RESULTS_DIR = os.path.join(RESULTS_DIR, "compstrat_results") | ||
| ARTIFACTS_AI_CSV_FILE = os.path.join(RESULTS_DIR, "artifacts_run_ai/AI.csv") | ||
| ARTIFACTS_BASELINE_CSV_FILE = os.path.join( | ||
| RESULTS_DIR, "artifacts_run_baseline/ExecutionTreeContributedCoverage.csv" | ||
| ) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import pytest | ||
|
|
||
| from backend.config.paths import ( | ||
| get_tmp_thread_files, | ||
| RESULTS_DIR, | ||
| UPLOAD_DIR, | ||
| get_thread_filepath, | ||
| TMP_FILE_DIR, | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "uid, filepath, expected", | ||
| [ | ||
| ("", RESULTS_DIR, RESULTS_DIR), | ||
| ("123", UPLOAD_DIR, TMP_FILE_DIR + "/123uploads"), | ||
| ], | ||
| ) | ||
| def test_get_thread_filepath(uid, filepath, expected): | ||
| assert get_thread_filepath(uid, filepath) == expected | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "uid, expected", | ||
| [ | ||
| ("", [UPLOAD_DIR, RESULTS_DIR]), | ||
| ("123", [TMP_FILE_DIR + "/123uploads", TMP_FILE_DIR + "/123results"]), | ||
| ], | ||
| ) | ||
| def test_get_created_tmp_files(uid, expected): | ||
| assert get_tmp_thread_files(uid) == expected |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import csv | ||
|
|
||
|
|
||
| def write_launch_info_to_csv( | ||
| *, | ||
| parsed_methods: list[str], | ||
| output_file: str, | ||
| ) -> None: | ||
| with open(output_file, "w") as csvfile: | ||
| writer = csv.writer(csvfile) | ||
| writer.writerow(["dll", "method"]) | ||
|
|
||
| for item in parsed_methods: | ||
| if "," in item: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When is there no comma in the |
||
| dll, method = item.split(",", 1) | ||
| writer.writerow([dll, method]) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import os | ||
| import shutil | ||
| from fastapi import UploadFile | ||
|
|
||
|
|
||
| def save_upload_file(file: UploadFile, dest_filepath: str) -> None: | ||
| os.makedirs(os.path.dirname(dest_filepath), exist_ok=True) | ||
| with open(dest_filepath, "wb") as f: | ||
| while chunk := file.file.read(1024 * 1024): | ||
| f.write(chunk) | ||
|
|
||
|
|
||
| def reset_dirs(paths: list) -> None: | ||
| for path in paths: | ||
| if os.path.exists(path): | ||
| shutil.rmtree(path) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| import pytest | ||
| import os | ||
| import csv | ||
|
|
||
| from backend.config.paths import TMP_FILE_DIR | ||
| from backend.file_utils.csv_methods_writer import write_launch_info_to_csv | ||
| from backend.file_utils.files import reset_dirs, save_upload_file | ||
| from unittest.mock import Mock | ||
| from fastapi import UploadFile | ||
| from io import BytesIO | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "filepaths", | ||
| [ | ||
| ([TMP_FILE_DIR + "/test"]), | ||
| ([TMP_FILE_DIR + "/test1", TMP_FILE_DIR + "/test2"]), | ||
| ], | ||
| ) | ||
| def test_removing_tmp_files(filepaths): | ||
| for path in filepaths: | ||
| os.makedirs(path) | ||
| reset_dirs(filepaths) | ||
| for path in filepaths: | ||
| assert not os.path.exists(path) | ||
|
|
||
|
|
||
| def test_save_upload_file(tmp_path): | ||
| test_content = b"Hello, World!" * 1000 | ||
| dest_path = tmp_path / "test.txt" | ||
|
|
||
| mock_file = BytesIO(test_content) | ||
| upload_file = Mock(spec=UploadFile) | ||
| upload_file.file = mock_file | ||
|
|
||
| save_upload_file(upload_file, str(dest_path)) | ||
|
|
||
| assert dest_path.exists() | ||
| with open(dest_path, "rb") as f: | ||
| saved_content = f.read() | ||
|
|
||
| assert saved_content == test_content | ||
|
|
||
|
|
||
| def test_write_launch_info_to_csv(tmp_path): | ||
| output_file = tmp_path / "launch_info.csv" | ||
|
|
||
| parsed_methods = [ | ||
| "ManuallyCollected.dll,BinSearchMain", | ||
| "ManuallyCollected.dll,BellmanFord", | ||
| "ManuallyCollected.dll,BinaryMaze1BFS", | ||
| ] | ||
|
|
||
| write_launch_info_to_csv( | ||
| parsed_methods=parsed_methods, output_file=str(output_file) | ||
| ) | ||
|
|
||
| assert output_file.exists() | ||
|
|
||
| with open(output_file, "r") as f: | ||
| reader = csv.reader(f) | ||
| rows = list(reader) | ||
|
|
||
| assert rows[0] == ["dll", "method"] | ||
|
|
||
| expected_data = [ | ||
| ["ManuallyCollected.dll", "BinSearchMain"], | ||
| ["ManuallyCollected.dll", "BellmanFord"], | ||
| ["ManuallyCollected.dll", "BinaryMaze1BFS"], | ||
| ] | ||
|
|
||
| assert rows[1:] == expected_data |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| import os | ||
| import subprocess | ||
| from backend.config.paths import ( | ||
| RESOURCES_DIR, | ||
| DATASET_FILE, | ||
| DOCKER_DIR, | ||
| METHODS_TS_FILE, | ||
| ) | ||
| from backend.utils.methods_handler import Methods | ||
|
|
||
| IMAGE_NAME = "pysymgym-test" | ||
|
|
||
|
|
||
| def fetch_dataset(data_upload_file): | ||
| container_name = "temp-fetch-dataset" | ||
|
|
||
| try: | ||
| subprocess.run( | ||
| ["docker", "create", "--name", container_name, IMAGE_NAME], | ||
| check=True, | ||
| capture_output=True, | ||
| ) | ||
|
|
||
| subprocess.run( | ||
| [ | ||
| "docker", | ||
| "cp", | ||
| f"{container_name}:/workspace/PySymGym/maps/DotNet/Maps/dataset.json", | ||
| data_upload_file, | ||
| ], | ||
| check=True, | ||
| ) | ||
|
|
||
| print(f"Dataset copied to {data_upload_file}") | ||
| return data_upload_file | ||
|
|
||
| finally: | ||
| subprocess.run(["docker", "rm", container_name], capture_output=True) | ||
|
|
||
|
|
||
| def build_container(): | ||
| print(f"Building Docker image '{IMAGE_NAME}'...") | ||
| subprocess.run( | ||
| ["docker", "build", "--no-cache", "-t", IMAGE_NAME, DOCKER_DIR], check=True | ||
| ) | ||
| print("Docker build completed.\n") | ||
|
|
||
| os.makedirs(RESOURCES_DIR, exist_ok=True) | ||
|
|
||
|
|
||
| def update_frontend_selection_options(dataset_file, selection_options_file): | ||
| print("Updating frontend selection options...") | ||
| selection_tree = Methods.build_selection_tree_from_dataset(dataset_file) | ||
| Methods.save_selection_to_frontend_file(selection_tree, selection_options_file) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| build_container() | ||
| fetch_dataset(DATASET_FILE) | ||
| update_frontend_selection_options(DATASET_FILE, METHODS_TS_FILE) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use
os.sephere.