{
    "cells": [
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "# Basic Python Flow"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "from instantgrade.utils.io_utils import generate_student_notebook\n",
                "\n",
                "generate_student_notebook(\n",
                "    instructor_path=\"./sample_solutions.ipynb\",\n",
                "    output_path=\"./submissions/student_notebook.ipynb\"\n",
                ")"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 1,
            "metadata": {},
            "outputs": [
                {
                    "name": "stderr",
                    "output_type": "stream",
                    "text": [
                        "Starting evaluation pipeline...\n",
                        "Loading instructor solution...\n",
                        "Loaded 11 questions.\n",
                        "Discovered 68 submissions to grade.\n",
                        "Starting Docker-based evaluation pipeline...\n",
                        "Could not start persistent Docker container; continuing with per-student docker runs\n",
                        "[1/68] Grading: Anushri-2423509-PracticeTest.ipynb\n",
                        "[Docker] Starting grading for Anushri-2423509-PracticeTest.ipynb\n",
                        "[Anushri-2423509-PracticeTest.ipynb][docker] Traceback (most recent call last):\n",
                        "[Anushri-2423509-PracticeTest.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Anushri-2423509-PracticeTest.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Anushri-2423509-PracticeTest.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Anushri-2423509-PracticeTest.ipynb.\n",
                        "[2/68] Grading: Aryan Chhabra.ipynb\n",
                        "[Docker] Starting grading for Aryan Chhabra.ipynb\n",
                        "[Aryan Chhabra.ipynb][docker] Traceback (most recent call last):\n",
                        "[Aryan Chhabra.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Aryan Chhabra.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Aryan Chhabra.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Aryan Chhabra.ipynb.\n",
                        "[3/68] Grading: Kabeer.ipynb\n",
                        "[Docker] Starting grading for Kabeer.ipynb\n",
                        "[Kabeer.ipynb][docker] Traceback (most recent call last):\n",
                        "[Kabeer.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Kabeer.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Kabeer.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Kabeer.ipynb.\n",
                        "[4/68] Grading: Lohitakksh Mukherji (2423531) _ Practice Test.ipynb\n",
                        "[Docker] Starting grading for Lohitakksh Mukherji (2423531) _ Practice Test.ipynb\n",
                        "[Lohitakksh Mukherji (2423531) _ Practice Test.ipynb][docker] Traceback (most recent call last):\n",
                        "[Lohitakksh Mukherji (2423531) _ Practice Test.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Lohitakksh Mukherji (2423531) _ Practice Test.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Lohitakksh Mukherji (2423531) _ Practice Test.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Lohitakksh Mukherji (2423531) _ Practice Test.ipynb.\n",
                        "[5/68] Grading: Lohitakksh-2423531-PracticeTest .ipynb\n",
                        "[Docker] Starting grading for Lohitakksh-2423531-PracticeTest .ipynb\n",
                        "[Lohitakksh-2423531-PracticeTest .ipynb][docker] Traceback (most recent call last):\n",
                        "[Lohitakksh-2423531-PracticeTest .ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Lohitakksh-2423531-PracticeTest .ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Lohitakksh-2423531-PracticeTest .ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Lohitakksh-2423531-PracticeTest .ipynb.\n",
                        "[6/68] Grading: Mock test.ipynb\n",
                        "[Docker] Starting grading for Mock test.ipynb\n",
                        "[Mock test.ipynb][docker] Traceback (most recent call last):\n",
                        "[Mock test.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Mock test.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Mock test.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Mock test.ipynb.\n",
                        "[7/68] Grading: Mrunmayi Rao_2423536_Class Participation.ipynb\n",
                        "[Docker] Starting grading for Mrunmayi Rao_2423536_Class Participation.ipynb\n",
                        "[Mrunmayi Rao_2423536_Class Participation.ipynb][docker] Traceback (most recent call last):\n",
                        "[Mrunmayi Rao_2423536_Class Participation.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Mrunmayi Rao_2423536_Class Participation.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Mrunmayi Rao_2423536_Class Participation.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Mrunmayi Rao_2423536_Class Participation.ipynb.\n",
                        "[8/68] Grading: Mukund khetan_2423537.ipynb\n",
                        "[Docker] Starting grading for Mukund khetan_2423537.ipynb\n",
                        "[Mukund khetan_2423537.ipynb][docker] Traceback (most recent call last):\n",
                        "[Mukund khetan_2423537.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Mukund khetan_2423537.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Mukund khetan_2423537.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Mukund khetan_2423537.ipynb.\n",
                        "[9/68] Grading: Nikhil 2423539.ipynb\n",
                        "[Docker] Starting grading for Nikhil 2423539.ipynb\n",
                        "[Nikhil 2423539.ipynb][docker] Traceback (most recent call last):\n",
                        "[Nikhil 2423539.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Nikhil 2423539.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Nikhil 2423539.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Nikhil 2423539.ipynb.\n",
                        "[10/68] Grading: PRACTICE EXAM - PYTHON.ipynb\n",
                        "[Docker] Starting grading for PRACTICE EXAM - PYTHON.ipynb\n",
                        "[PRACTICE EXAM - PYTHON.ipynb][docker] Traceback (most recent call last):\n",
                        "[PRACTICE EXAM - PYTHON.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[PRACTICE EXAM - PYTHON.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[PRACTICE EXAM - PYTHON.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for PRACTICE EXAM - PYTHON.ipynb.\n",
                        "[11/68] Grading: PYTHON MOCK TEST-2423524.ipynb\n",
                        "[Docker] Starting grading for PYTHON MOCK TEST-2423524.ipynb\n",
                        "[PYTHON MOCK TEST-2423524.ipynb][docker] Traceback (most recent call last):\n",
                        "[PYTHON MOCK TEST-2423524.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[PYTHON MOCK TEST-2423524.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[PYTHON MOCK TEST-2423524.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for PYTHON MOCK TEST-2423524.ipynb.\n",
                        "[12/68] Grading: PratikshaPrabhu_2423544 .ipynb\n",
                        "[Docker] Starting grading for PratikshaPrabhu_2423544 .ipynb\n",
                        "[PratikshaPrabhu_2423544 .ipynb][docker] Traceback (most recent call last):\n",
                        "[PratikshaPrabhu_2423544 .ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[PratikshaPrabhu_2423544 .ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[PratikshaPrabhu_2423544 .ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for PratikshaPrabhu_2423544 .ipynb.\n",
                        "[13/68] Grading: Python Practice Test 1 .ipynb\n",
                        "[Docker] Starting grading for Python Practice Test 1 .ipynb\n",
                        "[Python Practice Test 1 .ipynb][docker] Traceback (most recent call last):\n",
                        "[Python Practice Test 1 .ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Python Practice Test 1 .ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Python Practice Test 1 .ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Python Practice Test 1 .ipynb.\n",
                        "[14/68] Grading: Samanvitha P 2423552.ipynb\n",
                        "[Docker] Starting grading for Samanvitha P 2423552.ipynb\n",
                        "[Samanvitha P 2423552.ipynb][docker] Traceback (most recent call last):\n",
                        "[Samanvitha P 2423552.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Samanvitha P 2423552.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Samanvitha P 2423552.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Samanvitha P 2423552.ipynb.\n",
                        "[15/68] Grading: Trishikha Vijay 2423570.ipynb\n",
                        "[Docker] Starting grading for Trishikha Vijay 2423570.ipynb\n",
                        "[Trishikha Vijay 2423570.ipynb][docker] Traceback (most recent call last):\n",
                        "[Trishikha Vijay 2423570.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Trishikha Vijay 2423570.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Trishikha Vijay 2423570.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Trishikha Vijay 2423570.ipynb.\n",
                        "[16/68] Grading: Vehhaan_2423572.ipynb\n",
                        "[Docker] Starting grading for Vehhaan_2423572.ipynb\n",
                        "[Vehhaan_2423572.ipynb][docker] Traceback (most recent call last):\n",
                        "[Vehhaan_2423572.ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Vehhaan_2423572.ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Vehhaan_2423572.ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Vehhaan_2423572.ipynb.\n",
                        "[17/68] Grading: Vivan 23(1).ipynb\n",
                        "[Docker] Starting grading for Vivan 23(1).ipynb\n",
                        "[Vivan 23(1).ipynb][docker] Traceback (most recent call last):\n",
                        "[Vivan 23(1).ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Vivan 23(1).ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Vivan 23(1).ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Vivan 23(1).ipynb.\n",
                        "[18/68] Grading: Yashvita Yenuganti 2423574.ipynb\n",
                        "[Docker] Starting grading for Yashvita Yenuganti 2423574.ipynb\n",
                        "/Volumes/MacSSD/Areas/Github_Repositories/evaluator/src/instantgrade/evaluators/python/execution_service_docker.py:255: SyntaxWarning: invalid escape sequence '\\$'\n",
                        "  # 3. Write and build Dockerfile\n"
                    ]
                },
                {
                    "ename": "KeyboardInterrupt",
                    "evalue": "",
                    "output_type": "error",
                    "traceback": [
                        "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
                        "\u001b[31mKeyboardInterrupt\u001b[39m                         Traceback (most recent call last)",
                        "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 26\u001b[39m\n\u001b[32m     17\u001b[39m new_eval = NewEvaluator(\n\u001b[32m     18\u001b[39m     solution_file_path=solution,\n\u001b[32m     19\u001b[39m     submission_folder_path=submissions,\n\u001b[32m   (...)\u001b[39m\u001b[32m     22\u001b[39m     log_level=\u001b[33m'\u001b[39m\u001b[33minfo\u001b[39m\u001b[33m'\u001b[39m,\n\u001b[32m     23\u001b[39m )\n\u001b[32m     25\u001b[39m \u001b[38;5;66;03m# Run evaluation\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m26\u001b[39m new_report = \u001b[43mnew_eval\u001b[49m\u001b[43m.\u001b[49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m     28\u001b[39m \u001b[38;5;66;03m# Generate HTML report (safe with fallback)\u001b[39;00m\n\u001b[32m     29\u001b[39m report_path = report_dir / \u001b[33m\"\u001b[39m\u001b[33mevaluation_report_instantgrade_docker_all.html\u001b[39m\u001b[33m\"\u001b[39m\n",
                        "\u001b[36mFile \u001b[39m\u001b[32m/Volumes/MacSSD/Areas/Github_Repositories/evaluator/src/instantgrade/evaluators/python/evaluator.py:115\u001b[39m, in \u001b[36mEvaluator.run\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m    112\u001b[39m \u001b[38;5;28mself\u001b[39m.logger.info(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDiscovered \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlen\u001b[39m(all_submissions)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m submissions to grade.\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m    114\u001b[39m \u001b[38;5;66;03m# 3. Execute grading\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m115\u001b[39m executed = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mexecute_all\u001b[49m\u001b[43m(\u001b[49m\u001b[43mall_submissions\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    116\u001b[39m \u001b[38;5;28mself\u001b[39m.executed = executed\n\u001b[32m    117\u001b[39m \u001b[38;5;28mself\u001b[39m.logger.info(\u001b[33m\"\u001b[39m\u001b[33mExecution phase completed successfully.\u001b[39m\u001b[33m\"\u001b[39m)\n",
                        "\u001b[36mFile \u001b[39m\u001b[32m/Volumes/MacSSD/Areas/Github_Repositories/evaluator/src/instantgrade/evaluators/python/evaluator.py:160\u001b[39m, in \u001b[36mEvaluator.execute_all\u001b[39m\u001b[34m(self, submission_paths)\u001b[39m\n\u001b[32m    158\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m    159\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m.use_docker:\n\u001b[32m--> \u001b[39m\u001b[32m160\u001b[39m         result = \u001b[43mexecution_service\u001b[49m\u001b[43m.\u001b[49m\u001b[43mexecute_student\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43msolution_path\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msub\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    161\u001b[39m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m    162\u001b[39m         result = \u001b[38;5;28mself\u001b[39m._grade_local_student(execution_service, sub)\n",
                        "\u001b[36mFile \u001b[39m\u001b[32m/Volumes/MacSSD/Areas/Github_Repositories/evaluator/src/instantgrade/evaluators/python/execution_service_docker.py:117\u001b[39m, in \u001b[36mExecutionServiceDocker.execute_student\u001b[39m\u001b[34m(self, solution_path, submission_path)\u001b[39m\n\u001b[32m    114\u001b[39m     proc.kill()\n\u001b[32m    115\u001b[39m     \u001b[38;5;28;01mbreak\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m117\u001b[39m line = \u001b[43mproc\u001b[49m\u001b[43m.\u001b[49m\u001b[43mstdout\u001b[49m\u001b[43m.\u001b[49m\u001b[43mreadline\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    118\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m line:\n\u001b[32m    119\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m proc.poll() \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
                        "\u001b[31mKeyboardInterrupt\u001b[39m: "
                    ]
                }
            ],
            "source": [
                "import sys, pathlib\n",
                "from pathlib import Path\n",
                "\n",
                "# Setup paths\n",
                "repo = pathlib.Path('.').resolve().parent.parent\n",
                "sys.path.insert(0, str(repo))\n",
                "sys.path.insert(0, str(repo / 'src'))\n",
                "\n",
                "from instantgrade.evaluators.python.evaluator import Evaluator as NewEvaluator\n",
                "\n",
                "solution = Path('./sample_solutions.ipynb')\n",
                "submissions = Path('./InclassPracticeExam2')\n",
                "log_dir = Path('./logs_instantgrade_test')\n",
                "report_dir = Path('./reports')\n",
                "report_dir.mkdir(parents=True, exist_ok=True)\n",
                "\n",
                "new_eval = NewEvaluator(\n",
                "    solution_file_path=solution,\n",
                "    submission_folder_path=submissions,\n",
                "    use_docker=True,\n",
                "    log_path=log_dir,\n",
                "    log_level='info',\n",
                ")\n",
                "\n",
                "# Run evaluation\n",
                "new_report = new_eval.run()\n",
                "\n",
                "# Generate HTML report (safe with fallback)\n",
                "report_path = report_dir / \"evaluation_report_instantgrade_docker_all.html\"\n",
                "try:\n",
                "    output = new_eval.to_html(report_path)\n",
                "    print(f\"\\n✓ HTML report written to: {output}\")\n",
                "except KeyError as e:\n",
                "    print(f\"\\n⚠️ ReportingService.to_html failed with missing column: {e}\")\n",
                "    # Fallback: write raw results CSV so you can inspect the data\n",
                "    csv_path = report_dir / \"evaluation_report_instantgrade_docker_fallback.csv\"\n",
                "    try:\n",
                "        new_eval.report.to_csv(csv_path)\n",
                "        print(f\"✓ Fallback CSV report written to: {csv_path}\")\n",
                "        output = str(csv_path)\n",
                "    except Exception as e2:\n",
                "        print(\"✗ Fallback CSV also failed:\", e2)\n",
                "        raise\n",
                "\n",
                "# Show summary\n",
                "print(f\"\\n{'='*60}\")\n",
                "print(f\"EVALUATION SUMMARY\")\n",
                "print(f\"{'='*60}\")\n",
                "# robustly compute total submissions (handles dict/list/other)\n",
                "try:\n",
                "    if hasattr(new_eval, 'executed'):\n",
                "        if isinstance(new_eval.executed, dict):\n",
                "            total = len(new_eval.executed)\n",
                "        elif isinstance(new_eval.executed, list):\n",
                "            total = len(new_eval.executed)\n",
                "        else:\n",
                "            try:\n",
                "                total = len(new_eval.executed)\n",
                "            except Exception:\n",
                "                total = 0\n",
                "    else:\n",
                "        total = 0\n",
                "except Exception:\n",
                "    total = 0\n",
                "\n",
                "print(f\"Total submissions evaluated: {total}\")\n",
                "print(f\"Report saved to: {output}\")\n",
                "print(f\"{'='*60}\")"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 2,
            "metadata": {},
            "outputs": [
                {
                    "name": "stderr",
                    "output_type": "stream",
                    "text": [
                        "Starting evaluation pipeline...\n",
                        "Loading instructor solution...\n",
                        "Loaded 11 questions.\n",
                        "Discovered 1 submissions to grade.\n",
                        "Starting Docker-based evaluation pipeline...\n",
                        "Could not start persistent Docker container; continuing with per-student docker runs\n",
                        "[1/1] Grading: Lohitakksh-2423531-PracticeTest .ipynb\n",
                        "[Docker] Starting grading for Lohitakksh-2423531-PracticeTest .ipynb\n",
                        "[Lohitakksh-2423531-PracticeTest .ipynb][docker] Traceback (most recent call last):\n",
                        "[Lohitakksh-2423531-PracticeTest .ipynb][docker]   File \"/workspace/grader.py\", line 46, in <module>\n",
                        "[Lohitakksh-2423531-PracticeTest .ipynb][docker]     from instantgrade.evaluators.python.ingestion.solution_ingestion import SolutionIngestion\n",
                        "[Lohitakksh-2423531-PracticeTest .ipynb][docker] ModuleNotFoundError: No module named 'instantgrade.evaluators'\n",
                        "[grader] results.json not found in /workspace for Lohitakksh-2423531-PracticeTest .ipynb.\n",
                        "Execution phase completed successfully.\n",
                        "[Reporting] Processed 0 result rows.\n",
                        "Report generation complete.\n",
                        "Total evaluation completed in 0.67s.\n"
                    ]
                },
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "\n",
                        "⚠️ ReportingService.to_html failed with missing column: 'file'\n",
                        "✗ Fallback CSV also failed: 'InstantGrader' object has no attribute 'report'\n"
                    ]
                },
                {
                    "ename": "AttributeError",
                    "evalue": "'InstantGrader' object has no attribute 'report'",
                    "output_type": "error",
                    "traceback": [
                        "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
                        "\u001b[31mKeyError\u001b[39m                                  Traceback (most recent call last)",
                        "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[2]\u001b[39m\u001b[32m, line 31\u001b[39m\n\u001b[32m     30\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m---> \u001b[39m\u001b[32m31\u001b[39m     output = \u001b[43mnew_eval\u001b[49m\u001b[43m.\u001b[49m\u001b[43mto_html\u001b[49m\u001b[43m(\u001b[49m\u001b[43mreport_path\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m     32\u001b[39m     \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m✓ HTML report written to: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00moutput\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n",
                        "\u001b[36mFile \u001b[39m\u001b[32m/Volumes/MacSSD/Areas/Github_Repositories/evaluator/src/instantgrade/core/orchestrator.py:125\u001b[39m, in \u001b[36mInstantGrader.to_html\u001b[39m\u001b[34m(self, path)\u001b[39m\n\u001b[32m    124\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(\u001b[38;5;28mself\u001b[39m._evaluator, \u001b[33m\"\u001b[39m\u001b[33mto_html\u001b[39m\u001b[33m\"\u001b[39m):\n\u001b[32m--> \u001b[39m\u001b[32m125\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_evaluator\u001b[49m\u001b[43m.\u001b[49m\u001b[43mto_html\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpath\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    126\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[33m\"\u001b[39m\u001b[33mSelected evaluator does not implement to_html()\u001b[39m\u001b[33m\"\u001b[39m)\n",
                        "\u001b[36mFile \u001b[39m\u001b[32m/Volumes/MacSSD/Areas/Github_Repositories/evaluator/src/instantgrade/evaluators/python/evaluator.py:245\u001b[39m, in \u001b[36mEvaluator.to_html\u001b[39m\u001b[34m(self, path)\u001b[39m\n\u001b[32m    244\u001b[39m path = Path(path)\n\u001b[32m--> \u001b[39m\u001b[32m245\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mreport\u001b[49m\u001b[43m.\u001b[49m\u001b[43mto_html\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpath\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    246\u001b[39m \u001b[38;5;28mself\u001b[39m.logger.info(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mHTML report generated at: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mpath\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n",
                        "\u001b[36mFile \u001b[39m\u001b[32m/Volumes/MacSSD/Areas/Github_Repositories/evaluator/src/instantgrade/reporting/reporting_service.py:242\u001b[39m, in \u001b[36mReportingService.to_html\u001b[39m\u001b[34m(self, path)\u001b[39m\n\u001b[32m    241\u001b[39m df_summary = df[df[\u001b[33m\"\u001b[39m\u001b[33massertion\u001b[39m\u001b[33m\"\u001b[39m] != \u001b[33m\"\u001b[39m\u001b[33m[missing student identity]\u001b[39m\u001b[33m\"\u001b[39m].copy()\n\u001b[32m--> \u001b[39m\u001b[32m242\u001b[39m grouped = \u001b[43mdf\u001b[49m\u001b[43m.\u001b[49m\u001b[43mgroupby\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mfile\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mstudent\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mroll_number\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msort\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[32m    244\u001b[39m \u001b[38;5;66;03m# Build a student-level summary table (used for the Summary modal)\u001b[39;00m\n\u001b[32m    245\u001b[39m \u001b[38;5;66;03m# If Best-N enabled -> rely on self.student_best_df (Highest Best-N)\u001b[39;00m\n\u001b[32m    246\u001b[39m \u001b[38;5;66;03m# If Best-N disabled -> compute raw total marks per student across attempts\u001b[39;00m\n",
                        "\u001b[36mFile \u001b[39m\u001b[32m/Volumes/MacSSD/Areas/Github_Repositories/evaluator/.venv/lib/python3.13/site-packages/pandas/core/frame.py:9210\u001b[39m, in \u001b[36mDataFrame.groupby\u001b[39m\u001b[34m(self, by, axis, level, as_index, sort, group_keys, observed, dropna)\u001b[39m\n\u001b[32m   9208\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[33m\"\u001b[39m\u001b[33mYou have to supply one of \u001b[39m\u001b[33m'\u001b[39m\u001b[33mby\u001b[39m\u001b[33m'\u001b[39m\u001b[33m and \u001b[39m\u001b[33m'\u001b[39m\u001b[33mlevel\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m-> \u001b[39m\u001b[32m9210\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mDataFrameGroupBy\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m   9211\u001b[39m \u001b[43m    \u001b[49m\u001b[43mobj\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[32m   9212\u001b[39m \u001b[43m    \u001b[49m\u001b[43mkeys\u001b[49m\u001b[43m=\u001b[49m\u001b[43mby\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   9213\u001b[39m \u001b[43m    \u001b[49m\u001b[43maxis\u001b[49m\u001b[43m=\u001b[49m\u001b[43maxis\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   9214\u001b[39m \u001b[43m    \u001b[49m\u001b[43mlevel\u001b[49m\u001b[43m=\u001b[49m\u001b[43mlevel\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   9215\u001b[39m \u001b[43m    \u001b[49m\u001b[43mas_index\u001b[49m\u001b[43m=\u001b[49m\u001b[43mas_index\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   9216\u001b[39m \u001b[43m    \u001b[49m\u001b[43msort\u001b[49m\u001b[43m=\u001b[49m\u001b[43msort\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   9217\u001b[39m \u001b[43m    \u001b[49m\u001b[43mgroup_keys\u001b[49m\u001b[43m=\u001b[49m\u001b[43mgroup_keys\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   9218\u001b[39m \u001b[43m    \u001b[49m\u001b[43mobserved\u001b[49m\u001b[43m=\u001b[49m\u001b[43mobserved\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   9219\u001b[39m \u001b[43m    \u001b[49m\u001b[43mdropna\u001b[49m\u001b[43m=\u001b[49m\u001b[43mdropna\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   9220\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
                        "\u001b[36mFile \u001b[39m\u001b[32m/Volumes/MacSSD/Areas/Github_Repositories/evaluator/.venv/lib/python3.13/site-packages/pandas/core/groupby/groupby.py:1331\u001b[39m, in \u001b[36mGroupBy.__init__\u001b[39m\u001b[34m(self, obj, keys, axis, level, grouper, exclusions, selection, as_index, sort, group_keys, observed, dropna)\u001b[39m\n\u001b[32m   1330\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m grouper \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m1331\u001b[39m     grouper, exclusions, obj = \u001b[43mget_grouper\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m   1332\u001b[39m \u001b[43m        \u001b[49m\u001b[43mobj\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   1333\u001b[39m \u001b[43m        \u001b[49m\u001b[43mkeys\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   1334\u001b[39m \u001b[43m        \u001b[49m\u001b[43maxis\u001b[49m\u001b[43m=\u001b[49m\u001b[43maxis\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   1335\u001b[39m \u001b[43m        \u001b[49m\u001b[43mlevel\u001b[49m\u001b[43m=\u001b[49m\u001b[43mlevel\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   1336\u001b[39m \u001b[43m        \u001b[49m\u001b[43msort\u001b[49m\u001b[43m=\u001b[49m\u001b[43msort\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   1337\u001b[39m \u001b[43m        \u001b[49m\u001b[43mobserved\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mobserved\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mis\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mlib\u001b[49m\u001b[43m.\u001b[49m\u001b[43mno_default\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mobserved\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   1338\u001b[39m \u001b[43m        \u001b[49m\u001b[43mdropna\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mdropna\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   1339\u001b[39m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m   1341\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m observed \u001b[38;5;129;01mis\u001b[39;00m lib.no_default:\n",
                        "\u001b[36mFile \u001b[39m\u001b[32m/Volumes/MacSSD/Areas/Github_Repositories/evaluator/.venv/lib/python3.13/site-packages/pandas/core/groupby/grouper.py:1043\u001b[39m, in \u001b[36mget_grouper\u001b[39m\u001b[34m(obj, key, axis, level, sort, observed, validate, dropna)\u001b[39m\n\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m1043\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(gpr)\n\u001b[32m   1044\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(gpr, Grouper) \u001b[38;5;129;01mand\u001b[39;00m gpr.key \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m   1045\u001b[39m     \u001b[38;5;66;03m# Add key to exclusions\u001b[39;00m\n",
                        "\u001b[31mKeyError\u001b[39m: 'file'",
                        "\nDuring handling of the above exception, another exception occurred:\n",
                        "\u001b[31mAttributeError\u001b[39m                            Traceback (most recent call last)",
                        "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[2]\u001b[39m\u001b[32m, line 38\u001b[39m\n\u001b[32m     36\u001b[39m csv_path = report_dir / \u001b[33m\"\u001b[39m\u001b[33mevaluation_report_instantgrade_docker_fallback.csv\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m     37\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m---> \u001b[39m\u001b[32m38\u001b[39m     \u001b[43mnew_eval\u001b[49m\u001b[43m.\u001b[49m\u001b[43mreport\u001b[49m.to_csv(csv_path)\n\u001b[32m     39\u001b[39m     \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33m✓ Fallback CSV report written to: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcsv_path\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m     40\u001b[39m     output = \u001b[38;5;28mstr\u001b[39m(csv_path)\n",
                        "\u001b[31mAttributeError\u001b[39m: 'InstantGrader' object has no attribute 'report'"
                    ]
                }
            ],
            "source": [
                "import sys, pathlib\n",
                "from pathlib import Path\n",
                "\n",
                "# Setup paths\n",
                "repo = pathlib.Path('.').resolve().parent.parent\n",
                "sys.path.insert(0, str(repo))\n",
                "sys.path.insert(0, str(repo / 'src'))\n",
                "\n",
                "from instantgrade import InstantGrader\n",
                "\n",
                "solution = Path('./sample_solutions.ipynb')\n",
                "submissions = Path('./InclassPracticeExam2/Lohitakksh-2423531-PracticeTest .ipynb')\n",
                "log_dir = Path('./logs_instantgrade_test')\n",
                "report_dir = Path('./reports')\n",
                "report_dir.mkdir(parents=True, exist_ok=True)\n",
                "\n",
                "new_eval = InstantGrader(\n",
                "    solution_file_path=solution,\n",
                "    submission_folder_path=submissions,\n",
                "    use_docker=True,\n",
                "    log_path=log_dir,\n",
                "    log_level='debug',\n",
                ")\n",
                "\n",
                "# Run evaluation\n",
                "new_report = new_eval.run()\n",
                "\n",
                "# Generate HTML report (safe with fallback)\n",
                "report_path = report_dir / \"evaluation_report_instantgrade_docker1.html\"\n",
                "try:\n",
                "    output = new_eval.to_html(report_path)\n",
                "    print(f\"\\n✓ HTML report written to: {output}\")\n",
                "except KeyError as e:\n",
                "    print(f\"\\n⚠️ ReportingService.to_html failed with missing column: {e}\")\n",
                "    # Fallback: write raw results CSV so you can inspect the data\n",
                "    csv_path = report_dir / \"evaluation_report_instantgrade_docker_fallback.csv\"\n",
                "    try:\n",
                "        new_eval.report.to_csv(csv_path)\n",
                "        print(f\"✓ Fallback CSV report written to: {csv_path}\")\n",
                "        output = str(csv_path)\n",
                "    except Exception as e2:\n",
                "        print(\"✗ Fallback CSV also failed:\", e2)\n",
                "        raise\n",
                "\n",
                "# Show summary\n",
                "print(f\"\\n{'='*60}\")\n",
                "print(f\"EVALUATION SUMMARY\")\n",
                "print(f\"{'='*60}\")\n",
                "# robustly compute total submissions (handles dict/list/other)\n",
                "try:\n",
                "    if hasattr(new_eval, 'executed'):\n",
                "        if isinstance(new_eval.executed, dict):\n",
                "            total = len(new_eval.executed)\n",
                "        elif isinstance(new_eval.executed, list):\n",
                "            total = len(new_eval.executed)\n",
                "        else:\n",
                "            try:\n",
                "                total = len(new_eval.executed)\n",
                "            except Exception:\n",
                "                total = 0\n",
                "    else:\n",
                "        total = 0\n",
                "except Exception:\n",
                "    total = 0\n",
                "\n",
                "print(f\"Total submissions evaluated: {total}\")\n",
                "print(f\"Report saved to: {output}\")\n",
                "print(f\"{'='*60}\")"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 1,
            "metadata": {},
            "outputs": [
                {
                    "name": "stderr",
                    "output_type": "stream",
                    "text": [
                        "Starting evaluation pipeline...\n",
                        "Loading instructor solution...\n",
                        "Loaded 11 questions.\n",
                        "Discovered 1 submissions to grade.\n",
                        "Starting Local evaluation pipeline...\n",
                        "[1/1] Grading: Lohitakksh-2423531-PracticeTest .ipynb\n",
                        "[Local] Grading Lohitakksh-2423531-PracticeTest .ipynb\n",
                        "Execution phase completed successfully.\n",
                        "[Reporting] Processed 24 result rows.\n",
                        "Report generation complete.\n",
                        "Total evaluation completed in 0.67s.\n",
                        "HTML report generated at: reports/evaluation_report_instantgrade_docker1.html\n"
                    ]
                },
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "Anushri\n",
                        "2423509\n",
                        "[1, 2, 3, 4, 5, 6]\n",
                        "[2, 4, 6, 8, 10, 12, 14]\n",
                        "25\n",
                        "Access Denied\n",
                        "Access Granted\n",
                        "12\n",
                        "Even\n",
                        "Odd\n",
                        "55\n",
                        "[1, 4, 9, 16, 25, 36]\n",
                        "2\n",
                        "12.0\n",
                        "\n",
                        "✓ HTML report written to: reports/evaluation_report_instantgrade_docker1.html\n",
                        "\n",
                        "============================================================\n",
                        "EVALUATION SUMMARY\n",
                        "============================================================\n",
                        "Total submissions evaluated: 0\n",
                        "Report saved to: reports/evaluation_report_instantgrade_docker1.html\n",
                        "============================================================\n"
                    ]
                }
            ],
            "source": [
                "import sys, pathlib\n",
                "from pathlib import Path\n",
                "\n",
                "# Setup paths\n",
                "repo = pathlib.Path('.').resolve().parent.parent\n",
                "sys.path.insert(0, str(repo))\n",
                "sys.path.insert(0, str(repo / 'src'))\n",
                "\n",
                "from instantgrade import InstantGrader\n",
                "\n",
                "solution = Path('./sample_solutions.ipynb')\n",
                "submissions = Path('./InclassPracticeExam2/Lohitakksh-2423531-PracticeTest .ipynb')\n",
                "log_dir = Path('./logs_instantgrade_test')\n",
                "report_dir = Path('./reports')\n",
                "report_dir.mkdir(parents=True, exist_ok=True)\n",
                "\n",
                "new_eval = InstantGrader(\n",
                "    solution_file_path=solution,\n",
                "    submission_folder_path=submissions,\n",
                "    use_docker=False,\n",
                "    log_path=log_dir,\n",
                "    log_level='info',\n",
                ")\n",
                "\n",
                "# Run evaluation\n",
                "new_report = new_eval.run()\n",
                "\n",
                "# Generate HTML report (safe with fallback)\n",
                "report_path = report_dir / \"evaluation_report_instantgrade_docker1.html\"\n",
                "try:\n",
                "    output = new_eval.to_html(report_path)\n",
                "    print(f\"\\n✓ HTML report written to: {output}\")\n",
                "except KeyError as e:\n",
                "    print(f\"\\n⚠️ ReportingService.to_html failed with missing column: {e}\")\n",
                "    # Fallback: write raw results CSV so you can inspect the data\n",
                "    csv_path = report_dir / \"evaluation_report_instantgrade_docker_fallback.csv\"\n",
                "    try:\n",
                "        new_eval.report.to_csv(csv_path)\n",
                "        print(f\"✓ Fallback CSV report written to: {csv_path}\")\n",
                "        output = str(csv_path)\n",
                "    except Exception as e2:\n",
                "        print(\"✗ Fallback CSV also failed:\", e2)\n",
                "        raise\n",
                "\n",
                "# Show summary\n",
                "print(f\"\\n{'='*60}\")\n",
                "print(f\"EVALUATION SUMMARY\")\n",
                "print(f\"{'='*60}\")\n",
                "# robustly compute total submissions (handles dict/list/other)\n",
                "try:\n",
                "    if hasattr(new_eval, 'executed'):\n",
                "        if isinstance(new_eval.executed, dict):\n",
                "            total = len(new_eval.executed)\n",
                "        elif isinstance(new_eval.executed, list):\n",
                "            total = len(new_eval.executed)\n",
                "        else:\n",
                "            try:\n",
                "                total = len(new_eval.executed)\n",
                "            except Exception:\n",
                "                total = 0\n",
                "    else:\n",
                "        total = 0\n",
                "except Exception:\n",
                "    total = 0\n",
                "\n",
                "print(f\"Total submissions evaluated: {total}\")\n",
                "print(f\"Report saved to: {output}\")\n",
                "print(f\"{'='*60}\")"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 2,
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "Requirement already satisfied: pytest in /Volumes/MacSSD/Areas/Github_Repositories/evaluator/.venv/lib/python3.13/site-packages (9.0.1)\n",
                        "Requirement already satisfied: iniconfig>=1.0.1 in /Volumes/MacSSD/Areas/Github_Repositories/evaluator/.venv/lib/python3.13/site-packages (from pytest) (2.3.0)\n",
                        "Requirement already satisfied: packaging>=22 in /Volumes/MacSSD/Areas/Github_Repositories/evaluator/.venv/lib/python3.13/site-packages (from pytest) (25.0)\n",
                        "Requirement already satisfied: pluggy<2,>=1.5 in /Volumes/MacSSD/Areas/Github_Repositories/evaluator/.venv/lib/python3.13/site-packages (from pytest) (1.6.0)\n",
                        "Requirement already satisfied: pygments>=2.7.2 in /Volumes/MacSSD/Areas/Github_Repositories/evaluator/.venv/lib/python3.13/site-packages (from pytest) (2.19.2)\n"
                    ]
                }
            ],
            "source": [
                "!pip install pytest"
            ]
        },
        {
            "cell_type": "markdown",
            "metadata": {
                "id": "x2JVLvRAu_lX"
            },
            "source": [
                "# EOF"
            ]
        }
    ],
    "metadata": {
        "colab": {
            "provenance": []
        },
        "kernelspec": {
            "display_name": ".venv (3.13.7)",
            "language": "python",
            "name": "python3"
        },
        "language_info": {
            "codemirror_mode": {
                "name": "ipython",
                "version": 3
            },
            "file_extension": ".py",
            "mimetype": "text/x-python",
            "name": "python",
            "nbconvert_exporter": "python",
            "pygments_lexer": "ipython3",
            "version": "3.13.7"
        }
    },
    "nbformat": 4,
    "nbformat_minor": 0
}
