From e0368e1c72328baad1722d88f60ea44a301c6810 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 21 Oct 2025 11:44:48 -0400 Subject: [PATCH 01/15] feat: Add Python 3.14 support to setup.py file --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 899cefde6..6dbea105a 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,8 @@ release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "grpcio >= 1.51.3, < 2.0.0", # https://github.com/googleapis/python-pubsub/issues/609 + "grpcio >= 1.51.3, < 2.0.0; python_version < '3.14'", # https://github.com/googleapis/python-pubsub/issues/609 + "grpcio >= 1.75.1, < 2.0.0; python_version >= '3.14'", # google-api-core >= 1.34.0 is allowed in order to support google-api-core 1.x "google-auth >= 2.14.1, <3.0.0", "google-api-core[grpc] >= 1.34.0, <3.0.0,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,!=2.10.*", @@ -88,6 +89,7 @@ "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 :: Internet", ], From d59af4abf550850292858d8254841e0aeb6cb250 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 21 Oct 2025 11:46:07 -0400 Subject: [PATCH 02/15] feat: Add constraints file for Python 3.14 --- testing/constraints-3.14.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 testing/constraints-3.14.txt diff --git a/testing/constraints-3.14.txt b/testing/constraints-3.14.txt new file mode 100644 index 000000000..1dba0484d --- /dev/null +++ b/testing/constraints-3.14.txt @@ -0,0 +1,13 @@ +# We use the constraints file for the latest Python version +# (currently this file) to check that the latest +# major versions of dependencies are supported in setup.py. +# List all library dependencies and extras in this file. +# Require the latest major version be installed for each dependency. +# e.g., if setup.py has "google-cloud-foo >= 1.14.0, < 2.0.0", +# Then this file should have google-cloud-foo>=1 +google-api-core>=2 +google-auth>=2 +proto-plus>=1 +protobuf>=6 +grpc-google-iam-v1>=0 +grpcio >= 1.75.1 From 617bd534f2169dd8039d891475a86b4c3399078d Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 21 Oct 2025 11:53:27 -0400 Subject: [PATCH 03/15] feat(ci): Add Python 3.14 to unittest workflow --- .github/workflows/unittest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index 6a0429d96..d59bbb1b8 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - python: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] + python: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - name: Checkout uses: actions/checkout@v4 From f99245b0a4025ebdbccf9de0262b1d623c27f926 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 21 Oct 2025 12:06:03 -0400 Subject: [PATCH 04/15] docs: Add Python 3.14 support to CONTRIBUTING and repo settings --- .github/sync-repo-settings.yaml | 2 ++ CONTRIBUTING.rst | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index 77c1a4fb5..bfde18cc0 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -27,4 +27,6 @@ branchProtectionRules: - 'unit (3.10)' - 'unit (3.11)' - 'unit (3.12)' + - 'unit (3.13)' + - 'unit (3.14)' - 'cover' diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index f153c3ae7..417b1e9f8 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.7, 3.8, 3.9, 3.10, 3.11, 3.12 and 3.13 on both UNIX and Windows. + 3.7, 3.8, 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 @@ -228,6 +228,7 @@ We support: - `Python 3.11`_ - `Python 3.12`_ - `Python 3.13`_ +- `Python 3.14`_ .. _Python 3.7: https://docs.python.org/3.7/ .. _Python 3.8: https://docs.python.org/3.8/ @@ -236,6 +237,7 @@ We support: .. _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`_. From 28a4f18b5ed62c9e583d39acdbc3df3004924a16 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 21 Oct 2025 12:08:49 -0400 Subject: [PATCH 05/15] chore(owlbot): Add Python 3.14 to unit test versions --- owlbot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/owlbot.py b/owlbot.py index c58e5a67a..abaf534e2 100644 --- a/owlbot.py +++ b/owlbot.py @@ -338,7 +338,7 @@ samples=True, cov_level=99, versions=gcp.common.detect_versions(path="./google", default_first=True), - unit_test_python_versions=["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], + unit_test_python_versions=["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"], unit_test_dependencies=["flaky"], system_test_python_versions=["3.12"], system_test_external_dependencies=["psutil","flaky"], From 2ac7df87a6020b6b51abc6ca6d88217ed61b9809 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 21 Oct 2025 13:20:09 -0400 Subject: [PATCH 06/15] feat(nox): Add Python 3.14 support to noxfile --- noxfile.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/noxfile.py b/noxfile.py index 70e65a571..819fe4769 100644 --- a/noxfile.py +++ b/noxfile.py @@ -44,6 +44,7 @@ "3.11", "3.12", "3.13", + "3.14", ] UNIT_TEST_STANDARD_DEPENDENCIES = [ "mock", @@ -234,7 +235,7 @@ def install_unittest_dependencies(session, *constraints): def unit(session, protobuf_implementation): # 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( @@ -325,15 +326,15 @@ def system(session): if system_test_exists: session.run( "py.test", - "--quiet", + "--verbose", f"--junitxml=system_{session.python}_sponge_log.xml", system_test_path, *session.posargs, ) - if system_test_folder_exists: + if os.path.exists(system_test_folder_path): session.run( "py.test", - "--quiet", + "--verbose", f"--junitxml=system_{session.python}_sponge_log.xml", system_test_folder_path, *session.posargs, @@ -436,7 +437,7 @@ def docfx(session): ) -@nox.session(python="3.13") +@nox.session(python="3.14") @nox.parametrize( "protobuf_implementation", ["python", "upb", "cpp"], @@ -444,7 +445,7 @@ def docfx(session): 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 @@ -542,4 +543,4 @@ def prerelease_deps(session, protobuf_implementation): env={ "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, - ) + ) \ No newline at end of file From e592d35af999f6ea49382ccddad100387a72aefb Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Tue, 21 Oct 2025 13:31:55 -0400 Subject: [PATCH 07/15] feat(samples): Add Python 3.14 to samples/snippets noxfile --- samples/snippets/noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index c9a3d1ecb..c326375be 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"] From 5b653d8191ebb299259effb61877d7598c180937 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 22 Oct 2025 08:31:53 -0400 Subject: [PATCH 08/15] fix: Adapt to changes in Python 3.14 for scheduler and type hints --- .../_protocol/streaming_pull_manager.py | 2 +- .../cloud/pubsub_v1/subscriber/scheduler.py | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/google/cloud/pubsub_v1/subscriber/_protocol/streaming_pull_manager.py b/google/cloud/pubsub_v1/subscriber/_protocol/streaming_pull_manager.py index d509d8074..5132456a2 100644 --- a/google/cloud/pubsub_v1/subscriber/_protocol/streaming_pull_manager.py +++ b/google/cloud/pubsub_v1/subscriber/_protocol/streaming_pull_manager.py @@ -458,7 +458,7 @@ def dispatcher(self) -> Optional[dispatcher.Dispatcher]: return self._dispatcher @property - def leaser(self) -> Optional[leaser.Leaser]: + def leaser(self) -> Optional["leaser.Leaser"]: """The leaser helper.""" return self._leaser diff --git a/google/cloud/pubsub_v1/subscriber/scheduler.py b/google/cloud/pubsub_v1/subscriber/scheduler.py index a3b3c88e1..0e0c2c3d6 100644 --- a/google/cloud/pubsub_v1/subscriber/scheduler.py +++ b/google/cloud/pubsub_v1/subscriber/scheduler.py @@ -21,6 +21,7 @@ import abc import concurrent.futures import queue +import sys import typing from typing import Callable, List, Optional import warnings @@ -37,7 +38,7 @@ class Scheduler(metaclass=abc.ABCMeta): @property @abc.abstractmethod - def queue(self) -> queue.Queue: # pragma: NO COVER + def queue(self) -> "queue.Queue": # pragma: NO COVER """Queue: A concurrency-safe queue specific to the underlying concurrency implementation. @@ -162,7 +163,21 @@ def shutdown( work_item = self._executor._work_queue.get(block=False) if work_item is None: # Exceutor in shutdown mode. continue - dropped_messages.append(work_item.args[0]) # type: ignore[index] + + dropped_message = None + if sys.version_info < (3, 14): + # For Python < 3.14, work_item.args is a tuple of positional arguments. + # The message is expected to be the first argument. + if hasattr(work_item, 'args') and work_item.args: + dropped_message = work_item.args[0] # type: ignore[index] + else: + # For Python >= 3.14, work_item.task is (fn, args, kwargs). + # The message is expected to be the first item in the args tuple (task[1]). + if hasattr(work_item, 'task') and len(work_item.task) == 3 and work_item.task[1]: + dropped_message = work_item.task[1][0] + + if dropped_message is not None: + dropped_messages.append(dropped_message) except queue.Empty: pass From cf75db533b4344af504739d5ff6d9301cc361ab1 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Wed, 22 Oct 2025 13:06:51 +0000 Subject: [PATCH 09/15] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-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 --- google/cloud/pubsub_v1/subscriber/scheduler.py | 8 ++++++-- noxfile.py | 16 +++++++++++++--- samples/snippets/noxfile.py | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/google/cloud/pubsub_v1/subscriber/scheduler.py b/google/cloud/pubsub_v1/subscriber/scheduler.py index 0e0c2c3d6..cc3393bd7 100644 --- a/google/cloud/pubsub_v1/subscriber/scheduler.py +++ b/google/cloud/pubsub_v1/subscriber/scheduler.py @@ -168,12 +168,16 @@ def shutdown( if sys.version_info < (3, 14): # For Python < 3.14, work_item.args is a tuple of positional arguments. # The message is expected to be the first argument. - if hasattr(work_item, 'args') and work_item.args: + if hasattr(work_item, "args") and work_item.args: dropped_message = work_item.args[0] # type: ignore[index] else: # For Python >= 3.14, work_item.task is (fn, args, kwargs). # The message is expected to be the first item in the args tuple (task[1]). - if hasattr(work_item, 'task') and len(work_item.task) == 3 and work_item.task[1]: + if ( + hasattr(work_item, "task") + and len(work_item.task) == 3 + and work_item.task[1] + ): dropped_message = work_item.task[1][0] if dropped_message is not None: diff --git a/noxfile.py b/noxfile.py index 819fe4769..7455daf83 100644 --- a/noxfile.py +++ b/noxfile.py @@ -235,7 +235,12 @@ def install_unittest_dependencies(session, *constraints): def unit(session, protobuf_implementation): # Install all test dependencies, then install this package in-place. - if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13", "3.14"): + 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( @@ -445,7 +450,12 @@ def docfx(session): 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", "3.14"): + 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 @@ -543,4 +553,4 @@ def prerelease_deps(session, protobuf_implementation): env={ "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, - ) \ No newline at end of file + ) diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index c326375be..c9a3d1ecb 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", "3.14"] +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 727c02113079cf41ddf6aa53bddefd2f14cea36b Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 22 Oct 2025 10:06:18 -0400 Subject: [PATCH 10/15] fix: Make OpenTelemetry span test more resilient --- .../publisher/test_publisher_client.py | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/tests/unit/pubsub_v1/publisher/test_publisher_client.py b/tests/unit/pubsub_v1/publisher/test_publisher_client.py index d1b7d4a81..129913569 100644 --- a/tests/unit/pubsub_v1/publisher/test_publisher_client.py +++ b/tests/unit/pubsub_v1/publisher/test_publisher_client.py @@ -308,33 +308,37 @@ def test_opentelemetry_flow_control_exception(creds, span_exporter): future2.result() spans = span_exporter.get_finished_spans() - # Span 1 = Publisher Flow Control Span of first publish - # Span 2 = Publisher Batching Span of first publish - # Span 3 = Publisher Flow Control Span of second publish(raises FlowControlLimitError) - # Span 4 = Publish Create Span of second publish(raises FlowControlLimitError) - assert len(spans) == 4 - failed_flow_control_span = spans[2] - finished_publish_create_span = spans[3] + # Find the spans related to the second, failing publish call + failed_create_span = None + failed_fc_span = None + for span in spans: + if span.name == "topicID create": + if span.status.status_code == trace.StatusCode.ERROR: + failed_create_span = span + elif span.name == "publisher flow control": + if span.status.status_code == trace.StatusCode.ERROR: + failed_fc_span = span + + assert failed_create_span is not None, "Failed 'topicID create' span not found" + assert failed_fc_span is not None, "Failed 'publisher flow control' span not found" # Verify failed flow control span values. - assert failed_flow_control_span.name == "publisher flow control" - assert failed_flow_control_span.kind == trace.SpanKind.INTERNAL + assert failed_fc_span.kind == trace.SpanKind.INTERNAL assert ( - failed_flow_control_span.parent.span_id - == finished_publish_create_span.get_span_context().span_id + failed_fc_span.parent.span_id + == failed_create_span.get_span_context().span_id ) - assert failed_flow_control_span.status.status_code == trace.StatusCode.ERROR - - assert len(failed_flow_control_span.events) == 1 - assert failed_flow_control_span.events[0].name == "exception" + assert len(failed_fc_span.events) == 1 + assert failed_fc_span.events[0].name == "exception" # Verify finished publish create span values - assert finished_publish_create_span.name == "topicID create" - assert finished_publish_create_span.status.status_code == trace.StatusCode.ERROR - assert len(finished_publish_create_span.events) == 2 - assert finished_publish_create_span.events[0].name == "publish start" - assert finished_publish_create_span.events[1].name == "exception" + assert failed_create_span.status.status_code == trace.StatusCode.ERROR + assert len(failed_create_span.events) >= 1 # Should have at least 'publish start' + assert failed_create_span.events[0].name == "publish start" + # Check for exception event + has_exception_event = any(event.name == "exception" for event in failed_create_span.events) + assert has_exception_event, "Exception event not found in failed create span" @pytest.mark.skipif( From d77a9cc4e0a90bc8d2677760973acdbff30e1d2a Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 22 Oct 2025 10:13:04 -0400 Subject: [PATCH 11/15] =?UTF-8?q?Revert=20"=F0=9F=A6=89=20Updates=20from?= =?UTF-8?q?=20OwlBot=20post-processor"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit cf75db533b4344af504739d5ff6d9301cc361ab1. --- google/cloud/pubsub_v1/subscriber/scheduler.py | 8 ++------ noxfile.py | 16 +++------------- samples/snippets/noxfile.py | 2 +- 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/google/cloud/pubsub_v1/subscriber/scheduler.py b/google/cloud/pubsub_v1/subscriber/scheduler.py index cc3393bd7..0e0c2c3d6 100644 --- a/google/cloud/pubsub_v1/subscriber/scheduler.py +++ b/google/cloud/pubsub_v1/subscriber/scheduler.py @@ -168,16 +168,12 @@ def shutdown( if sys.version_info < (3, 14): # For Python < 3.14, work_item.args is a tuple of positional arguments. # The message is expected to be the first argument. - if hasattr(work_item, "args") and work_item.args: + if hasattr(work_item, 'args') and work_item.args: dropped_message = work_item.args[0] # type: ignore[index] else: # For Python >= 3.14, work_item.task is (fn, args, kwargs). # The message is expected to be the first item in the args tuple (task[1]). - if ( - hasattr(work_item, "task") - and len(work_item.task) == 3 - and work_item.task[1] - ): + if hasattr(work_item, 'task') and len(work_item.task) == 3 and work_item.task[1]: dropped_message = work_item.task[1][0] if dropped_message is not None: diff --git a/noxfile.py b/noxfile.py index 7455daf83..819fe4769 100644 --- a/noxfile.py +++ b/noxfile.py @@ -235,12 +235,7 @@ def install_unittest_dependencies(session, *constraints): def unit(session, protobuf_implementation): # Install all test dependencies, then install this package in-place. - if protobuf_implementation == "cpp" and session.python in ( - "3.11", - "3.12", - "3.13", - "3.14", - ): + 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( @@ -450,12 +445,7 @@ def docfx(session): 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", - "3.14", - ): + 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 @@ -553,4 +543,4 @@ def prerelease_deps(session, protobuf_implementation): env={ "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, - ) + ) \ No newline at end of file diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index c9a3d1ecb..c326375be 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"] From f9b5a2f514fba1fd2a083aa863c4beadd76905d6 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Wed, 22 Oct 2025 14:15:22 +0000 Subject: [PATCH 12/15] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-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 --- google/cloud/pubsub_v1/subscriber/scheduler.py | 8 ++++++-- noxfile.py | 16 +++++++++++++--- samples/snippets/noxfile.py | 2 +- .../pubsub_v1/publisher/test_publisher_client.py | 9 +++++---- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/google/cloud/pubsub_v1/subscriber/scheduler.py b/google/cloud/pubsub_v1/subscriber/scheduler.py index 0e0c2c3d6..cc3393bd7 100644 --- a/google/cloud/pubsub_v1/subscriber/scheduler.py +++ b/google/cloud/pubsub_v1/subscriber/scheduler.py @@ -168,12 +168,16 @@ def shutdown( if sys.version_info < (3, 14): # For Python < 3.14, work_item.args is a tuple of positional arguments. # The message is expected to be the first argument. - if hasattr(work_item, 'args') and work_item.args: + if hasattr(work_item, "args") and work_item.args: dropped_message = work_item.args[0] # type: ignore[index] else: # For Python >= 3.14, work_item.task is (fn, args, kwargs). # The message is expected to be the first item in the args tuple (task[1]). - if hasattr(work_item, 'task') and len(work_item.task) == 3 and work_item.task[1]: + if ( + hasattr(work_item, "task") + and len(work_item.task) == 3 + and work_item.task[1] + ): dropped_message = work_item.task[1][0] if dropped_message is not None: diff --git a/noxfile.py b/noxfile.py index 819fe4769..7455daf83 100644 --- a/noxfile.py +++ b/noxfile.py @@ -235,7 +235,12 @@ def install_unittest_dependencies(session, *constraints): def unit(session, protobuf_implementation): # Install all test dependencies, then install this package in-place. - if protobuf_implementation == "cpp" and session.python in ("3.11", "3.12", "3.13", "3.14"): + 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( @@ -445,7 +450,12 @@ def docfx(session): 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", "3.14"): + 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 @@ -543,4 +553,4 @@ def prerelease_deps(session, protobuf_implementation): env={ "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION": protobuf_implementation, }, - ) \ No newline at end of file + ) diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index c326375be..c9a3d1ecb 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", "3.14"] +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"] diff --git a/tests/unit/pubsub_v1/publisher/test_publisher_client.py b/tests/unit/pubsub_v1/publisher/test_publisher_client.py index 129913569..651c040ba 100644 --- a/tests/unit/pubsub_v1/publisher/test_publisher_client.py +++ b/tests/unit/pubsub_v1/publisher/test_publisher_client.py @@ -326,18 +326,19 @@ def test_opentelemetry_flow_control_exception(creds, span_exporter): # Verify failed flow control span values. assert failed_fc_span.kind == trace.SpanKind.INTERNAL assert ( - failed_fc_span.parent.span_id - == failed_create_span.get_span_context().span_id + failed_fc_span.parent.span_id == failed_create_span.get_span_context().span_id ) assert len(failed_fc_span.events) == 1 assert failed_fc_span.events[0].name == "exception" # Verify finished publish create span values assert failed_create_span.status.status_code == trace.StatusCode.ERROR - assert len(failed_create_span.events) >= 1 # Should have at least 'publish start' + assert len(failed_create_span.events) >= 1 # Should have at least 'publish start' assert failed_create_span.events[0].name == "publish start" # Check for exception event - has_exception_event = any(event.name == "exception" for event in failed_create_span.events) + has_exception_event = any( + event.name == "exception" for event in failed_create_span.events + ) assert has_exception_event, "Exception event not found in failed create span" From dbd5fb18200d7450b51b13153b57f5323a3a3cb9 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 22 Oct 2025 11:25:00 -0400 Subject: [PATCH 13/15] tweaks kokoro to avoid 3.7 and 3.8 NOTE: they are covered by github actions --- .kokoro/presubmit/presubmit.cfg | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.kokoro/presubmit/presubmit.cfg b/.kokoro/presubmit/presubmit.cfg index 8f43917d9..3ed63de47 100644 --- a/.kokoro/presubmit/presubmit.cfg +++ b/.kokoro/presubmit/presubmit.cfg @@ -1 +1,6 @@ -# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "NOX_SESSION" + value: "unit-3.9 unit-3.10 unit-3.11 unit-3.12 unit-3.13 unit-3.14 system-3.12 cover lint lint_setup_py blacken mypy docs docfx format" +} From 20d1671ad14c148c2d9dba4997b993e15b2b12df Mon Sep 17 00:00:00 2001 From: Chalmer Lowe Date: Wed, 22 Oct 2025 11:53:41 -0400 Subject: [PATCH 14/15] Apply suggestion from @chalmerlowe --- .kokoro/presubmit/presubmit.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.kokoro/presubmit/presubmit.cfg b/.kokoro/presubmit/presubmit.cfg index 3ed63de47..227ccdf47 100644 --- a/.kokoro/presubmit/presubmit.cfg +++ b/.kokoro/presubmit/presubmit.cfg @@ -2,5 +2,5 @@ env_vars: { key: "NOX_SESSION" - value: "unit-3.9 unit-3.10 unit-3.11 unit-3.12 unit-3.13 unit-3.14 system-3.12 cover lint lint_setup_py blacken mypy docs docfx format" + value: "system-3.12 blacken mypy format" } From b4ab18ef8a4150112c168f271d0ff4c0a02902d4 Mon Sep 17 00:00:00 2001 From: chalmer lowe Date: Wed, 22 Oct 2025 12:44:26 -0400 Subject: [PATCH 15/15] feat(ci): Add Kokoro samples config for Python 3.14 --- .kokoro/samples/python3.14/common.cfg | 40 ++++++++++++++++++++ .kokoro/samples/python3.14/continuous.cfg | 6 +++ .kokoro/samples/python3.14/periodic-head.cfg | 11 ++++++ .kokoro/samples/python3.14/periodic.cfg | 6 +++ .kokoro/samples/python3.14/presubmit.cfg | 6 +++ 5 files changed, 69 insertions(+) create mode 100644 .kokoro/samples/python3.14/common.cfg create mode 100644 .kokoro/samples/python3.14/continuous.cfg create mode 100644 .kokoro/samples/python3.14/periodic-head.cfg create mode 100644 .kokoro/samples/python3.14/periodic.cfg create mode 100644 .kokoro/samples/python3.14/presubmit.cfg diff --git a/.kokoro/samples/python3.14/common.cfg b/.kokoro/samples/python3.14/common.cfg new file mode 100644 index 000000000..f6feff705 --- /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-pubsub/.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-pubsub/.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 000000000..b19681787 --- /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" +} diff --git a/.kokoro/samples/python3.14/periodic-head.cfg b/.kokoro/samples/python3.14/periodic-head.cfg new file mode 100644 index 000000000..f9cfcd33e --- /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-pubsub/.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 000000000..71cd1e597 --- /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 000000000..b19681787 --- /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" +}