diff --git a/.github/workflows/test_suite.yml b/.github/workflows/test_suite.yml index a21f8661..6059aca5 100644 --- a/.github/workflows/test_suite.yml +++ b/.github/workflows/test_suite.yml @@ -14,7 +14,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.14 - name: Install nox run: python -m pip install nox - name: Run Lint @@ -22,18 +22,20 @@ jobs: unit: runs-on: ubuntu-latest - + strategy: + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] steps: - name: Checkout code uses: actions/checkout@v5 - - name: Setup Python + - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: ${{ matrix.python-version }} - name: Install nox run: python -m pip install nox - name: Run Unit Tests - run: nox -s unit + run: nox -s unit-${{ matrix.python-version }} env: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging @@ -47,7 +49,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.14 - name: Install nox run: python -m pip install nox - name: Run mockserver tests @@ -62,7 +64,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.14 - name: Install nox run: python -m pip install nox - name: Run samples @@ -84,7 +86,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.9 - name: Install nox run: python -m pip install nox - name: Run Compliance Tests @@ -109,7 +111,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.14 - name: Install nox run: python -m pip install nox - name: Run Compliance Tests @@ -120,7 +122,9 @@ jobs: system: runs-on: ubuntu-latest - + strategy: + matrix: + python-version: ["3.9", "3.14"] services: emulator-0: image: gcr.io/cloud-spanner-emulator/emulator:latest @@ -130,14 +134,14 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v5 - - name: Setup Python + - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: ${{ matrix.python-version }} - name: Install nox run: python -m pip install nox - name: Run System Tests - run: nox -s system + run: nox -s system-${{ matrix.python-version }} env: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging @@ -157,11 +161,11 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.9 - name: Install nox run: python -m pip install nox - name: Run Migration Tests run: nox -s migration_test env: SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging \ No newline at end of file diff --git a/noxfile.py b/noxfile.py index c9f1cb24..567c01f5 100644 --- a/noxfile.py +++ b/noxfile.py @@ -75,10 +75,12 @@ class = StreamHandler """ -BLACK_VERSION = "black==22.3.0" +BLACK_VERSION = "black==23.7.0" BLACK_PATHS = ["google", "test", "noxfile.py", "setup.py", "samples"] -DEFAULT_PYTHON_VERSION = "3.12" -DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20 = "3.12" +UNIT_TEST_PYTHON_VERSIONS = ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] +SYSTEM_TEST_PYTHON_VERSIONS = ["3.9", "3.14"] +DEFAULT_PYTHON_VERSION = "3.14" +DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20 = "3.14" @nox.session(python=DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20) @@ -126,7 +128,7 @@ def lint_setup_py(session): session.run("python", "setup.py", "check", "--restructuredtext", "--strict") -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS[0]) def compliance_test_14(session): """Run SQLAlchemy dialect compliance test suite.""" @@ -208,7 +210,7 @@ def compliance_test_20(session): ) -@nox.session() +@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) def system(session): """Run SQLAlchemy dialect system test suite.""" @@ -245,7 +247,7 @@ def system(session): session.run("python", "drop_test_database.py") -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS) def unit(session): """Run unit tests.""" # Run SQLAlchemy dialect compliance test suite with OpenTelemetry. @@ -287,14 +289,14 @@ def mockserver(session): ) -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS[0]) def migration_test(session): """Test migrations with SQLAlchemy v1.4 and Alembic""" session.run("pip", "install", "sqlalchemy>=1.4,<2.0", "--force-reinstall") _migration_test(session) -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS[-1]) def _migration_test(session): """Migrate with SQLAlchemy and Alembic and check the result.""" import glob diff --git a/samples/insert_data_sample.py b/samples/insert_data_sample.py index a415e621..c2e25ad2 100644 --- a/samples/insert_data_sample.py +++ b/samples/insert_data_sample.py @@ -20,6 +20,7 @@ from sample_helper import run_sample from model import Singer, Album, Track + # Shows how to insert data using SQLAlchemy, including relationships that are # defined both as foreign keys and as interleaved tables. def insert_data(): diff --git a/samples/insert_or_ignore_sample.py b/samples/insert_or_ignore_sample.py index 36fbd492..065bb059 100644 --- a/samples/insert_or_ignore_sample.py +++ b/samples/insert_or_ignore_sample.py @@ -21,6 +21,7 @@ from sample_helper import run_sample from model import Singer + # Shows how to use insert-or-ignore using SQLAlchemy and Spanner. def insert_or_ignore_sample(): engine = create_engine( diff --git a/samples/insert_or_update_sample.py b/samples/insert_or_update_sample.py index 9b23b24a..75c2f53b 100644 --- a/samples/insert_or_update_sample.py +++ b/samples/insert_or_update_sample.py @@ -21,6 +21,7 @@ from sample_helper import run_sample from model import Singer + # Shows how to use insert-or-update using SQLAlchemy and Spanner. def insert_or_update_sample(): engine = create_engine( diff --git a/samples/interleaved_table_sample.py b/samples/interleaved_table_sample.py index 0d652159..2b009101 100644 --- a/samples/interleaved_table_sample.py +++ b/samples/interleaved_table_sample.py @@ -20,6 +20,7 @@ from sample_helper import run_sample from model import Singer, Album, Track + # Shows how INTERLEAVE IN PARENT can be used in SQLAlchemy. # INTERLEAVE IN PARENT can be modelled as if it were a normal relationship # in SQLAlchemy. SQLAlchemy can also generate the correct DDL for this. diff --git a/samples/parse_json_sample.py b/samples/parse_json_sample.py index b0868ea8..34488fa6 100644 --- a/samples/parse_json_sample.py +++ b/samples/parse_json_sample.py @@ -18,6 +18,7 @@ from sample_helper import run_sample from model import Venue + # Shows how to use the PARSE_JSON function in Spanner using SQLAlchemy. def parse_json_sample(): engine = create_engine( diff --git a/samples/partitioned_dml_sample.py b/samples/partitioned_dml_sample.py index 62c312ff..e799a39d 100644 --- a/samples/partitioned_dml_sample.py +++ b/samples/partitioned_dml_sample.py @@ -17,6 +17,7 @@ from sample_helper import run_sample + # Shows how to use Partitioned DML using SQLAlchemy and Spanner. def partitioned_dml_sample(): engine = create_engine( diff --git a/samples/pickle_type_sample.py b/samples/pickle_type_sample.py index 58159996..f3dce513 100644 --- a/samples/pickle_type_sample.py +++ b/samples/pickle_type_sample.py @@ -20,6 +20,7 @@ from sample_helper import run_sample from model import Singer + # Shows how to use PickleType with Spanner. def pickle_type(): engine = create_engine( diff --git a/setup.py b/setup.py index 67cd184b..9da47231 100644 --- a/setup.py +++ b/setup.py @@ -62,6 +62,12 @@ classifiers=[ "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ], description=description, long_description=readme,