From 6f11d53fa50184912cb8afa613474271e1a9dd6f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 14:07:43 +0000 Subject: [PATCH 1/9] feat: remove python 3.8 support --- .github/sync-repo-settings.yaml | 1 - .kokoro/samples/python3.8/common.cfg | 40 --------------------- .kokoro/samples/python3.8/continuous.cfg | 6 ---- .kokoro/samples/python3.8/periodic-head.cfg | 11 ------ .kokoro/samples/python3.8/periodic.cfg | 6 ---- .kokoro/samples/python3.8/presubmit.cfg | 6 ---- CONTRIBUTING.rst | 12 +++---- README.rst | 2 +- noxfile.py | 20 +++-------- owlbot.py | 5 ++- samples/snippets/noxfile.py | 2 +- samples/snippets/requirements-test.txt | 3 -- samples/snippets/requirements.txt | 13 ------- testing/constraints-3.8.txt | 13 ------- 14 files changed, 13 insertions(+), 127 deletions(-) delete mode 100644 .kokoro/samples/python3.8/common.cfg delete mode 100644 .kokoro/samples/python3.8/continuous.cfg delete mode 100644 .kokoro/samples/python3.8/periodic-head.cfg delete mode 100644 .kokoro/samples/python3.8/periodic.cfg delete mode 100644 .kokoro/samples/python3.8/presubmit.cfg delete mode 100644 testing/constraints-3.8.txt 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.8/common.cfg b/.kokoro/samples/python3.8/common.cfg deleted file mode 100644 index e8cc035c..00000000 --- a/.kokoro/samples/python3.8/common.cfg +++ /dev/null @@ -1,40 +0,0 @@ -# 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.8" -} - -# Declare build specific Cloud project. -env_vars: { - key: "BUILD_SPECIFIC_GCLOUD_PROJECT" - value: "python-docs-samples-tests-py38" -} - -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" \ No newline at end of file diff --git a/.kokoro/samples/python3.8/continuous.cfg b/.kokoro/samples/python3.8/continuous.cfg deleted file mode 100644 index a1c8d975..00000000 --- a/.kokoro/samples/python3.8/continuous.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# 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.8/periodic-head.cfg b/.kokoro/samples/python3.8/periodic-head.cfg deleted file mode 100644 index abf3481d..00000000 --- a/.kokoro/samples/python3.8/periodic-head.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# 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.8/periodic.cfg b/.kokoro/samples/python3.8/periodic.cfg deleted file mode 100644 index 71cd1e59..00000000 --- a/.kokoro/samples/python3.8/periodic.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "INSTALL_LIBRARY_FROM_SOURCE" - value: "False" -} diff --git a/.kokoro/samples/python3.8/presubmit.cfg b/.kokoro/samples/python3.8/presubmit.cfg deleted file mode 100644 index a1c8d975..00000000 --- a/.kokoro/samples/python3.8/presubmit.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# 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/CONTRIBUTING.rst b/CONTRIBUTING.rst index 2f03f9d0..51eb8676 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, and 3.13 on both UNIX and Windows. - The feature must not add unnecessary dependencies (where "unnecessary" is of course subjective, but new dependencies should @@ -148,7 +148,7 @@ Running System Tests .. 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.12, and 3.13. 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,14 +221,12 @@ 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.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/ @@ -241,7 +239,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..87e1653a 100644 --- a/noxfile.py +++ b/noxfile.py @@ -39,9 +39,9 @@ "setup.py", ] -DEFAULT_PYTHON_VERSION = "3.8" +DEFAULT_PYTHON_VERSION = "3.9" -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"] UNIT_TEST_STANDARD_DEPENDENCIES = [ "mock", "asyncmock", @@ -56,11 +56,6 @@ "tests", ] UNIT_TEST_EXTRAS_BY_PYTHON: Dict[str, List[str]] = { - "3.8": [ - "tests", - "alembic", - "bqstorage", - ], "3.11": [ "tests", "geography", @@ -78,7 +73,7 @@ ], } -SYSTEM_TEST_PYTHON_VERSIONS: List[str] = ["3.8", "3.12", "3.13"] +SYSTEM_TEST_PYTHON_VERSIONS: List[str] = ["3.12", "3.13"] SYSTEM_TEST_STANDARD_DEPENDENCIES: List[str] = [ "mock", "pytest", @@ -91,11 +86,6 @@ "tests", ] SYSTEM_TEST_EXTRAS_BY_PYTHON: Dict[str, List[str]] = { - "3.8": [ - "tests", - "alembic", - "bqstorage", - ], "3.12": [ "tests", "geography", @@ -398,9 +388,7 @@ def compliance(session): "-c", constraints_path, ) - if session.python == "3.8": - extras = "[tests,alembic]" - elif session.python in ["3.12", "3.13"]: + if session.python in ["3.12", "3.13"]: extras = "[tests,geography]" else: extras = "[tests]" diff --git a/owlbot.py b/owlbot.py index 5173dce0..c9512594 100644 --- a/owlbot.py +++ b/owlbot.py @@ -30,14 +30,13 @@ # ---------------------------------------------------------------------------- extras = ["tests"] extras_by_python = { - "3.8": ["tests", "alembic", "bqstorage"], "3.11": ["tests", "geography", "bqstorage"], "3.12": ["tests", "geography", "bqstorage"], "3.13": ["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"], + system_test_python_versions=["3.12", "3.13"], cov_level=100, unit_test_extras=extras, unit_test_extras_by_python=extras_by_python, diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index e5885544..10ecc88e 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.9", "3.10", "3.11", "3.12", "3.13"] # 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 d31b0a4e..de552810 100644 --- a/samples/snippets/requirements-test.txt +++ b/samples/snippets/requirements-test.txt @@ -5,16 +5,13 @@ google-auth==2.40.3 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' 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.1; python_version >= '3.9' diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index a98926e2..9fb5e6cf 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1,37 +1,26 @@ -alembic===1.14.0; python_version == '3.8' alembic==1.16.4; python_version >= '3.9' certifi==2025.7.14 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.35.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.1; python_version >= '3.9' -grpcio-status===1.68.0; python_version == '3.8' grpcio-status==1.73.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' packaging==25.0 proto-plus==1.26.1 -protobuf===5.28.3; python_version == '3.8' protobuf==6.31.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' python-dateutil==2.9.0.post0 pytz==2025.2 @@ -41,7 +30,5 @@ shapely===2.0.7; python_version <= '3.9' shapely==2.1.1; 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.1; python_version >= '3.9' -urllib3===2.2.3; python_version == '3.8' urllib3==2.5.0; python_version >= '3.9' 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 From 4e86c0446c30d4e88e644d04f7a7c30581f2e47d Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 23 Jul 2025 12:05:38 +0000 Subject: [PATCH 2/9] adds debugging to noxfile and tweaks to correct coverage --- noxfile.py | 46 +++++++++++++++++++++++++++++++++ setup.py | 2 +- sqlalchemy_bigquery/__init__.py | 10 ++++--- testing/constraints-3.9.txt | 14 ++++++++++ 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/noxfile.py b/noxfile.py index 87e1653a..90165ed9 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 @@ -100,6 +102,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", @@ -118,6 +141,7 @@ @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def lint(session): """Run linters. @@ -125,6 +149,7 @@ def lint(session): serious code quality issues. """ session.install(FLAKE8_VERSION, BLACK_VERSION) + session.run("python", "-m", "pip", "freeze") session.run( "black", "--check", @@ -134,9 +159,11 @@ 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) + session.run("python", "-m", "pip", "freeze") session.run( "black", *LINT_PATHS, @@ -144,6 +171,7 @@ def blacken(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def format(session): """ Run isort to sort imports. Then run black @@ -152,6 +180,7 @@ def format(session): session.install(BLACK_VERSION, ISORT_VERSION) # Use the --fss option to sort imports using strict alphabetical order. # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections + session.run("python", "-m", "pip", "freeze") session.run( "isort", "--fss", @@ -164,9 +193,11 @@ 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.run("python", "-m", "pip", "freeze") session.run("python", "setup.py", "check", "--restructuredtext", "--strict") @@ -203,6 +234,7 @@ 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. @@ -229,6 +261,7 @@ def unit(session, protobuf_implementation, install_extras=True): session.install("protobuf<4") # Run py.test against the unit tests. + session.run("python", "-m", "pip", "freeze") session.run( "py.test", "--quiet", @@ -278,6 +311,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( @@ -300,6 +334,7 @@ def system(session): session.skip("System tests were not found") install_systemtest_dependencies(session, "-c", constraints_path) + session.run("python", "-m", "pip", "freeze") # Run py.test against the system tests. if system_test_exists: @@ -321,6 +356,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( @@ -345,6 +381,7 @@ def system_noextras(session): global SYSTEM_TEST_EXTRAS_BY_PYTHON SYSTEM_TEST_EXTRAS_BY_PYTHON = False install_systemtest_dependencies(session, "-c", constraints_path) + session.run("python", "-m", "pip", "freeze") # Run py.test against the system tests. if system_test_exists: @@ -366,6 +403,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( @@ -418,6 +456,7 @@ def compliance(session): @nox.session(python=DEFAULT_PYTHON_VERSION) +@_calculate_duration def cover(session): """Run the final coverage report. @@ -425,12 +464,14 @@ def cover(session): test runs (not system test runs), and then erases coverage data. """ session.install("coverage", "pytest-cov") + session.run("python", "-m", "pip", "freeze") session.run("coverage", "report", "--show-missing", "--fail-under=100") session.run("coverage", "erase") @nox.session(python="3.10") +@_calculate_duration def docs(session): """Build the docs for this library.""" @@ -453,6 +494,7 @@ def docs(session): ) shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) + session.run("python", "-m", "pip", "freeze") session.run( "sphinx-build", "-W", # warnings as errors @@ -468,6 +510,7 @@ def docs(session): @nox.session(python="3.10") +@_calculate_duration def docfx(session): """Build the docfx yaml files for this library.""" @@ -490,6 +533,7 @@ def docfx(session): ) shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) + session.run("python", "-m", "pip", "freeze") session.run( "sphinx-build", "-T", # show full traceback on exception @@ -520,6 +564,7 @@ def docfx(session): "protobuf_implementation", ["python", "upb", "cpp"], ) +@_calculate_duration def prerelease_deps(session, protobuf_implementation): """Run all tests with prerelease versions of dependencies installed.""" @@ -581,6 +626,7 @@ def prerelease_deps(session, protobuf_implementation): "requests", ] session.install(*other_deps) + session.run("python", "-m", "pip", "freeze") # Print out prerelease package versions session.run( diff --git a/setup.py b/setup.py index 6d6c814a..472c8fa0 100644 --- a/setup.py +++ b/setup.py @@ -62,7 +62,7 @@ def readme(): # 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", + "pyarrow >= 5.0.0", ], } diff --git a/sqlalchemy_bigquery/__init__.py b/sqlalchemy_bigquery/__init__.py index 1e506125..a8c9c139 100644 --- a/sqlalchemy_bigquery/__init__.py +++ b/sqlalchemy_bigquery/__init__.py @@ -48,14 +48,16 @@ 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/testing/constraints-3.9.txt b/testing/constraints-3.9.txt index e69de29b..ca2062ca 100644 --- a/testing/constraints-3.9.txt +++ b/testing/constraints-3.9.txt @@ -0,0 +1,14 @@ +# 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 +pyarrow==5.0.0 \ No newline at end of file From 21fb2aec6a0b1ef1cfe5d85fe2b70355fe20574a Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 23 Jul 2025 12:13:26 +0000 Subject: [PATCH 3/9] updates lowest version for system test and owlbot --- noxfile.py | 2 +- owlbot.py | 2 +- samples/snippets/noxfile.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/noxfile.py b/noxfile.py index 90165ed9..9ef04fa4 100644 --- a/noxfile.py +++ b/noxfile.py @@ -75,7 +75,7 @@ ], } -SYSTEM_TEST_PYTHON_VERSIONS: List[str] = ["3.12", "3.13"] +SYSTEM_TEST_PYTHON_VERSIONS: List[str] = ["3.9", "3.12", "3.13"] SYSTEM_TEST_STANDARD_DEPENDENCIES: List[str] = [ "mock", "pytest", diff --git a/owlbot.py b/owlbot.py index c9512594..ff4ec518 100644 --- a/owlbot.py +++ b/owlbot.py @@ -36,7 +36,7 @@ } templated_files = common.py_library( unit_test_python_versions=["3.9", "3.10", "3.11", "3.12", "3.13"], - system_test_python_versions=["3.12", "3.13"], + system_test_python_versions=["3.9", "3.12", "3.13"], cov_level=100, unit_test_extras=extras, unit_test_extras_by_python=extras_by_python, diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index 10ecc88e..90dd62a2 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.9", "3.10", "3.11", "3.12", "3.13"] +ALL_VERSIONS = ["3.9", "3.10", "3.11", "3.12", "3.13"] # Any default versions that should be ignored. IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] From a8fa9532fa0a6e85b5fb45fd7e7d75534aec0380 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 23 Jul 2025 15:14:53 +0000 Subject: [PATCH 4/9] updates DEFAULT_PYTHON_VERSION to 3.10 --- noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 9ef04fa4..1be76a93 100644 --- a/noxfile.py +++ b/noxfile.py @@ -41,7 +41,7 @@ "setup.py", ] -DEFAULT_PYTHON_VERSION = "3.9" +DEFAULT_PYTHON_VERSION = "3.10" UNIT_TEST_PYTHON_VERSIONS: List[str] = ["3.9", "3.10", "3.11", "3.12", "3.13"] UNIT_TEST_STANDARD_DEPENDENCIES = [ From a00b3782d8684611f34b104b4385c3d15cd168ae Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Wed, 23 Jul 2025 15:16:59 +0000 Subject: [PATCH 5/9] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20po?= =?UTF-8?q?st-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .kokoro/samples/python3.8/common.cfg | 40 +++++++++++++++++++++ .kokoro/samples/python3.8/continuous.cfg | 6 ++++ .kokoro/samples/python3.8/periodic-head.cfg | 11 ++++++ .kokoro/samples/python3.8/periodic.cfg | 6 ++++ .kokoro/samples/python3.8/presubmit.cfg | 6 ++++ samples/snippets/noxfile.py | 2 +- 6 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 .kokoro/samples/python3.8/common.cfg create mode 100644 .kokoro/samples/python3.8/continuous.cfg create mode 100644 .kokoro/samples/python3.8/periodic-head.cfg create mode 100644 .kokoro/samples/python3.8/periodic.cfg create mode 100644 .kokoro/samples/python3.8/presubmit.cfg diff --git a/.kokoro/samples/python3.8/common.cfg b/.kokoro/samples/python3.8/common.cfg new file mode 100644 index 00000000..e8cc035c --- /dev/null +++ b/.kokoro/samples/python3.8/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.8" +} + +# Declare build specific Cloud project. +env_vars: { + key: "BUILD_SPECIFIC_GCLOUD_PROJECT" + value: "python-docs-samples-tests-py38" +} + +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" \ No newline at end of file diff --git a/.kokoro/samples/python3.8/continuous.cfg b/.kokoro/samples/python3.8/continuous.cfg new file mode 100644 index 00000000..a1c8d975 --- /dev/null +++ b/.kokoro/samples/python3.8/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.8/periodic-head.cfg b/.kokoro/samples/python3.8/periodic-head.cfg new file mode 100644 index 00000000..abf3481d --- /dev/null +++ b/.kokoro/samples/python3.8/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.8/periodic.cfg b/.kokoro/samples/python3.8/periodic.cfg new file mode 100644 index 00000000..71cd1e59 --- /dev/null +++ b/.kokoro/samples/python3.8/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.8/presubmit.cfg b/.kokoro/samples/python3.8/presubmit.cfg new file mode 100644 index 00000000..a1c8d975 --- /dev/null +++ b/.kokoro/samples/python3.8/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/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index 90dd62a2..e5885544 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.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"] # Any default versions that should be ignored. IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] From a9881faf49b52d8dd1ea6e817982c99a57cafe0b Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 24 Jul 2025 11:19:45 +0000 Subject: [PATCH 6/9] updates extras in several sessions & lists additional Python ver. --- CONTRIBUTING.rst | 2 +- noxfile.py | 2 +- owlbot.py | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 51eb8676..538a10eb 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -148,7 +148,7 @@ Running System Tests .. note:: - System tests are only configured to run under Python 3.12, and 3.13. + System tests are only configured to run under Python 3.9, 3.12, and 3.13. 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 diff --git a/noxfile.py b/noxfile.py index 1be76a93..a754abaa 100644 --- a/noxfile.py +++ b/noxfile.py @@ -427,7 +427,7 @@ def compliance(session): constraints_path, ) if session.python in ["3.12", "3.13"]: - extras = "[tests,geography]" + extras = "[tests,geography,alembic]" else: extras = "[tests]" session.install("-e", f".{extras}", "-c", constraints_path) diff --git a/owlbot.py b/owlbot.py index ff4ec518..a8e359fe 100644 --- a/owlbot.py +++ b/owlbot.py @@ -30,6 +30,7 @@ # ---------------------------------------------------------------------------- extras = ["tests"] extras_by_python = { + "3.9": ["tests", "alembic", "bqstorage"], "3.11": ["tests", "geography", "bqstorage"], "3.12": ["tests", "geography", "bqstorage"], "3.13": ["tests", "geography", "bqstorage"], From 8af7c47657441417f7bbb0ffa48091c8a8e0bd5a Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 24 Jul 2025 15:01:03 +0000 Subject: [PATCH 7/9] Revert "adds debugging to noxfile and tweaks to correct coverage" This reverts commit 4e86c0446c30d4e88e644d04f7a7c30581f2e47d. --- noxfile.py | 46 --------------------------------- setup.py | 2 +- sqlalchemy_bigquery/__init__.py | 10 +++---- testing/constraints-3.9.txt | 14 ---------- 4 files changed, 5 insertions(+), 67 deletions(-) diff --git a/noxfile.py b/noxfile.py index a754abaa..8fb2e70b 100644 --- a/noxfile.py +++ b/noxfile.py @@ -18,12 +18,10 @@ 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 @@ -102,27 +100,6 @@ 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", @@ -141,7 +118,6 @@ def wrapper(*args, **kwargs): @nox.session(python=DEFAULT_PYTHON_VERSION) -@_calculate_duration def lint(session): """Run linters. @@ -149,7 +125,6 @@ def lint(session): serious code quality issues. """ session.install(FLAKE8_VERSION, BLACK_VERSION) - session.run("python", "-m", "pip", "freeze") session.run( "black", "--check", @@ -159,11 +134,9 @@ 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) - session.run("python", "-m", "pip", "freeze") session.run( "black", *LINT_PATHS, @@ -171,7 +144,6 @@ def blacken(session): @nox.session(python=DEFAULT_PYTHON_VERSION) -@_calculate_duration def format(session): """ Run isort to sort imports. Then run black @@ -180,7 +152,6 @@ def format(session): session.install(BLACK_VERSION, ISORT_VERSION) # Use the --fss option to sort imports using strict alphabetical order. # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections - session.run("python", "-m", "pip", "freeze") session.run( "isort", "--fss", @@ -193,11 +164,9 @@ 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.run("python", "-m", "pip", "freeze") session.run("python", "setup.py", "check", "--restructuredtext", "--strict") @@ -234,7 +203,6 @@ 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. @@ -261,7 +229,6 @@ def unit(session, protobuf_implementation, install_extras=True): session.install("protobuf<4") # Run py.test against the unit tests. - session.run("python", "-m", "pip", "freeze") session.run( "py.test", "--quiet", @@ -311,7 +278,6 @@ 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( @@ -334,7 +300,6 @@ def system(session): session.skip("System tests were not found") install_systemtest_dependencies(session, "-c", constraints_path) - session.run("python", "-m", "pip", "freeze") # Run py.test against the system tests. if system_test_exists: @@ -356,7 +321,6 @@ def system(session): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) -@_calculate_duration def system_noextras(session): """Run the system test suite.""" constraints_path = str( @@ -381,7 +345,6 @@ def system_noextras(session): global SYSTEM_TEST_EXTRAS_BY_PYTHON SYSTEM_TEST_EXTRAS_BY_PYTHON = False install_systemtest_dependencies(session, "-c", constraints_path) - session.run("python", "-m", "pip", "freeze") # Run py.test against the system tests. if system_test_exists: @@ -403,7 +366,6 @@ 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( @@ -456,7 +418,6 @@ def compliance(session): @nox.session(python=DEFAULT_PYTHON_VERSION) -@_calculate_duration def cover(session): """Run the final coverage report. @@ -464,14 +425,12 @@ def cover(session): test runs (not system test runs), and then erases coverage data. """ session.install("coverage", "pytest-cov") - session.run("python", "-m", "pip", "freeze") session.run("coverage", "report", "--show-missing", "--fail-under=100") session.run("coverage", "erase") @nox.session(python="3.10") -@_calculate_duration def docs(session): """Build the docs for this library.""" @@ -494,7 +453,6 @@ def docs(session): ) shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) - session.run("python", "-m", "pip", "freeze") session.run( "sphinx-build", "-W", # warnings as errors @@ -510,7 +468,6 @@ def docs(session): @nox.session(python="3.10") -@_calculate_duration def docfx(session): """Build the docfx yaml files for this library.""" @@ -533,7 +490,6 @@ def docfx(session): ) shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) - session.run("python", "-m", "pip", "freeze") session.run( "sphinx-build", "-T", # show full traceback on exception @@ -564,7 +520,6 @@ def docfx(session): "protobuf_implementation", ["python", "upb", "cpp"], ) -@_calculate_duration def prerelease_deps(session, protobuf_implementation): """Run all tests with prerelease versions of dependencies installed.""" @@ -626,7 +581,6 @@ def prerelease_deps(session, protobuf_implementation): "requests", ] session.install(*other_deps) - session.run("python", "-m", "pip", "freeze") # Print out prerelease package versions session.run( diff --git a/setup.py b/setup.py index 472c8fa0..6d6c814a 100644 --- a/setup.py +++ b/setup.py @@ -62,7 +62,7 @@ def readme(): # 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 >= 5.0.0", + "pyarrow >= 3.0.0", ], } diff --git a/sqlalchemy_bigquery/__init__.py b/sqlalchemy_bigquery/__init__.py index a8c9c139..1e506125 100644 --- a/sqlalchemy_bigquery/__init__.py +++ b/sqlalchemy_bigquery/__init__.py @@ -48,16 +48,14 @@ from . import _versions_helpers sys_major, sys_minor, sys_micro = _versions_helpers.extract_runtime_version() -# 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 +if sys_major == 3 and sys_minor in (7, 8): warnings.warn( - "The python-bigquery-sqlalchemy library no longer supports Python 3.7 " - "and Python 3.8. " + "The python-bigquery library will stop supporting Python 3.7 " + "and Python 3.8 in a future major release expected in Q4 2024. " 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)", - FutureWarning, + PendingDeprecationWarning, ) diff --git a/testing/constraints-3.9.txt b/testing/constraints-3.9.txt index ca2062ca..e69de29b 100644 --- a/testing/constraints-3.9.txt +++ b/testing/constraints-3.9.txt @@ -1,14 +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 -numpy==1.26.4 -pyarrow==5.0.0 \ No newline at end of file From 762a46d5685aec3c4d6f22b715780c5b7853a3ac Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 24 Jul 2025 15:05:47 +0000 Subject: [PATCH 8/9] adds back in code that was removed --- setup.py | 2 +- sqlalchemy_bigquery/__init__.py | 9 ++++++--- testing/constraints-3.9.txt | 13 +++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 6d6c814a..472c8fa0 100644 --- a/setup.py +++ b/setup.py @@ -62,7 +62,7 @@ def readme(): # 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", + "pyarrow >= 5.0.0", ], } diff --git a/sqlalchemy_bigquery/__init__.py b/sqlalchemy_bigquery/__init__.py index 1e506125..54d2f5d4 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() + +# 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): 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/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 From e50cad3063528c3ec0a699df4d61164632148a37 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Thu, 24 Jul 2025 16:20:38 +0000 Subject: [PATCH 9/9] adds pragma to avoid cover fallure. --- sqlalchemy_bigquery/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlalchemy_bigquery/__init__.py b/sqlalchemy_bigquery/__init__.py index 54d2f5d4..373c4861 100644 --- a/sqlalchemy_bigquery/__init__.py +++ b/sqlalchemy_bigquery/__init__.py @@ -51,7 +51,7 @@ # 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): +if sys_major == 3 and sys_minor in (7, 8): # pragma: NO COVER warnings.warn( "The python-bigquery-sqlalchemy library no longer supports Python 3.7 " "and Python 3.8. "