diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 508ba98e..4a311db0 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:25de45b58e52021d3a24a6273964371a97a4efeefe6ad3845a64e697c63b6447 -# created: 2025-04-14T14:34:43.260858345Z + digest: sha256:543e209e7c1c1ffe720eb4db1a3f045a75099304fb19aa11a47dc717b8aae2a9 +# created: 2025-10-09T14:48:42.914384887Z diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index d9de7a03..c3e26318 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -11,7 +11,6 @@ branchProtectionRules: - 'OwlBot Post Processor' - 'Kokoro' - 'Samples - Lint' - - 'Samples - Python 3.8' - 'Samples - Python 3.9' - 'Samples - Python 3.10' - 'Samples - Python 3.11' diff --git a/.kokoro/samples/python3.14/common.cfg b/.kokoro/samples/python3.14/common.cfg new file mode 100644 index 00000000..cc6e7ee0 --- /dev/null +++ b/.kokoro/samples/python3.14/common.cfg @@ -0,0 +1,40 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} + +# Specify which tests to run +env_vars: { + key: "RUN_TESTS_SESSION" + value: "py-3.14" +} + +# Declare build specific Cloud project. +env_vars: { + key: "BUILD_SPECIFIC_GCLOUD_PROJECT" + value: "python-docs-samples-tests-314" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-bigquery-sqlalchemy/.kokoro/test-samples.sh" +} + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-samples-testing-docker" +} + +# Download secrets for samples +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples" + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Use the trampoline script to run in docker. +build_file: "python-bigquery-sqlalchemy/.kokoro/trampoline_v2.sh" diff --git a/.kokoro/samples/python3.14/continuous.cfg b/.kokoro/samples/python3.14/continuous.cfg new file mode 100644 index 00000000..a1c8d975 --- /dev/null +++ b/.kokoro/samples/python3.14/continuous.cfg @@ -0,0 +1,6 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} \ No newline at end of file diff --git a/.kokoro/samples/python3.14/periodic-head.cfg b/.kokoro/samples/python3.14/periodic-head.cfg new file mode 100644 index 00000000..abf3481d --- /dev/null +++ b/.kokoro/samples/python3.14/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-bigquery-sqlalchemy/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.14/periodic.cfg b/.kokoro/samples/python3.14/periodic.cfg new file mode 100644 index 00000000..71cd1e59 --- /dev/null +++ b/.kokoro/samples/python3.14/periodic.cfg @@ -0,0 +1,6 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "False" +} diff --git a/.kokoro/samples/python3.14/presubmit.cfg b/.kokoro/samples/python3.14/presubmit.cfg new file mode 100644 index 00000000..a1c8d975 --- /dev/null +++ b/.kokoro/samples/python3.14/presubmit.cfg @@ -0,0 +1,6 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 72311aa6..83a5bc63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,14 @@ Older versions of this project were distributed as [pybigquery][0]. [2]: https://pypi.org/project/pybigquery/#history +## [1.16.0](https://github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.15.0...v1.16.0) (2025-11-05) + + +### Features + +* Add support for Python 3.14 ([#1278](https://github.com/googleapis/python-bigquery-sqlalchemy/issues/1278)) ([c09a009](https://github.com/googleapis/python-bigquery-sqlalchemy/commit/c09a00976a70194abb2561753071e3e7b3659d5c)) +* Remove python 3.8 support ([#1215](https://github.com/googleapis/python-bigquery-sqlalchemy/issues/1215)) ([632d6ef](https://github.com/googleapis/python-bigquery-sqlalchemy/commit/632d6ef024bdd1dcb4206e2b111063f79f29b7ba)) + ## [1.15.0](https://github.com/googleapis/python-bigquery-sqlalchemy/compare/v1.14.1...v1.15.0) (2025-06-18) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 2f03f9d0..3d141082 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -22,7 +22,7 @@ In order to add a feature: documentation. - The feature must work fully on the following CPython versions: - 3.8, 3.9, 3.10, 3.11, 3.12, and 3.13 on both UNIX and Windows. + 3.9, 3.10, 3.11, 3.12, 3.13 and 3.14 on both UNIX and Windows. - The feature must not add unnecessary dependencies (where "unnecessary" is of course subjective, but new dependencies should @@ -72,7 +72,7 @@ We use `nox `__ to instrument our tests. - To run a single unit test:: - $ nox -s unit-3.13 -- -k + $ nox -s unit-3.14 -- -k .. note:: @@ -143,12 +143,12 @@ Running System Tests $ nox -s system # Run a single system test - $ nox -s system-3.13 -- -k + $ nox -s system-3.14 -- -k .. note:: - System tests are only configured to run under Python 3.8, 3.12, and 3.13. + System tests are only configured to run under Python 3.9, 3.12, and 3.14. For expediency, we do not run them in older versions of Python 3. This alone will not run the tests. You'll need to change some local @@ -195,11 +195,11 @@ configure them just like the System Tests. # Run all tests in a folder $ cd samples/snippets - $ nox -s py-3.8 + $ nox -s py-3.9 # Run a single sample test $ cd samples/snippets - $ nox -s py-3.8 -- -k + $ nox -s py-3.9 -- -k ******************************************** Note About ``README`` as it pertains to PyPI @@ -221,19 +221,19 @@ Supported Python Versions We support: -- `Python 3.8`_ - `Python 3.9`_ - `Python 3.10`_ - `Python 3.11`_ - `Python 3.12`_ - `Python 3.13`_ +- `Python 3.14`_ -.. _Python 3.8: https://docs.python.org/3.8/ .. _Python 3.9: https://docs.python.org/3.9/ .. _Python 3.10: https://docs.python.org/3.10/ .. _Python 3.11: https://docs.python.org/3.11/ .. _Python 3.12: https://docs.python.org/3.12/ .. _Python 3.13: https://docs.python.org/3.13/ +.. _Python 3.14: https://docs.python.org/3.14/ Supported versions can be found in our ``noxfile.py`` `config`_. @@ -241,7 +241,7 @@ Supported versions can be found in our ``noxfile.py`` `config`_. .. _config: https://github.com/googleapis/python-bigquery-sqlalchemy/blob/main/noxfile.py -We also explicitly decided to support Python 3 beginning with version 3.8. +We also explicitly decided to support Python 3 beginning with version 3.9. Reasons for this include: - Encouraging use of newest versions of Python 3 diff --git a/README.rst b/README.rst index 2a64c0c7..be964f0c 100644 --- a/README.rst +++ b/README.rst @@ -51,7 +51,7 @@ dependencies. Supported Python Versions ^^^^^^^^^^^^^^^^^^^^^^^^^ -Python >= 3.8, <3.14 +Python >= 3.9, <3.14 Unsupported Python Versions ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/noxfile.py b/noxfile.py index b6e34730..d4fd895b 100644 --- a/noxfile.py +++ b/noxfile.py @@ -18,10 +18,12 @@ from __future__ import absolute_import +from functools import wraps import os import pathlib import re import shutil +import time from typing import Dict, List import warnings @@ -39,9 +41,9 @@ "setup.py", ] -DEFAULT_PYTHON_VERSION = "3.8" +DEFAULT_PYTHON_VERSION = "3.14" -UNIT_TEST_PYTHON_VERSIONS: List[str] = ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] +UNIT_TEST_PYTHON_VERSIONS: List[str] = ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] UNIT_TEST_STANDARD_DEPENDENCIES = [ "mock", "asyncmock", @@ -56,11 +58,6 @@ "tests", ] UNIT_TEST_EXTRAS_BY_PYTHON: Dict[str, List[str]] = { - "3.8": [ - "tests", - "alembic", - "bqstorage", - ], "3.11": [ "tests", "geography", @@ -76,9 +73,14 @@ "geography", "bqstorage", ], + "3.14": [ + "tests", + "geography", + "bqstorage", + ], } -SYSTEM_TEST_PYTHON_VERSIONS: List[str] = ["3.8", "3.12", "3.13"] +SYSTEM_TEST_PYTHON_VERSIONS: List[str] = ["3.9", "3.12", "3.13", "3.14"] SYSTEM_TEST_STANDARD_DEPENDENCIES: List[str] = [ "mock", "pytest", @@ -91,17 +93,17 @@ "tests", ] SYSTEM_TEST_EXTRAS_BY_PYTHON: Dict[str, List[str]] = { - "3.8": [ + "3.12": [ "tests", - "alembic", + "geography", "bqstorage", ], - "3.12": [ + "3.13": [ "tests", "geography", "bqstorage", ], - "3.13": [ + "3.14": [ "tests", "geography", "bqstorage", @@ -110,6 +112,27 @@ CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() + +def _calculate_duration(func): + """This decorator prints the execution time for the decorated function.""" + + @wraps(func) + def wrapper(*args, **kwargs): + start = time.monotonic() + result = func(*args, **kwargs) + end = time.monotonic() + total_seconds = round(end - start) + hours = total_seconds // 3600 # Integer division to get hours + remaining_seconds = total_seconds % 3600 # Modulo to find remaining seconds + minutes = remaining_seconds // 60 + seconds = remaining_seconds % 60 + human_time = f"{hours:}:{minutes:0>2}:{seconds:0>2}" + print(f"Session ran in {total_seconds} seconds ({human_time})") + return result + + return wrapper + + nox.options.sessions = [ "unit", "system", @@ -128,6 +151,7 @@ @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def lint(session): """Run linters. @@ -144,6 +168,7 @@ def lint(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def blacken(session): """Run black. Format code to uniform standard.""" session.install(BLACK_VERSION) @@ -154,6 +179,7 @@ def blacken(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def format(session): """ Run isort to sort imports. Then run black @@ -174,9 +200,10 @@ def format(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def lint_setup_py(session): """Verify that setup.py is valid (including RST check).""" - session.install("docutils", "pygments") + session.install("docutils", "pygments", "setuptools") session.run("python", "setup.py", "check", "--restructuredtext", "--strict") @@ -213,10 +240,16 @@ def install_unittest_dependencies(session, *constraints): "protobuf_implementation", ["python", "upb", "cpp"], ) +@_calculate_duration def unit(session, protobuf_implementation, install_extras=True): # Install all test dependencies, then install this package in-place. - if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): + if protobuf_implementation == "cpp" and session.python in ( + "3.11", + "3.12", + "3.13", + "3.14", + ): session.skip("cpp implementation is not supported in python 3.11+") constraints_path = str( @@ -224,7 +257,7 @@ def unit(session, protobuf_implementation, install_extras=True): ) install_unittest_dependencies(session, "-c", constraints_path) - if install_extras and session.python in ["3.11", "3.12", "3.13"]: + if install_extras and session.python in ["3.11", "3.12", "3.13", "3.14"]: install_target = ".[geography,alembic,tests,bqstorage]" elif install_extras: install_target = ".[all]" @@ -288,6 +321,7 @@ def install_systemtest_dependencies(session, *constraints): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) +@_calculate_duration def system(session): """Run the system test suite.""" constraints_path = str( @@ -331,6 +365,7 @@ def system(session): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) +@_calculate_duration def system_noextras(session): """Run the system test suite.""" constraints_path = str( @@ -376,6 +411,7 @@ def system_noextras(session): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS[-1]) +@_calculate_duration def compliance(session): """Run the SQLAlchemy dialect-compliance system tests""" constraints_path = str( @@ -398,10 +434,8 @@ def compliance(session): "-c", constraints_path, ) - if session.python == "3.8": - extras = "[tests,alembic]" - elif session.python in ["3.12", "3.13"]: - extras = "[tests,geography]" + if session.python in ["3.12", "3.13", "3.14"]: + extras = "[tests,geography,alembic]" else: extras = "[tests]" session.install("-e", f".{extras}", "-c", constraints_path) @@ -430,6 +464,7 @@ def compliance(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def cover(session): """Run the final coverage report. @@ -443,6 +478,7 @@ def cover(session): @nox.session(python="3.10") +@_calculate_duration def docs(session): """Build the docs for this library.""" @@ -480,6 +516,7 @@ def docs(session): @nox.session(python="3.10") +@_calculate_duration def docfx(session): """Build the docfx yaml files for this library.""" @@ -527,15 +564,21 @@ def docfx(session): ) -@nox.session(python="3.13") +@nox.session(python=DEFAULT_PYTHON_VERSION) @nox.parametrize( "protobuf_implementation", ["python", "upb", "cpp"], ) +@_calculate_duration def prerelease_deps(session, protobuf_implementation): """Run all tests with prerelease versions of dependencies installed.""" - if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13"): + if protobuf_implementation == "cpp" and session.python in ( + "3.11", + "3.12", + "3.13", + "3.14", + ): session.skip("cpp implementation is not supported in python 3.11+") # Install all dependencies diff --git a/owlbot.py b/owlbot.py index 5173dce0..e5e1d8b4 100644 --- a/owlbot.py +++ b/owlbot.py @@ -30,14 +30,15 @@ # ---------------------------------------------------------------------------- extras = ["tests"] extras_by_python = { - "3.8": ["tests", "alembic", "bqstorage"], + "3.9": ["tests", "alembic", "bqstorage"], "3.11": ["tests", "geography", "bqstorage"], "3.12": ["tests", "geography", "bqstorage"], "3.13": ["tests", "geography", "bqstorage"], + "3.14": ["tests", "geography", "bqstorage"], } templated_files = common.py_library( - unit_test_python_versions=["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - system_test_python_versions=["3.8", "3.12", "3.13"], + unit_test_python_versions=["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"], + system_test_python_versions=["3.9", "3.12", "3.13", "3.14"], cov_level=100, unit_test_extras=extras, unit_test_extras_by_python=extras_by_python, @@ -53,6 +54,7 @@ # exclude gh actions as credentials are needed for tests ".github/workflows", "README.rst", + "renovate.json", ], ) diff --git a/renovate.json b/renovate.json index c7875c46..ccdeeb0a 100644 --- a/renovate.json +++ b/renovate.json @@ -8,5 +8,12 @@ "ignorePaths": [".pre-commit-config.yaml", ".kokoro/requirements.txt", "setup.py", ".github/workflows/unittest.yml"], "pip_requirements": { "fileMatch": ["requirements-test.txt", "samples/[\\S/]*constraints.txt", "samples/[\\S/]*constraints-test.txt"] - } + }, + "packageRules": [ + { + "matchFileNames": ["requirements.txt"], + "matchStrings": ["geoalchemy2(.*); python_version == '3.9'"], + "allowedVersions": ">= 0.17.1, < 0.18.0" + } + ] } diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index e5885544..6c2546ed 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -89,7 +89,7 @@ def get_pytest_env_vars() -> Dict[str, str]: # DO NOT EDIT - automatically generated. # All versions used to test samples. -ALL_VERSIONS = ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] +ALL_VERSIONS = ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] # Any default versions that should be ignored. IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] diff --git a/samples/snippets/requirements-test.txt b/samples/snippets/requirements-test.txt index 82b196c3..b878043a 100644 --- a/samples/snippets/requirements-test.txt +++ b/samples/snippets/requirements-test.txt @@ -1,20 +1,17 @@ -attrs==25.3.0 +attrs==25.4.0 click===8.1.8; python_version <= '3.9' -click==8.2.1; python_version >= '3.10' -google-auth==2.40.3 +click==8.3.0; python_version >= '3.10' +google-auth==2.41.1 google-cloud-testutils==1.6.4 iniconfig==2.1.0 packaging==25.0 -pluggy===1.5.0; python_version == '3.8' pluggy==1.6.0; python_version >= '3.9' py==1.11.0 pyasn1==0.6.1 pyasn1-modules==0.4.2 -pyparsing===3.1.4; python_version == '3.8' -pyparsing==3.2.3; python_version >= '3.9' +pyparsing==3.2.5; python_version >= '3.9' pytest===6.2.5 rsa==4.9.1 six==1.17.0 toml==0.10.2 -typing-extensions===4.13.0; python_version == '3.8' -typing-extensions==4.14.0; python_version >= '3.9' +typing-extensions==4.15.0; python_version >= '3.9' diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index 3ee07a2d..2b448f07 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,47 +1,35 @@ -alembic===1.14.0; python_version == '3.8' -alembic==1.16.2; python_version >= '3.9' -certifi==2025.6.15 -charset-normalizer==3.4.2 -geoalchemy2==0.17.1 -google-api-core[grpc]==2.25.1 -google-auth==2.40.3 -google-cloud-bigquery===3.30.0; python_version == '3.8' -google-cloud-bigquery==3.34.0; python_version >= '3.9' +alembic==1.16.5; python_version >= '3.9' +certifi==2025.10.5 +charset-normalizer==3.4.3 +geoalchemy2===0.17.1; python_version == '3.9' +geoalchemy2==0.18.0; python_version >= '3.10' +google-api-core[grpc]==2.25.2 +google-auth==2.41.1 +google-cloud-bigquery==3.38.0; python_version >= '3.9' google-cloud-core==2.4.3 -google-crc32c===1.5.0; python_version == '3.8' google-crc32c==1.7.1; python_version >= '3.9' google-resumable-media==2.7.2 googleapis-common-protos==1.70.0 -greenlet===3.1.1; python_version == '3.8' -greenlet==3.2.3; python_version >= '3.9' -grpcio===1.68.0; python_version == '3.8' -grpcio==1.73.0; python_version >= '3.9' -grpcio-status===1.68.0; python_version == '3.8' -grpcio-status==1.73.0; python_version >= '3.9' +greenlet==3.2.4; python_version >= '3.9' +grpcio==1.75.1; python_version >= '3.9' +grpcio-status==1.75.1; python_version >= '3.9' idna==3.10 -importlib-resources===6.4.5; python_version == '3.8' importlib-resources==6.5.2; python_version >= '3.9' -mako===1.3.5; python_version == '3.8' mako==1.3.10; python_version >= '3.9' -markupsafe===2.1.5; python_version == '3.8' -markupsafe==3.0.2; python_version >= '3.9' +markupsafe==3.0.3; python_version >= '3.9' packaging==25.0 proto-plus==1.26.1 -protobuf===5.28.3; python_version == '3.8' -protobuf==6.31.1; python_version >= '3.9' +protobuf==6.32.1; python_version >= '3.9' pyasn1==0.6.1 pyasn1-modules==0.4.2 -pyparsing===3.1.4; python_version == '3.8' -pyparsing==3.2.3; python_version >= '3.9' +pyparsing==3.2.5; python_version >= '3.9' python-dateutil==2.9.0.post0 pytz==2025.2 -requests==2.32.4 +requests==2.32.5 rsa==4.9.1 shapely===2.0.7; python_version <= '3.9' -shapely==2.1.1; python_version >= '3.10' +shapely==2.1.2; python_version >= '3.10' six==1.17.0 sqlalchemy===1.4.27 -typing-extensions===4.13.0; python_version == '3.8' -typing-extensions==4.14.0; python_version >= '3.9' -urllib3===2.2.3; python_version == '3.8' +typing-extensions==4.15.0; python_version >= '3.9' urllib3==2.5.0; python_version >= '3.9' diff --git a/setup.py b/setup.py index 6d6c814a..fbc319bd 100644 --- a/setup.py +++ b/setup.py @@ -61,8 +61,9 @@ def readme(): # grpc.Channel.close() method isn't added until 1.32.0. # https://github.com/grpc/grpc/pull/15254 "grpcio >= 1.47.0, < 2.0.0", - "grpcio >= 1.49.1, < 2.0.0; python_version>='3.11'", - "pyarrow >= 3.0.0", + "grpcio >= 1.49.1, < 2.0.0; python_version =='3.11'", + "grpcio >= 1.75.1, < 2.0.0; python_version >= '3.14'", + "pyarrow >= 5.0.0", ], } @@ -105,6 +106,7 @@ def readme(): "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: OS Independent", "Topic :: Database :: Front-Ends", ], @@ -120,7 +122,7 @@ def readme(): "sqlalchemy>=1.4.16,<3.0.0", ], extras_require=extras, - python_requires=">=3.8, <3.14", + python_requires=">=3.8, <3.15", tests_require=["packaging", "pytz"], entry_points={ "sqlalchemy.dialects": ["bigquery = sqlalchemy_bigquery:BigQueryDialect"] diff --git a/sqlalchemy_bigquery/__init__.py b/sqlalchemy_bigquery/__init__.py index 1e506125..373c4861 100644 --- a/sqlalchemy_bigquery/__init__.py +++ b/sqlalchemy_bigquery/__init__.py @@ -48,14 +48,17 @@ from . import _versions_helpers sys_major, sys_minor, sys_micro = _versions_helpers.extract_runtime_version() -if sys_major == 3 and sys_minor in (7, 8): + +# Now that support for Python 3.7 and 3.8 has been removed, we don't expect the +# following check to succeed. The warning is only included for robustness. +if sys_major == 3 and sys_minor in (7, 8): # pragma: NO COVER warnings.warn( - "The python-bigquery library will stop supporting Python 3.7 " - "and Python 3.8 in a future major release expected in Q4 2024. " + "The python-bigquery-sqlalchemy library no longer supports Python 3.7 " + "and Python 3.8. " f"Your Python version is {sys_major}.{sys_minor}.{sys_micro}. We " "recommend that you update soon to ensure ongoing support. For " "more details, see: [Google Cloud Client Libraries Supported Python Versions policy](https://cloud.google.com/python/docs/supported-python-versions)", - PendingDeprecationWarning, + FutureWarning, ) diff --git a/sqlalchemy_bigquery/version.py b/sqlalchemy_bigquery/version.py index 86059295..e76f81a9 100644 --- a/sqlalchemy_bigquery/version.py +++ b/sqlalchemy_bigquery/version.py @@ -17,4 +17,4 @@ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__version__ = "1.15.0" +__version__ = "1.16.0" diff --git a/testing/constraints-3.14.txt b/testing/constraints-3.14.txt new file mode 100644 index 00000000..e69de29b diff --git a/testing/constraints-3.8.txt b/testing/constraints-3.8.txt deleted file mode 100644 index 667a747d..00000000 --- a/testing/constraints-3.8.txt +++ /dev/null @@ -1,13 +0,0 @@ -# This constraints file is used to check that lower bounds -# are correct in setup.py -# List *all* library dependencies and extras in this file. -# Pin the version to the lower bound. -# -# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", -sqlalchemy==1.4.16 -google-auth==1.25.0 -google-cloud-bigquery==3.3.6 -google-cloud-bigquery-storage==2.0.0 -google-api-core==1.31.5 -grpcio==1.47.0 -pyarrow==3.0.0 diff --git a/testing/constraints-3.9.txt b/testing/constraints-3.9.txt index e69de29b..a9840fe3 100644 --- a/testing/constraints-3.9.txt +++ b/testing/constraints-3.9.txt @@ -0,0 +1,13 @@ +# This constraints file is used to check that lower bounds +# are correct in setup.py +# List *all* library dependencies and extras in this file. +# Pin the version to the lower bound. +# +# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", +sqlalchemy==1.4.16 +google-auth==1.25.0 +google-cloud-bigquery==3.3.6 +google-cloud-bigquery-storage==2.0.0 +google-api-core==1.31.5 +grpcio==1.47.0 +numpy==1.26.4 diff --git a/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py b/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py index ff14db9a..6ac2ffa0 100644 --- a/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py +++ b/tests/sqlalchemy_dialect_compliance/test_dialect_compliance.py @@ -55,8 +55,9 @@ ) from sqlalchemy.testing.suite.test_reflection import ( - BizarroCharacterFKResolutionTest, + BizarroCharacterTest, ComponentReflectionTest, + ComponentReflectionTestExtra, HasTableTest, ) @@ -615,6 +616,7 @@ def test_no_results_for_non_returning_insert(cls): pass +del ComponentReflectionTestExtra # Multiple tests re: CHECK CONSTRAINTS, etc which del ComponentReflectionTest # Multiple tests re: CHECK CONSTRAINTS, etc which # BQ does not support # class ComponentReflectionTest(_ComponentReflectionTest): @@ -629,7 +631,7 @@ def test_no_results_for_non_returning_insert(cls): # pass del ArrayTest # only appears to apply to postgresql -del BizarroCharacterFKResolutionTest +del BizarroCharacterTest del HasTableTest.test_has_table_cache # TODO confirm whether BQ has table caching del DistinctOnTest # expects unquoted table names. del HasIndexTest # BQ doesn't do the indexes that SQLA is loooking for.