From e08265c709020186dbbc949c351dd621014be6db Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 18:29:10 -0400 Subject: [PATCH 01/12] Add test dependencies to requirements.txt --- requirements.txt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 27f8f50..4896285 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,19 @@ -SQLAlchemy==2.0.44 +# Self-dependency that allows us to import data models for testing +-e git+https://github.com/Project-CARPI/database-schema.git#egg=carpi_data_model +certifi==2026.2.25 +charset-normalizer==3.4.7 +docker==7.1.0 +idna==3.11 +iniconfig==2.3.0 +mysql-connector-python==9.6.0 +packaging==26.0 +pluggy==1.6.0 +Pygments==2.20.0 +pytest==9.0.3 +python-dotenv==1.2.2 +requests==2.33.1 +SQLAlchemy==2.0.49 +testcontainers==4.14.2 typing_extensions==4.15.0 +urllib3==2.6.3 +wrapt==2.1.2 From 92ab48daaf0af98366219a1440cc2bc34c23a994 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 18:29:21 -0400 Subject: [PATCH 02/12] Create basic test script --- tests/test_models.py | 61 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tests/test_models.py diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..032ea6c --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,61 @@ +import pytest +from sqlalchemy import create_engine +from sqlalchemy.orm import Session +from testcontainers.mysql import MySqlContainer + +from carpi_data_model.models import * + + +@pytest.fixture(scope="session") +def engine(): + """ + Spin up a temporary MySQL Docker container for the whole test session. This + requires Docker to be running on your machine. + """ + with MySqlContainer("mysql:8.0", dialect="mysqlconnector") as mysql: + yield create_engine(mysql.get_connection_url(), echo=False) + + +@pytest.fixture(autouse=True) +def setup_database(engine): + """ + Creates all tables before each test and drops them after to ensure a clean + state for every test. + """ + Base.metadata.create_all(bind=engine) + yield + Base.metadata.drop_all(bind=engine) + + +def test_create_tables(engine): + """ + Test that the SQLAlchemy schema can be translated into DDL and executed + in a Native MySQL database without throwing any mapping or constraint + errors. + """ + assert Subject.__tablename__ in Base.metadata.tables + assert Attribute.__tablename__ in Base.metadata.tables + assert Restriction.__tablename__ in Base.metadata.tables + assert Faculty.__tablename__ in Base.metadata.tables + assert Course.__tablename__ in Base.metadata.tables + assert Course_Attribute.__tablename__ in Base.metadata.tables + assert Course_Relationship.__tablename__ in Base.metadata.tables + assert Course_Restriction.__tablename__ in Base.metadata.tables + assert Course_Offering.__tablename__ in Base.metadata.tables + assert Course_Faculty.__tablename__ in Base.metadata.tables + + +def test_insert_and_query(engine): + """ + Test basic database operations (insert and query) on a table + to ensure the ORM definitions functionally work. + """ + with Session(engine) as session: + subj = Subject(subj_code="CSCI", title="Computer Science") + session.add(subj) + session.commit() + + fetched = session.query(Subject).filter_by(subj_code="CSCI").first() + assert fetched is not None + assert fetched.subj_code == "CSCI" + assert fetched.title == "Computer Science" From b2e3fb06a9dd01cdfdcd6b53eda6c468aa08e2c7 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:03:49 -0400 Subject: [PATCH 03/12] Update required Python version in pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index cbc5619..4b9fd90 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "carpi-data-model" version = "1.0" dependencies = ["SQLAlchemy>=2.0.0"] -requires-python = ">=3.7" +requires-python = ">=3.10" authors = [{ name = "Raymond Chen" }, { name = "Jack Zgombic" }] maintainers = [{ name = "Raymond Chen" }] description = "The MySQL database schema used in Project CARPI." From b7c7ea00dde239834cdf22f25b75a2a2ec54ca13 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:04:19 -0400 Subject: [PATCH 04/12] Minor fix to docstring format --- tests/test_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_models.py b/tests/test_models.py index 032ea6c..145d035 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -47,8 +47,8 @@ def test_create_tables(engine): def test_insert_and_query(engine): """ - Test basic database operations (insert and query) on a table - to ensure the ORM definitions functionally work. + Test basic database operations (insert and query) on a table to ensure the + ORM definitions functionally work. """ with Session(engine) as session: subj = Subject(subj_code="CSCI", title="Computer Science") From 8c5d1875bce91239248a1935406f31805b12dc36 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:17:08 -0400 Subject: [PATCH 05/12] Add setup and testing instructions to README --- README.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fd5ebc8..4197ad9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,75 @@ # database-schema -CARPI MySQL database schemas. + +This repository is a Python package that contains SQLAlchemy data models for use in the CARPI Course Planner project. + +## Installing as a Dependency + +In your project's dependency list (often named `requirements.txt` or similar), add the following line: + +``` +carpi-data-model @ git+https://github.com/Project-CARPI/database-schema.git +``` + +If installing directly on the command line using pip, use the following command: + +```bash +pip3 install git+https://github.com/Project-CARPI/database-schema.git +``` + +## Local Development & Testing + +Along with the core SQLAlchemy models, this repository includes a PyTest-based test suite. + +### Prerequisites + +- **Python >= 3.10**: If you don't have it installed, [download it here.](https://www.python.org/) +- **Docker**: Required to automatically spin up temporary MySQL containers during testing. [Download Docker Desktop here.](https://www.docker.com/products/docker-desktop/) + +### Setup Instructions + +**1. Set Up a Virtual Environment** +To avoid cluttering your global Python environment, create a virtual environment in the project root: + +```bash +# Create a virtual environment directory named .venv +python -m venv .venv +``` + +**2. Activate the Environment** +Depending on your operating system, activate the virtual environment: + +- **Windows:** + ```powershell + .venv\Scripts\activate + ``` +- **macOS / Linux:** + ```bash + source .venv/bin/activate + ``` + +You will see a `(.venv)` prefix in your terminal prompt when the environment is successfully active: + +```bash +(.venv) raymond@Macbook-Pro database-schema % +``` + +**3. Install Required Dependencies** +With the virtual environment active, install the required packages for testing: + +```bash +pip install -r requirements.txt +``` + +### Running the Tests + +Once your environment is set up and **Docker is running** in the background, you can execute the test suite using pytest: + +```bash +pytest tests/ +``` + +To exit the virtual environment when you are finished, run the deactivate command: + +```bash +deactivate +``` From 3c0f7ad812c05bd2e726b717fed104fc4a0a8662 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:20:37 -0400 Subject: [PATCH 06/12] Add GitHub Action to automatically run test suite --- .github/workflows/test.yml | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..54bf2c4 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,42 @@ +name: Run Tests + +on: + push: + branches: ["**"] + pull_request: + branches: ["**"] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + # Match the Python version specified in pyproject.toml + python-version: "3.10" + cache: "pip" + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + + # Remove the remote git dependency from requirements so CI doesn't + # clone and test the remote 'main' branch over your local commit! + sed -i '/git+https:\/\/github\.com\/Project-CARPI\/database-schema\.git/d' requirements.txt + + # Install all other dependencies + pip install -r requirements.txt + + # Install the currently checked-out version of the project + pip install -e . + + - name: Run Test Suite + # GitHub's Ubuntu runners come with Docker pre-installed so the testcontainers + # package should work out of the box. + run: | + pytest tests/ From ab3f356c5616ee55ee288de9cec95ea63d66a558 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:24:34 -0400 Subject: [PATCH 07/12] Clarify GitHub Action test and job names --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 54bf2c4..a38f964 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Run Tests +name: SQLAlchemy Model Tests on: push: @@ -7,7 +7,7 @@ on: branches: ["**"] jobs: - test: + Run Test Suite: runs-on: ubuntu-latest steps: From 1598a7540fc832485defa2b4fa8a391706e340b7 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:29:53 -0400 Subject: [PATCH 08/12] Fix spaces in GitHub Action job name Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a38f964..fd21a24 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,8 @@ on: branches: ["**"] jobs: - Run Test Suite: + run_test_suite: + name: Run Test Suite runs-on: ubuntu-latest steps: From 00ddeaf6507a5e585204f87e109ee181089154df Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:30:20 -0400 Subject: [PATCH 09/12] Replace wildcard model import with individual imports Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/test_models.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/test_models.py b/tests/test_models.py index 145d035..455a094 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -3,7 +3,19 @@ from sqlalchemy.orm import Session from testcontainers.mysql import MySqlContainer -from carpi_data_model.models import * +from carpi_data_model.models import ( + Attribute, + Base, + Course, + Course_Attribute, + Course_Faculty, + Course_Offering, + Course_Relationship, + Course_Restriction, + Faculty, + Restriction, + Subject, +) @pytest.fixture(scope="session") From 362021aae0f3a0ceca1044d15fb2258cf519ff76 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:30:58 -0400 Subject: [PATCH 10/12] Dispose SQLAlchemy engine after test session Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/test_models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_models.py b/tests/test_models.py index 455a094..460b6af 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -25,7 +25,11 @@ def engine(): requires Docker to be running on your machine. """ with MySqlContainer("mysql:8.0", dialect="mysqlconnector") as mysql: - yield create_engine(mysql.get_connection_url(), echo=False) + db_engine = create_engine(mysql.get_connection_url(), echo=False) + try: + yield db_engine + finally: + db_engine.dispose() @pytest.fixture(autouse=True) From 77b6fab3e8146ac3abb6aad3ccd6bb5ca28f49cc Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:33:41 -0400 Subject: [PATCH 11/12] Assert table existence in database Previously, the test only ensured that the Python model declarations were correct, which didn't imply that the tables were successfully created in the database. Although, I suppose this test wouldn't run in the first place if the setup_database fixture failed beforehand. --- tests/test_models.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/tests/test_models.py b/tests/test_models.py index 145d035..3b62b90 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,5 +1,5 @@ import pytest -from sqlalchemy import create_engine +from sqlalchemy import create_engine, inspect from sqlalchemy.orm import Session from testcontainers.mysql import MySqlContainer @@ -31,18 +31,21 @@ def test_create_tables(engine): """ Test that the SQLAlchemy schema can be translated into DDL and executed in a Native MySQL database without throwing any mapping or constraint - errors. - """ - assert Subject.__tablename__ in Base.metadata.tables - assert Attribute.__tablename__ in Base.metadata.tables - assert Restriction.__tablename__ in Base.metadata.tables - assert Faculty.__tablename__ in Base.metadata.tables - assert Course.__tablename__ in Base.metadata.tables - assert Course_Attribute.__tablename__ in Base.metadata.tables - assert Course_Relationship.__tablename__ in Base.metadata.tables - assert Course_Restriction.__tablename__ in Base.metadata.tables - assert Course_Offering.__tablename__ in Base.metadata.tables - assert Course_Faculty.__tablename__ in Base.metadata.tables + errors. Ensures the tables actually exist in the database catalog. + """ + inspector = inspect(engine) + existing_tables = inspector.get_table_names() + + assert Subject.__tablename__ in existing_tables + assert Attribute.__tablename__ in existing_tables + assert Restriction.__tablename__ in existing_tables + assert Faculty.__tablename__ in existing_tables + assert Course.__tablename__ in existing_tables + assert Course_Attribute.__tablename__ in existing_tables + assert Course_Relationship.__tablename__ in existing_tables + assert Course_Restriction.__tablename__ in existing_tables + assert Course_Offering.__tablename__ in existing_tables + assert Course_Faculty.__tablename__ in existing_tables def test_insert_and_query(engine): From e9f2a797e3a61edbad3d1e07cd1fe26b75779e7c Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Thu, 9 Apr 2026 13:29:14 -0400 Subject: [PATCH 12/12] Update self-dependency to use local source code Previously, there was a major potential issue during development in which local changes to the package would not be tested properly. This was the old dependency line would fetch the latest commit from the default git branch and PyTest would test that code, effectively making the tests meaningless. This new dependency line basically adds all files in the current working directory to the Python PATH, and this only needs to be done once as Python will automatically track changes to the source code upon each import of the package. The GitHub Action job has also been simplified to reflect this new change. --- .github/workflows/test.yml | 9 --------- requirements.txt | 10 ++++++++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fd21a24..59d5c5e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,17 +25,8 @@ jobs: - name: Install Dependencies run: | python -m pip install --upgrade pip - - # Remove the remote git dependency from requirements so CI doesn't - # clone and test the remote 'main' branch over your local commit! - sed -i '/git+https:\/\/github\.com\/Project-CARPI\/database-schema\.git/d' requirements.txt - - # Install all other dependencies pip install -r requirements.txt - # Install the currently checked-out version of the project - pip install -e . - - name: Run Test Suite # GitHub's Ubuntu runners come with Docker pre-installed so the testcontainers # package should work out of the box. diff --git a/requirements.txt b/requirements.txt index 4896285..853de12 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,11 @@ -# Self-dependency that allows us to import data models for testing --e git+https://github.com/Project-CARPI/database-schema.git#egg=carpi_data_model +# Self-dependency that allows PyTest to import the package being tested. +# +# As an "editable" dependency, Python will automatically track changes to the source code +# without needing to reinstall the package after every change, which is ideal for +# development environments. +-e . + +# Other third-party dependencies certifi==2026.2.25 charset-normalizer==3.4.7 docker==7.1.0