Repository navigation
Conversation
The generated BidiReadObject stub parses every response with proto-plus over upb, which copies each data chunk twice on the event-loop thread before it reaches the caller's buffer. Add a wire-format parser for plain data responses that exposes `checksummed_data.content` as a memoryview of the received message, and let `_AsyncReadObjectStream` use a stub built with it (wrapped like the generated method: error mapping, no default retry or timeout, same client-info header). Responses carrying object metadata, or anything that does not parse cleanly, are handed to the generated parser, so callers keep seeing the real message or its usual DecodeError. CRC32C verification in the read path is unchanged: the memoryview flows through google_crc32c.value(), the user buffer write and the rolling checksum. Because google-crc32c releases up to 1.9.0 only accept bytes there, the fast path is used only when the installed google-crc32c can checksum a memoryview; GOOGLE_CLOUD_STORAGE_FAST_BIDI_READ=0 forces the generated parser as well.
…sages and invalid tags The zero-copy BidiReadObjectResponse parser is meant to be indistinguishable from the generated one apart from the type of ``content``; a comparison against upb found a few places where it was not: - ReadRange.read_offset/read_length/read_id are int64, so a ten-byte two's-complement varint must come back negative, and bits above 64 in an over-long varint are dropped rather than kept. - A singular embedded message that occurs twice in its parent is merged; the sub-message parsers now fill in the existing object, which also removes two throw-away allocations per ObjectRangeData. - Field number 0, tags above 32 bits and tags encoded in more than five bytes are malformed and now reach the generated parser's DecodeError. Tests cover each case against the generated parser.
…c write microbenchmarks (googleapis#18511) ## Description Passes `storage_class="RAPID"` (when `RUN_RCU_SYSTEM_TESTS=True`) and `finalize_on_close=True` to `AsyncAppendableObjectWriter` in `upload_chunks_using_grpc_async` in microbenchmarks writes.
…googleapis#18543) Previously, Resumable Uploads would only accept the request_body as part of the `upload` method. Now, it can also be passed in the constructor, to serve as a default value
…eapis#18542) This PR allows AsyncAuthorizedSession to support standard credential types by wrapping them in an adapter --------- Co-authored-by: Anthonios Partheniou <partheniou@google.com>
…e uploads (googleapis#18544) Currently, resumable uploads only support `aiohttp.ClientSession`. Gapic clients use `AsyncAuthorizedSession` instead. This PR refactors the implementation to support both options --------- Co-authored-by: Anthonios Partheniou <partheniou@google.com>
🤖 I have created a release *beep* *boop* --- ## [2.60.0](googleapis/google-cloud-python@google-auth-v2.59.1...google-auth-v2.60.0) (2026-10-02) ### Features * **auth:** Support sync credentials in AsyncAuthorizedSession ([googleapis#18542](googleapis#18542)) ([3799568](googleapis@3799568)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
🤖 I have created a release *beep* *boop* --- <details><summary>google-api-core: 2.41.0</summary> ## [2.41.0](googleapis/google-cloud-python@google-api-core-v2.40.0...google-api-core-v2.41.0) (2026-10-02) ### Features * **api_core:** resumable upload supports request_body in constructor ([googleapis#18543](googleapis#18543)) ([97bc619](googleapis@97bc619)) * **api-core:** support AsyncAuthorizedSession transport for resumable uploads ([googleapis#18544](googleapis#18544)) ([9b96af7](googleapis@9b96af7)) * **auth:** Support sync credentials in AsyncAuthorizedSession ([googleapis#18542](googleapis#18542)) ([3799568](googleapis@3799568)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
…le uploads (googleapis#18495) - Add client, transport, and unit test template support for resumable upload RPCs. - Resumable upload methods accept an optional `ResumableUploadConfig` on the client and return `ResumableUploadSession` / `AsyncResumableUploadSession` from `google.api_core.resumable_transfer`. Since resumable uploads use HTTP, the gRPC and gRPC-async transports delegate resumable upload calls to the corresponding REST transport.
googleapis#18501) - Add sample generation support for resumable upload RPCs. - Generated sync and async snippets demonstrate creating an upload session with `ResumableUploadConfig`, uploading a stream directly, iterating over `UploadProgress` updates per chunk, and resuming an interrupted upload from a saved session URL.
…ptor (googleapis#18581) Fix an issue where async streaming RPCs were incorrectly wrapped in _AsyncUnaryResponseWrapper instead of _AsyncStreamingResponseWrapper, preventing metrics from being properly recorded. #### Problem In grpc.aio, streaming call objects (like UnaryStreamCall) implement `__aiter__` (returning an async generator) but do not define `__anext__` directly on the call object itself. Because AsyncMetricsInterceptor checked `hasattr(response, "__anext__")`, all async streaming calls (such as ExecuteStreamingSql and StreamingRead) were misclassified as unary calls and wrapped in _AsyncUnaryResponseWrapper. Because _AsyncUnaryResponseWrapper only records metrics when awaited (`__await__`), and callers iterate over streams chunk-by-chunk rather than awaiting the stream object itself: 1. Frontend metrics (gfe_latencies, afe_latencies, and missing header counts) were never recorded for any async queries or streaming reads. 2. Attempt completion was never recorded when the stream finished. Instead, it was only recorded much later when the wrapper was garbage-collected (`__del__`), resulting in wildly inflated attempt latency measurements or attempts incorrectly reporting as CANCELLED. #### Solution - Explicitly dispatch async interceptor wrappers based on the gRPC call type (is_streaming=True for intercept_unary_stream and intercept_stream_stream) rather than fragile runtime dunder checks. - Realign class inheritance so StreamUnaryCall is handled by _AsyncUnaryResponseWrapper, adding write() and done_writing() delegation. - Support sending real HTTP/2 response headers in the in-memory mock Spanner server via an add_header() helper, removing monkeypatching of internal gRPC classes in integration tests. - Add unit tests for direct `__anext__()` consumption (matching StreamedResultSet), delegation methods, error handling, and sync/async response wrappers.
) This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [pytest](https://redirect.github.com/pytest-dev/pytest) ([changelog](https://docs.pytest.org/en/stable/changelog.html)) | `==8.4.2` → `==9.0.3` |  |  | | [pytest](https://redirect.github.com/pytest-dev/pytest) ([changelog](https://docs.pytest.org/en/stable/changelog.html)) | `==8.3.5` → `==9.0.3` |  |  | | [pytest](https://redirect.github.com/pytest-dev/pytest) ([changelog](https://docs.pytest.org/en/stable/changelog.html)) | `==7.4.3` → `==9.0.3` |  |  | --- ### pytest has vulnerable tmpdir handling [CVE-2025-71176](https://nvd.nist.gov/vuln/detail/CVE-2025-71176) / [GHSA-6w46-j5rx-g56g](https://redirect.github.com/advisories/GHSA-6w46-j5rx-g56g) <details> <summary>More information</summary> #### Details pytest through 9.0.2 on UNIX relies on directories with the `/tmp/pytest-of-{user}` name pattern, which allows local users to cause a denial of service or possibly gain privileges. #### Severity - CVSS Score: 6.8 / 10 (Medium) - Vector String: `CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L` #### References - [https://nvd.nist.gov/vuln/detail/CVE-2025-71176](https://nvd.nist.gov/vuln/detail/CVE-2025-71176) - [https://github.com/pytest-dev/pytest/issues/13669](https://redirect.github.com/pytest-dev/pytest/issues/13669) - [https://www.openwall.com/lists/oss-security/2026/01/21/5](https://www.openwall.com/lists/oss-security/2026/01/21/5) - [https://github.com/pytest-dev/pytest/pull/14343](https://redirect.github.com/pytest-dev/pytest/pull/14343) - [https://github.com/pytest-dev/pytest/commit/95d8423bd24992deea5b9df32555fa1741679e2c](https://redirect.github.com/pytest-dev/pytest/commit/95d8423bd24992deea5b9df32555fa1741679e2c) - [https://github.com/pytest-dev/pytest/releases/tag/9.0.3](https://redirect.github.com/pytest-dev/pytest/releases/tag/9.0.3) - [https://github.com/advisories/GHSA-6w46-j5rx-g56g](https://redirect.github.com/advisories/GHSA-6w46-j5rx-g56g) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-6w46-j5rx-g56g) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Release Notes <details> <summary>pytest-dev/pytest (pytest)</summary> ### [`v9.0.3`](https://redirect.github.com/pytest-dev/pytest/releases/tag/9.0.3) [Compare Source](https://redirect.github.com/pytest-dev/pytest/compare/9.0.2...9.0.3) ### pytest 9.0.3 (2026-04-07) #### Bug fixes - [#&googleapis#8203;12444](https://redirect.github.com/pytest-dev/pytest/issues/12444): Fixed `pytest.approx` which now correctly takes into account `~collections.abc.Mapping` keys order to compare them. - [#&googleapis#8203;13634](https://redirect.github.com/pytest-dev/pytest/issues/13634): Blocking a `conftest.py` file using the `-p no:` option is now explicitly disallowed. Previously this resulted in an internal assertion failure during plugin loading. Pytest now raises a clear `UsageError` explaining that conftest files are not plugins and cannot be disabled via `-p`. - [#&googleapis#8203;13734](https://redirect.github.com/pytest-dev/pytest/issues/13734): Fixed crash when a test raises an exceptiongroup with `__tracebackhide__ = True`. - [#&googleapis#8203;14195](https://redirect.github.com/pytest-dev/pytest/issues/14195): Fixed an issue where non-string messages passed to <span class="title-ref">unittest.TestCase.subTest()</span> were not printed. - [#&googleapis#8203;14343](https://redirect.github.com/pytest-dev/pytest/issues/14343): Fixed use of insecure temporary directory (CVE-2025-71176). #### Improved documentation - [#&googleapis#8203;13388](https://redirect.github.com/pytest-dev/pytest/issues/13388): Clarified documentation for `-p` vs `PYTEST_PLUGINS` plugin loading and fixed an incorrect `-p` example. - [#&googleapis#8203;13731](https://redirect.github.com/pytest-dev/pytest/issues/13731): Clarified that capture fixtures (e.g. `capsys` and `capfd`) take precedence over the `-s` / `--capture=no` command-line options in `Accessing captured output from a test function <accessing-captured-output>`. - [#&googleapis#8203;14088](https://redirect.github.com/pytest-dev/pytest/issues/14088): Clarified that the default `pytest_collection` hook sets `session.items` before it calls `pytest_collection_finish`, not after. - [#&googleapis#8203;14255](https://redirect.github.com/pytest-dev/pytest/issues/14255): TOML integer log levels must be quoted: Updating reference documentation. #### Contributor-facing changes - [#&googleapis#8203;12689](https://redirect.github.com/pytest-dev/pytest/issues/12689): The test reports are now published to Codecov from GitHub Actions. The test statistics is visible [on the web interface](https://app.codecov.io/gh/pytest-dev/pytest/tests). \-- by `aleguy02` ### [`v9.0.2`](https://redirect.github.com/pytest-dev/pytest/releases/tag/9.0.2) [Compare Source](https://redirect.github.com/pytest-dev/pytest/compare/9.0.1...9.0.2) ### pytest 9.0.2 (2025-12-06) #### Bug fixes - [#&googleapis#8203;13896](https://redirect.github.com/pytest-dev/pytest/issues/13896): The terminal progress feature added in pytest 9.0.0 has been disabled by default, except on Windows, due to compatibility issues with some terminal emulators. You may enable it again by passing `-p terminalprogress`. We may enable it by default again once compatibility improves in the future. Additionally, when the environment variable `TERM` is `dumb`, the escape codes are no longer emitted, even if the plugin is enabled. - [#&googleapis#8203;13904](https://redirect.github.com/pytest-dev/pytest/issues/13904): Fixed the TOML type of the `tmp_path_retention_count` settings in the API reference from number to string. - [#&googleapis#8203;13946](https://redirect.github.com/pytest-dev/pytest/issues/13946): The private `config.inicfg` attribute was changed in a breaking manner in pytest 9.0.0. Due to its usage in the ecosystem, it is now restored to working order using a compatibility shim. It will be deprecated in pytest 9.1 and removed in pytest 10. - [#&googleapis#8203;13965](https://redirect.github.com/pytest-dev/pytest/issues/13965): Fixed quadratic-time behavior when handling `unittest` subtests in Python 3.10. #### Improved documentation - [#&googleapis#8203;4492](https://redirect.github.com/pytest-dev/pytest/issues/4492): The API Reference now contains cross-reference-able documentation of `pytest's command-line flags <command-line-flags>`. ### [`v9.0.1`](https://redirect.github.com/pytest-dev/pytest/releases/tag/9.0.1) [Compare Source](https://redirect.github.com/pytest-dev/pytest/compare/9.0.0...9.0.1) ### pytest 9.0.1 (2025-11-12) #### Bug fixes - [#&googleapis#8203;13895](https://redirect.github.com/pytest-dev/pytest/issues/13895): Restore support for skipping tests via `raise unittest.SkipTest`. - [#&googleapis#8203;13896](https://redirect.github.com/pytest-dev/pytest/issues/13896): The terminal progress plugin added in pytest 9.0 is now automatically disabled when iTerm2 is detected, it generated desktop notifications instead of the desired functionality. - [#&googleapis#8203;13904](https://redirect.github.com/pytest-dev/pytest/issues/13904): Fixed the TOML type of the verbosity settings in the API reference from number to string. - [#&googleapis#8203;13910](https://redirect.github.com/pytest-dev/pytest/issues/13910): Fixed <span class="title-ref">UserWarning: Do not expect file\_or\_dir</span> on some earlier Python 3.12 and 3.13 point versions. #### Packaging updates and notes for downstreams - [#&googleapis#8203;13933](https://redirect.github.com/pytest-dev/pytest/issues/13933): The tox configuration has been adjusted to make sure the desired version string can be passed into its `package_env` through the `SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST` environment variable as a part of the release process -- by `webknjaz`. #### Contributor-facing changes - [#&googleapis#8203;13891](https://redirect.github.com/pytest-dev/pytest/issues/13891), [#&googleapis#8203;13942](https://redirect.github.com/pytest-dev/pytest/issues/13942): The CI/CD part of the release automation is now capable of creating GitHub Releases without having a Git checkout on disk -- by `bluetech` and `webknjaz`. - [#&googleapis#8203;13933](https://redirect.github.com/pytest-dev/pytest/issues/13933): The tox configuration has been adjusted to make sure the desired version string can be passed into its `package_env` through the `SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST` environment variable as a part of the release process -- by `webknjaz`. ### [`v9.0.0`](https://redirect.github.com/pytest-dev/pytest/releases/tag/9.0.0) [Compare Source](https://redirect.github.com/pytest-dev/pytest/compare/8.4.2...9.0.0) ### pytest 9.0.0 (2025-11-05) #### New features - [#&googleapis#8203;1367](https://redirect.github.com/pytest-dev/pytest/issues/1367): **Support for subtests** has been added. `subtests <subtests>` are an alternative to parametrization, useful in situations where the parametrization values are not all known at collection time. Example: ```python def contains_docstring(p: Path) -> bool: """Return True if the given Python file contains a top-level docstring.""" ... def test_py_files_contain_docstring(subtests: pytest.Subtests) -> None: for path in Path.cwd().glob("*.py"): with subtests.test(path=str(path)): assert contains_docstring(path) ``` Each assert failure or error is caught by the context manager and reported individually, giving a clear picture of all files that are missing a docstring. In addition, `unittest.TestCase.subTest` is now also supported. This feature was originally implemented as a separate plugin in [pytest-subtests](https://redirect.github.com/pytest-dev/pytest-subtests), but since then has been merged into the core. > \[!NOTE] > This feature is experimental and will likely evolve in future releases. By that we mean that we might change how subtests are reported on failure, but the functionality and how to use it are stable. - [#&googleapis#8203;13743](https://redirect.github.com/pytest-dev/pytest/issues/13743): Added support for **native TOML configuration files**. While pytest, since version 6, supports configuration in `pyproject.toml` files under `[tool.pytest.ini_options]`, it does so in an "INI compatibility mode", where all configuration values are treated as strings or list of strings. Now, pytest supports the native TOML data model. In `pyproject.toml`, the native TOML configuration is under the `[tool.pytest]` table. ```toml # pyproject.toml [tool.pytest] minversion = "9.0" addopts = ["-ra", "-q"] testpaths = [ "tests", "integration", ] ``` The `[tool.pytest.ini_options]` table remains supported, but both tables cannot be used at the same time. If you prefer to use a separate configuration file, or don't use `pyproject.toml`, you can use `pytest.toml` or `.pytest.toml`: ```toml # pytest.toml or .pytest.toml [pytest] minversion = "9.0" addopts = ["-ra", "-q"] testpaths = [ "tests", "integration", ] ``` The documentation now (sometimes) shows configuration snippets in both TOML and INI formats, in a tabbed interface. See `config file formats` for full details. - [#&googleapis#8203;13823](https://redirect.github.com/pytest-dev/pytest/issues/13823): Added a **"strict mode"** enabled by the `strict` configuration option. When set to `true`, the `strict` option currently enables - `strict_config` - `strict_markers` - `strict_parametrization_ids` - `strict_xfail` The individual strictness options can be explicitly set to override the global `strict` setting. The previously-deprecated `--strict` command-line flag now enables strict mode. If pytest adds new strictness options in the future, they will also be enabled in strict mode. Therefore, you should only enable strict mode if you use a pinned/locked version of pytest, or if you want to proactively adopt new strictness options as they are added. See `strict mode` for more details. - [#&googleapis#8203;13737](https://redirect.github.com/pytest-dev/pytest/issues/13737): Added the `strict_parametrization_ids` configuration option. When set, pytest emits an error if it detects non-unique parameter set IDs, rather than automatically making the IDs unique by adding <span class="title-ref">0</span>, <span class="title-ref">1</span>, ... to them. This can be particularly useful for catching unintended duplicates. - [#&googleapis#8203;13072](https://redirect.github.com/pytest-dev/pytest/issues/13072): Added support for displaying test session **progress in the terminal tab** using the [OSC 9;4;](https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC) ANSI sequence. When pytest runs in a supported terminal emulator like ConEmu, Gnome Terminal, Ptyxis, Windows Terminal, Kitty or Ghostty, you'll see the progress in the terminal tab or window, allowing you to monitor pytest's progress at a glance. This feature is automatically enabled when running in a TTY. It is implemented as an internal plugin. If needed, it can be disabled as follows: - On a user level, using `-p no:terminalprogress` on the command line or via an environment variable `PYTEST_ADDOPTS='-p no:terminalprogress'`. - On a project configuration level, using `addopts = "-p no:terminalprogress"`. - [#&googleapis#8203;478](https://redirect.github.com/pytest-dev/pytest/issues/478): Support PEP420 (implicit namespace packages) as <span class="title-ref">--pyargs</span> target when `consider_namespace_packages` is <span class="title-ref">true</span> in the config. Previously, this option only impacted package imports, now it also impacts tests discovery. - [#&googleapis#8203;13678](https://redirect.github.com/pytest-dev/pytest/issues/13678): Added a new `faulthandler_exit_on_timeout` configuration option set to "false" by default to let <span class="title-ref">faulthandler</span> interrupt the <span class="title-ref">pytest</span> process after a timeout in case of deadlock. Previously, a <span class="title-ref">faulthandler</span> timeout would only dump the traceback of all threads to stderr, but would not interrupt the <span class="title-ref">pytest</span> process. \-- by `ogrisel`. - [#&googleapis#8203;13829](https://redirect.github.com/pytest-dev/pytest/issues/13829): Added support for configuration option aliases via the `aliases` parameter in `Parser.addini() <pytest.Parser.addini>`. Plugins can now register alternative names for configuration options, allowing for more flexibility in configuration naming and supporting backward compatibility when renaming options. The canonical name always takes precedence if both the canonical name and an alias are specified in the configuration file. #### Improvements in existing functionality - [#&googleapis#8203;13330](https://redirect.github.com/pytest-dev/pytest/issues/13330): Having pytest configuration spread over more than one file (for example having both a `pytest.ini` file and `pyproject.toml` with a `[tool.pytest.ini_options]` table) will now print a warning to make it clearer to the user that only one of them is actually used. \-- by `sgaist` - [#&googleapis#8203;13574](https://redirect.github.com/pytest-dev/pytest/issues/13574): The single argument `--version` no longer loads the entire plugin infrastructure, making it faster and more reliable when displaying only the pytest version. Passing `--version` twice (e.g., `pytest --version --version`) retains the original behavior, showing both the pytest version and plugin information. > \[!NOTE] > Since `--version` is now processed early, it only takes effect when passed directly via the command line. It will not work if set through other mechanisms, such as `PYTEST_ADDOPTS` or `addopts`. - [#&googleapis#8203;13823](https://redirect.github.com/pytest-dev/pytest/issues/13823): Added `strict_xfail` as an alias to the `xfail_strict` option, `strict_config` as an alias to the `--strict-config` flag, and `strict_markers` as an alias to the `--strict-markers` flag. This makes all strictness options consistently have configuration options with the prefix `strict_`. - [#&googleapis#8203;13700](https://redirect.github.com/pytest-dev/pytest/issues/13700): <span class="title-ref">--junitxml</span> no longer prints the <span class="title-ref">generated xml file</span> summary at the end of the pytest session when <span class="title-ref">--quiet</span> is given. - [#&googleapis#8203;13732](https://redirect.github.com/pytest-dev/pytest/issues/13732): Previously, when filtering warnings, pytest would fail if the filter referenced a class that could not be imported. Now, this only outputs a message indicating the problem. - [#&googleapis#8203;13859](https://redirect.github.com/pytest-dev/pytest/issues/13859): Clarify the error message for <span class="title-ref">pytest.raises()</span> when a regex <span class="title-ref">match</span> fails. - [#&googleapis#8203;13861](https://redirect.github.com/pytest-dev/pytest/issues/13861): Better sentence structure in a test's expected error message. Previously, the error message would be "expected exception must be \<expected>, but got \<actual>". Now, it is "Expected \<expected>, but got \<actual>". #### Removals and backward incompatible breaking changes - [#&googleapis#8203;12083](https://redirect.github.com/pytest-dev/pytest/issues/12083): Fixed a bug where an invocation such as <span class="title-ref">pytest a/ a/b</span> would cause only tests from <span class="title-ref">a/b</span> to run, and not other tests under <span class="title-ref">a/</span>. The fix entails a few breaking changes to how such overlapping arguments and duplicates are handled: 1. <span class="title-ref">pytest a/b a/</span> or <span class="title-ref">pytest a/ a/b</span> are equivalent to <span class="title-ref">pytest a</span>; if an argument overlaps another arguments, only the prefix remains. 2. <span class="title-ref">pytest x.py x.py</span> is equivalent to <span class="title-ref">pytest x.py</span>; previously such an invocation was taken as an explicit request to run the tests from the file twice. If you rely on these behaviors, consider using `--keep-duplicates <duplicate-paths>`, which retains its existing behavior (including the bug). - [#&googleapis#8203;13719](https://redirect.github.com/pytest-dev/pytest/issues/13719): Support for Python 3.9 is dropped following its end of life. - [#&googleapis#8203;13766](https://redirect.github.com/pytest-dev/pytest/issues/13766): Previously, pytest would assume it was running in a CI/CD environment if either of the environment variables <span class="title-ref">$CI</span> or <span class="title-ref">$BUILD\_NUMBER</span> was defined; now, CI mode is only activated if at least one of those variables is defined and set to a *non-empty* value. - [#&googleapis#8203;13779](https://redirect.github.com/pytest-dev/pytest/issues/13779): **PytestRemovedIn9Warning deprecation warnings are now errors by default.** Following our plan to remove deprecated features with as little disruption as possible, all warnings of type `PytestRemovedIn9Warning` now generate errors instead of warning messages by default. **The affected features will be effectively removed in pytest 9.1**, so please consult the `deprecations` section in the docs for directions on how to update existing code. In the pytest `9.0.X` series, it is possible to change the errors back into warnings as a stopgap measure by adding this to your `pytest.ini` file: ```ini [pytest] filterwarnings = ignore::pytest.PytestRemovedIn9Warning ``` But this will stop working when pytest `9.1` is released. **If you have concerns** about the removal of a specific feature, please add a comment to `13779`. #### Deprecations (removal in next major release) - [#&googleapis#8203;13807](https://redirect.github.com/pytest-dev/pytest/issues/13807): `monkeypatch.syspath_prepend() <pytest.MonkeyPatch.syspath_prepend>` now issues a deprecation warning when the prepended path contains legacy namespace packages (those using `pkg_resources.declare_namespace()`). Users should migrate to native namespace packages (`420`). See `monkeypatch-fixup-namespace-packages` for details. #### Bug fixes - [#&googleapis#8203;13445](https://redirect.github.com/pytest-dev/pytest/issues/13445): Made the type annotations of `pytest.skip` and friends more spec-complaint to have them work across more type checkers. - [#&googleapis#8203;13537](https://redirect.github.com/pytest-dev/pytest/issues/13537): Fixed a bug in which `ExceptionGroup` with only `Skipped` exceptions in teardown was not handled correctly and showed as error. - [#&googleapis#8203;13598](https://redirect.github.com/pytest-dev/pytest/issues/13598): Fixed possible collection confusion on Windows when short paths and symlinks are involved. - [#&googleapis#8203;13716](https://redirect.github.com/pytest-dev/pytest/issues/13716): Fixed a bug where a nonsensical invocation like `pytest x.py[a]` (a file cannot be parametrized) was silently treated as `pytest x.py`. This is now a usage error. - [#&googleapis#8203;13722](https://redirect.github.com/pytest-dev/pytest/issues/13722): Fixed a misleading assertion failure message when using `pytest.approx` on mappings with differing lengths. - [#&googleapis#8203;13773](https://redirect.github.com/pytest-dev/pytest/issues/13773): Fixed the static fixture closure calculation to properly consider transitive dependencies requested by overridden fixtures. - [#&googleapis#8203;13816](https://redirect.github.com/pytest-dev/pytest/issues/13816): Fixed `pytest.approx` which now returns a clearer error message when comparing mappings with different keys. - [#&googleapis#8203;13849](https://redirect.github.com/pytest-dev/pytest/issues/13849): Hidden `.pytest.ini` files are now picked up as the config file even if empty. This was an inconsistency with non-hidden `pytest.ini`. - [#&googleapis#8203;13865](https://redirect.github.com/pytest-dev/pytest/issues/13865): Fixed <span class="title-ref">--show-capture</span> with <span class="title-ref">--tb=line</span>. - [#&googleapis#8203;13522](https://redirect.github.com/pytest-dev/pytest/issues/13522): Fixed `pytester` in subprocess mode ignored all :attr\`pytester.plugins \<pytest.Pytester.plugins>\` except the first. Fixed `pytester` in subprocess mode silently ignored non-str `pytester.plugins <pytest.Pytester.plugins>`. Now it errors instead. If you are affected by this, specify the plugin by name, or switch the affected tests to use `pytester.runpytest_inprocess <pytest.Pytester.runpytest_inprocess>` explicitly instead. #### Packaging updates and notes for downstreams - [#&googleapis#8203;13791](https://redirect.github.com/pytest-dev/pytest/issues/13791): Minimum requirements on `iniconfig` and `packaging` were bumped to `1.0.1` and `22.0.0`, respectively. #### Contributor-facing changes - [#&googleapis#8203;12244](https://redirect.github.com/pytest-dev/pytest/issues/12244): Fixed self-test failures when <span class="title-ref">TERM=dumb</span>. - [#&googleapis#8203;12474](https://redirect.github.com/pytest-dev/pytest/issues/12474): Added scheduled GitHub Action Workflow to run Sphinx linkchecks in repo documentation. - [#&googleapis#8203;13621](https://redirect.github.com/pytest-dev/pytest/issues/13621): pytest's own testsuite now handles the `lsof` command hanging (e.g. due to unreachable network filesystems), with the affected selftests being skipped after 10 seconds. - [#&googleapis#8203;13638](https://redirect.github.com/pytest-dev/pytest/issues/13638): Fixed deprecated `gh pr new` command in `scripts/prepare-release-pr.py`. The script now uses `gh pr create` which is compatible with GitHub CLI v2.0+. - [#&googleapis#8203;13695](https://redirect.github.com/pytest-dev/pytest/issues/13695): Flush <span class="title-ref">stdout</span> and <span class="title-ref">stderr</span> in <span class="title-ref">Pytester.run</span> to avoid truncated outputs in <span class="title-ref">test\_faulthandler.py::test\_timeout</span> on CI -- by `ogrisel`. - [#&googleapis#8203;13771](https://redirect.github.com/pytest-dev/pytest/issues/13771): Skip <span class="title-ref">test\_do\_not\_collect\_symlink\_siblings</span> on Windows environments without symlink support to avoid false negatives. - [#&googleapis#8203;13841](https://redirect.github.com/pytest-dev/pytest/issues/13841): `tox>=4` is now required when contributing to pytest. - [#&googleapis#8203;13625](https://redirect.github.com/pytest-dev/pytest/issues/13625): Added missing docstrings to `pytest_addoption()`, `pytest_configure()`, and `cacheshow()` functions in `cacheprovider.py`. #### Miscellaneous internal changes - [#&googleapis#8203;13830](https://redirect.github.com/pytest-dev/pytest/issues/13830): Configuration overrides (`-o`/`--override-ini`) are now processed during startup rather than during `config.getini() <pytest.Config.getini>`. </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/google-cloud-python). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMjUuMSIsInVwZGF0ZWRJblZlciI6IjQ0LjEzNC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> --------- Co-authored-by: Chalmer Lowe <chalmerlowe@google.com>
…ps (googleapis#18582) Speed up the unit test suite by ~55% (reducing full suite runtime from ~66s to ~29s) by eliminating wall-clock sleep delays, avoiding live gRPC transport initialization, and reducing cryptographic CPU burn in protocol tests. Key changes: - Intercept retry backoff sleeps: Mock localized `time.sleep` and `asyncio.sleep` in transaction, snapshot, and batch commit retry tests. Each test now verifies retry counts and delay values without idling in real time. - Deterministic concurrency synchronization: Replace arbitrary timing sleeps in session manager and metrics tests with explicit `asyncio.Event` and `threading.Barrier` coordination, eliminating CI flakiness under CPU contention. - Eliminate teardown polling: Remove `_assert_true_with_timeout` and sleep polling from `test_database_session_manager.py` by relying on event-driven rotation callbacks and blocking thread joins. - Isolate GAPIC admin transports: Use autospec mock transports in `test_client.py` and `test_instance.py` instead of default credentials, eliminating live gRPC channel creation and 60-second network timeout risks. - Lower Omni Argon2id test parameters: Use minimal valid test parameters (1 iteration, 8 KB RAM) in protocol flow and state machine tests, reducing key derivation time by ~1,100x while leaving RFC golden vector tests untouched. - Clean up legacy mocks: Convert legacy global `mock.patch("time.sleep")` calls in `test_session.py` to localized module paths adhering to repository mock hygiene rules.
…th Alembic 1.20 and SQLAlchemy 2.1 (googleapis#18570)
) This PR enables bound access tokens, bound ID tokens, and default mTLS certificate discovery for Agent Identity workloads on GKE/CR, and adds per-request control for ID token binding: * Fall back to the well-known GKE workload credential bundle (`/var/run/secrets/workload-spiffe-credentials/x509.credential-bundle.private-key.pem`) in `_agent_identity_utils.get_agent_identity_certificate_path()`, `_mtls_helper._get_workload_cert_and_key()`, `_mtls_helper.check_use_client_cert()`, and `mtls.has_default_client_cert_source()` when no explicit or default certificate config file is present. * Add an optional `bind_id_token` parameter (`True`, `False`, or `None`) to `compute_engine.IDTokenCredentials`, `fetch_id_token_credentials()`, and `fetch_id_token()` (sync and async) so callers can explicitly opt in or out of binding metadata server ID tokens per request. * Scope default bound ID tokens to GKE by keeping ID tokens unbound when `GOOGLE_API_CERTIFICATE_CONFIG` is set (unless `bind_id_token=True`), while continuing to bind access tokens by default on both Cloud Run and GKE. * Add and update unit tests for GKE credential bundle fallback, `bind_id_token` options, and the `GOOGLE_API_CERTIFICATE_CONFIG` default gate. ---- Note: 1. GKE mounts a single combined PEM file (`x509.credential-bundle.private-key.pem`) at `/var/run/secrets/workload-spiffe-credentials/` without setting `GOOGLE_API_CERTIFICATE_CONFIG`. With this fallback, GKE Agent Identity workloads automatically use bound access tokens and bound ID tokens by default when the file is present. 2. On Cloud Run (where `GOOGLE_API_CERTIFICATE_CONFIG` is set), default ID token requests (`bind_id_token=None`) temporarily remain unbound so existing callers do not receive bound ID tokens. Callers on Cloud Run can pass `bind_id_token=True` to request bound ID tokens now, and a follow-up PR will remove this temporary gate to enable bound ID tokens by default on Cloud Run as well. design: go/sdk-mds-bound-token b/545779266
🤖 I have created a release *beep* *boop* --- ## [2.61.0](googleapis/google-cloud-python@google-auth-v2.60.0...google-auth-v2.61.0) (2026-10-07) ### Features * **auth:** support bound access and ID tokens for GKE ([googleapis#18594](googleapis#18594)) ([9f5fd7b](googleapis@9f5fd7b)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
…8587) `DocumentSnapshot` can be used with sync or async document reference types, which can result in confusing or incorrect type annotations upstream This PR makes `DocumentSnapshot` into a Generic, so it can specify what type of reference it holds. Fixes googleapis#15367
Earlier this year, we replaced `rsa` as a required depdendency with `cryptography`, because `rsa` has been deprecated. At the time, we kept `rsa` as an optional, opt-in dependency. Lately, `rsa` has been showing up in more version scanners as a problem (example: googleapis#15600 (comment), internal bug reports). This is showing up for `cryptography`, even though it's an optional dependency This PR drops `rsa` completely from `setup.py`, following the same pattern used for pyopenssl.
…googleapis#18357) Eliminate the redundant inner 'CloudSpanner.Session.run_in_transaction' span and duplicate MetricsCapture context, leaving 'CloudSpanner.Database.run_in_transaction' as the single transaction lifecycle span (matching Java and Go client behavior). - Attach transaction retry, abort, and rollback events directly to the active span. - Guard span event creation, retry delay computation, and exception stringification behind span.is_recording(). - Refactor the run_in_transaction retry loop by extracting _create_transaction_for_attempt and _handle_aborted helpers.
…ule (googleapis#18407) Introduce the foundational OpenTelemetry client metrics gating and configuration module for Google Cloud Storage. - Add `_opentelemetry_metrics.py` with a development gate (`_ENABLE_METRICS_DEV_GATE`) and environment variable parsing (`GCP_STORAGE_PYTHON_ENABLE_OTEL_METRICS`, `GCP_STORAGE_PYTHON_ENABLE_OTEL_DEBUG_METRICS`). - Implement `is_metrics_enabled()` and `is_advanced_metrics_enabled()` evaluation helpers with precedence hierarchy (dev gate -> client setting -> environment variable -> default). - Provide `get_common_attributes()` and `get_meter()` helpers for OpenTelemetry metrics instrumentation. - Add unit tests in `test__opentelemetry_metrics.py` covering gating resolution, environment variable overrides, `ImportError` fallback, and attribute helpers.
… GOOGLE_CLOUD_STORAGE_ZERO_COPY_BIDI_READ=1
…stants Explain the opt-in switch's accepted spellings, the four protobuf wire types, the 64-bit varint mask and the 32-bit tag limit.
…e loads (googleapis#18824) ## Context & Problem In `pandas 3.1.0+`, `DataFrame.to_csv()` applies `date_format` via `strftime()` to Python `datetime.datetime` objects inside `object`-dtype columns ([pandas-dev/pandas#27306](pandas-dev/pandas#27306)). On Linux/glibc with Python `< 3.14`, `strftime("%Y-%m-%d %H:%M:%S.%f")` does not zero-pad years `< 1000` (producing `"1-01-01 00:00:00.000000"`, which BigQuery's CSV load parser rejects in `test_load_table_from_dataframe_w_explicit_schema_source_format_csv`) and strips timezone offsets from timezone-aware `datetime` objects in `TIMESTAMP` columns. ## Summary of Changes - Add `_pandas_helpers.dataframe_to_csv()` and `_format_datetime_for_csv()` to pre-format `datetime.datetime` objects (excluding `pandas.NaT`) in `DATETIME` and `TIMESTAMP` `object`-dtype columns via `datetime.isoformat(value, sep=" ")` before delegating to `dataframe.to_csv()`. - Update `Client.load_table_from_dataframe()` to call `_pandas_helpers.dataframe_to_csv(dataframe, new_job_config.schema, tmppath)`. - Add unit tests in `tests/unit/test_client.py` covering `DATETIME` and `TIMESTAMP` `object`-dtype columns (including 4-digit year padding for year `1`, timezone offsets, `None`, `pandas.NaT`, and pre-formatted strings) as well as schema-less CSV dataframe loads. ## Verification - Verified `tests/system/test_pandas.py::test_load_table_from_dataframe_w_explicit_schema_source_format_csv` and `test_load_table_from_dataframe_w_explicit_schema_source_format_csv_floats` pass against BigQuery with `pandas 3.1.0`. - Verified the full unit test suite (`2895 passed`) with 100% statement and branch coverage on modified lines under both `pandas 3.1.0` and `pandas 3.0.6`. - Verified `mypy` passes cleanly across all 56 source files.
…oogleapis#18799) Before, `query_and_wait(query_results_format="ARROW")` always created a job unless the caller set `client.default_job_creation_mode`, so small Arrow queries paid about 200 ms for a job they didn't need. Arrow callers want low latency, so ARROW queries now default to `JOB_CREATION_OPTIONAL`, which is what `createQueryArrowStream()` in the Node.js client already does. This changes behavior for existing ARROW callers (Beta since 3.44.0): results that fit in the first response now come back with `RowIterator.job_id` set to `None`. `location` and `query_id` are still set. To always get a job, set `default_job_creation_mode="JOB_CREATION_REQUIRED"` on the client or use `client.query()`. - `query_and_wait()` sends `jobCreationMode=JOB_CREATION_OPTIONAL` when `query_results_format` is `ARROW` and the client doesn't set `default_job_creation_mode`. A client-level mode still wins. - Multi-page and long-running ARROW queries still get a job, since BigQuery creates one when rows remain. ARROW queries that need `jobs.insert` (for example, with a destination table) also still create a job. - Queries without `ARROW` are unchanged. - The `query_results_format` and `default_job_creation_mode` docstrings describe the new default and how to opt out. - Tests: unit tests for the ARROW default, a client-level mode taking precedence, non-ARROW queries sending no mode, and the `jobs.insert` fallback. Ran the unit suite and `tests/system/test_arrow.py` against BigQuery. A live single-page ARROW query returned `job_id=None`, while a multi-page ARROW query, a non-ARROW query and an ARROW query with `JOB_CREATION_REQUIRED` on the client each returned a job.
## Summary Temporarily pin `pytest<9.2` in the `noxfile.py` configuration of the 13 handwritten packages affected by the `pytest 9.2.0` release. ## Context Upstream `pytest 9.2.0` (released on October 27, 2026) changed warning filter initialization so that `filterwarnings = error` is applied *before* `pytest_configure` plugin hooks run, and removed the private `FixtureManager._arg2fixturedefs` attribute used by `pytest-asyncio==0.21.2`. Pinning `pytest<9.2` in the affected handwritten packages unblocks CI and current release pull requests (such as googleapis#18876). A follow-up effort will address `pytest 9.2` compatibility across these packages cleanly. ## Why These 13 Handwritten Packages Are Pinned All 13 packages configure `filterwarnings = error` in `pytest.ini` or `pyproject.toml` and fall into two categories: 1. **Direct `pytest-asyncio` usage (10 packages)**: `db-dtypes`, `google-api-core`, `google-auth-httplib2`, `google-cloud-dns`, `google-cloud-documentai-toolbox`, `google-cloud-error-reporting`, `google-cloud-firestore` (also pins `pytest-asyncio==0.21.2`), `google-cloud-logging`, `google-cloud-pubsub`, and `google-cloud-runtimeconfig`. Each installs `pytest-asyncio` directly in its own `noxfile.py` alongside `filterwarnings = error`, causing `pytest 9.2.0` to abort during startup when `pytest-asyncio` emits `PytestDeprecationWarning` for `asyncio_default_fixture_loop_scope`. 2. **Shared CI virtualenv inheritance (3 packages)**: `google-cloud-core`, `google-cloud-testutils`, and `proto-plus`. Although these three do not install `pytest-asyncio` in their own `noxfile.py`, our GitHub Actions test workflows reuse a shared Nox virtualenv directory (`NOX_ENVDIR=/tmp/shared_nox_envs`) across all packages in the same CI shard. When earlier packages in a shard install `pytest-asyncio` into that shared environment it will trigger the `filterwarnings = error` startup failure when these three packages run.
Update googleapis API sources and regenerate all Python libraries (excluding `google-cloud-ces` per googleapis#18888 and `google-cloud-chronicle` per googleapis#18890). ## Debug Info ### System Details - Python version: Python 3.13.15 - Go version: go version go1.27.3 linux/amd64 - OS: Linux 7.1.6-1rodete1-amd64 x86_64 - Librarian version: v0.50.0 ### Commands Executed - `go run github.com/googleapis/librarian/cmd/librarian@v0.50.0 update sources.googleapis` - `go run github.com/googleapis/librarian/cmd/librarian@v0.50.0 install` - `go run github.com/googleapis/librarian/cmd/librarian@v0.50.0 generate --all` - `git add .` - `git commit -m "feat: update API sources and regenerate"` ### Included googleapis CLs **google/chat/v1** - http://cl/1005723277 **google/cloud/ces/v1beta** - http://cl/1005071734 **google/cloud/chronicle/v1** - http://cl/1009115372 **google/cloud/documentai/v1beta3** - http://cl/1009078005 **google/cloud/geminidataanalytics/v1** - http://cl/1004080644 **google/cloud/geminidataanalytics/v1alpha** - http://cl/1004094508 **google/cloud/geminidataanalytics/v1beta** - http://cl/1005749856 **google/cloud/memorystore/v1** - http://cl/1007519450 - http://cl/1005379726 **google/cloud/memorystore/v1beta** - http://cl/1007522660 **google/cloud/modelarmor/v1** - http://cl/1006160230 **google/cloud/oracledatabase/v1** - http://cl/1007799612 **google/cloud/redis/cluster/v1** - http://cl/1007520135 **google/cloud/redis/cluster/v1beta1** - http://cl/1007612497 **google/cloud/sql/v1** - http://cl/1007133627 **google/cloud/sql/v1beta4** - http://cl/1007133967 **google/cloud/video/transcoder/v1** - http://cl/1008249014 **google/shopping/merchant/quota/v1** - http://cl/1005563202
…ndpoint attributes with spec (googleapis#18866)
…ogleapis#18894) Onboard google/cloud/designcenter/v1 API (google-cloud-designcenter). Internal tracking bug http://b/577038296 PiperOrigin-RevId: 1005520228 ## Debug Info ### System Details - Python version: Python 3.13.15 - OS: Linux 7.1.6-1rodete1-amd64 x86_64 - Librarian version: v0.50.0 ### Commands Executed - `python3 -m venv venv && source venv/bin/activate` - `pip install --upgrade pip` - `go run github.com/googleapis/librarian/cmd/librarian@v0.50.0 install` - `go run github.com/googleapis/librarian/cmd/librarian@v0.50.0 add google/cloud/designcenter/v1` - `go run github.com/googleapis/librarian/cmd/librarian@v0.50.0 generate -v google-cloud-designcenter` - `go run github.com/googleapis/librarian/cmd/librarian@v0.50.0 tidy` - `git add .` - `git commit -m "feat(google/cloud/designcenter/v1): add google-cloud-designcenter"`
…n in Client Timeout compliance tests (googleapis#18867)
🤖 I have created a release *beep* *boop* --- <details><summary>gapic-generator: 1.44.1</summary> ## [1.44.1](googleapis/google-cloud-python@gapic-generator-v1.44.0...gapic-generator-v1.44.1) (2026-10-29) ### Bug Fixes * **google-api-core:** align HTTP T3 and T4 OpenTelemetry span status and attributes ([googleapis#18868](googleapis#18868)) ([deb2194](googleapis@deb2194)) * **google-api-core:** align OpenTelemetry span names, kinds, and T3 endpoint attributes with spec ([googleapis#18866](googleapis#18866)) ([2a10196](googleapis@2a10196)) </details> <details><summary>google-api-core: 2.43.2</summary> ## [2.43.2](googleapis/google-cloud-python@google-api-core-v2.43.1...google-api-core-v2.43.2) (2026-10-29) ### Bug Fixes * **google-api-core:** align HTTP T3 and T4 OpenTelemetry span status and attributes ([googleapis#18868](googleapis#18868)) ([deb2194](googleapis@deb2194)) * **google-api-core:** align OpenTelemetry span names, kinds, and T3 endpoint attributes with spec ([googleapis#18866](googleapis#18866)) ([2a10196](googleapis@2a10196)) </details> <details><summary>google-apps-chat: 0.10.8</summary> ## [0.10.8](googleapis/google-cloud-python@google-apps-chat-v0.10.7...google-apps-chat-v0.10.8) (2026-10-29) ### Features * update API sources and regenerate ([googleapis#18889](googleapis#18889)) ([8705243](googleapis@8705243)) </details> <details><summary>google-cloud-documentai: 3.17.0</summary> ## [3.17.0](googleapis/google-cloud-python@google-cloud-documentai-v3.16.0...google-cloud-documentai-v3.17.0) (2026-10-29) ### Features * update API sources and regenerate ([googleapis#18889](googleapis#18889)) ([8705243](googleapis@8705243)) </details> <details><summary>google-cloud-geminidataanalytics: 0.13.6</summary> ## [0.13.6](googleapis/google-cloud-python@google-cloud-geminidataanalytics-v0.13.5...google-cloud-geminidataanalytics-v0.13.6) (2026-10-29) ### Features * update API sources and regenerate ([googleapis#18889](googleapis#18889)) ([8705243](googleapis@8705243)) </details> <details><summary>google-cloud-memorystore: 0.5.7</summary> ## [0.5.7](googleapis/google-cloud-python@google-cloud-memorystore-v0.5.6...google-cloud-memorystore-v0.5.7) (2026-10-29) ### Features * update API sources and regenerate ([googleapis#18889](googleapis#18889)) ([8705243](googleapis@8705243)) </details> <details><summary>google-cloud-modelarmor: 0.7.4</summary> ## [0.7.4](googleapis/google-cloud-python@google-cloud-modelarmor-v0.7.3...google-cloud-modelarmor-v0.7.4) (2026-10-29) ### Features * update API sources and regenerate ([googleapis#18889](googleapis#18889)) ([8705243](googleapis@8705243)) </details> <details><summary>google-cloud-oracledatabase: 0.6.4</summary> ## [0.6.4](googleapis/google-cloud-python@google-cloud-oracledatabase-v0.6.3...google-cloud-oracledatabase-v0.6.4) (2026-10-29) ### Features * update API sources and regenerate ([googleapis#18889](googleapis#18889)) ([8705243](googleapis@8705243)) </details> <details><summary>google-cloud-redis-cluster: 0.5.7</summary> ## [0.5.7](googleapis/google-cloud-python@google-cloud-redis-cluster-v0.5.6...google-cloud-redis-cluster-v0.5.7) (2026-10-29) ### Features * update API sources and regenerate ([googleapis#18889](googleapis#18889)) ([8705243](googleapis@8705243)) </details> <details><summary>google-cloud-sql: 0.1.3</summary> ## [0.1.3](googleapis/google-cloud-python@google-cloud-sql-v0.1.2...google-cloud-sql-v0.1.3) (2026-10-29) ### Features * update API sources and regenerate ([googleapis#18889](googleapis#18889)) ([8705243](googleapis@8705243)) </details> <details><summary>google-cloud-video-transcoder: 1.23.0</summary> ## [1.23.0](googleapis/google-cloud-python@google-cloud-video-transcoder-v1.22.0...google-cloud-video-transcoder-v1.23.0) (2026-10-29) ### Features * update API sources and regenerate ([googleapis#18889](googleapis#18889)) ([8705243](googleapis@8705243)) </details> <details><summary>google-shopping-merchant-quota: 1.7.0</summary> ## [1.7.0](googleapis/google-cloud-python@google-shopping-merchant-quota-v1.6.0...google-shopping-merchant-quota-v1.7.0) (2026-10-29) ### Features * update API sources and regenerate ([googleapis#18889](googleapis#18889)) ([8705243](googleapis@8705243)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
🤖 I have created a release *beep* *boop* --- ## [3.47.0](googleapis/google-cloud-python@google-cloud-bigquery-v3.46.2...google-cloud-bigquery-v3.47.0) (2026-10-29) ### Features * **bigquery:** add column data policies to SchemaField ([googleapis#18710](googleapis#18710)) ([157efe4](googleapis@157efe4)) * **bigquery:** add timestamp_precision for Arrow query results ([googleapis#18649](googleapis#18649)) ([a29d384](googleapis@a29d384)) * **bigquery:** read Arrow results from explicit destinations ([googleapis#18654](googleapis#18654)) ([8ac01b9](googleapis@8ac01b9)) * **bigquery:** share one BigQuery Storage client per Client ([googleapis#18652](googleapis#18652)) ([89cbc50](googleapis@89cbc50)) * **bigquery:** skip job creation for ARROW query_and_wait results ([googleapis#18799](googleapis#18799)) ([ca24f26](googleapis@ca24f26)) * **bigquery:** validate Arrow queries before sending them ([googleapis#18645](googleapis#18645)) ([1ac51ce](googleapis@1ac51ce)) * support Python 3.15 ([8fceef4](googleapis@8fceef4)) ### Bug Fixes * **bigquery:** apply max_results to the whole Arrow result ([googleapis#18651](googleapis#18651)) ([48c022c](googleapis@48c022c)) * **bigquery:** keep the Arrow first page and wait without rows ([googleapis#18650](googleapis#18650)) ([4eb0e71](googleapis@4eb0e71)) * **bigquery:** keep the Arrow schema for empty results ([googleapis#18655](googleapis#18655)) ([3ccf5ac](googleapis@3ccf5ac)) * **bigquery:** pass universe_domain to the BigQuery Storage client ([googleapis#18783](googleapis#18783)) ([6ab4063](googleapis@6ab4063)) * **bigquery:** raise when an Arrow batch arrives before its schema ([googleapis#18791](googleapis#18791)) ([7944a4c](googleapis@7944a4c)) * **bigquery:** require bqstorage 2.43.0 ([googleapis#18780](googleapis#18780)) ([3cd40ce](googleapis@3cd40ce)) * **bigquery:** send the same Arrow options on jobs.query and ReadRows ([googleapis#18646](googleapis#18646)) ([d7a2d27](googleapis@d7a2d27)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
feat: update Compute Engine v1 (preview) API to 2026-10-01-preview revision 20261007 feat: add AliasNetworkEndpoints service and AliasNetworkEndpoint resource messages feat: add HaControllerParams and HaControllerInstanceNetworkInterface messages to HaController feat: add ProtectionTier enum and protection_tier field to Scheduling and ResourceStatusScheduling feat: add ip_collection to AccessConfig and network_attachment and service_class_id to Address and NetworkEndpointGroup feat: add MEMORY_OPTIMIZED_X5 values to Commitment.Type enum and FAILURE_CUSTOMER_REPORTED to UpcomingMaintenance.MaintenanceReasons enum feat: remove FLOW_MANAGEMENT_UNSPECIFIED from WireProperties.FlowManagement enum docs: see release notes https://docs.cloud.google.com/compute/docs/release-notes
…s#18700) 🤖 I have created a release *beep* *boop* --- ## [1.56.0-preview.2](googleapis/google-cloud-python@google-cloud-compute-v1.56.0-preview.1...google-cloud-compute-v1.56.0-preview.2) (2026-10-29) ### Features * add AliasNetworkEndpoints service and AliasNetworkEndpoint ([1f86109](googleapis@1f86109)) * add HaControllerParams and HaControllerInstanceNetworkInterface ([1f86109](googleapis@1f86109)) * add ip_collection to AccessConfig and network_attachment and ([1f86109](googleapis@1f86109)) * add MEMORY_OPTIMIZED_X5 values to Commitment.Type enum and ([1f86109](googleapis@1f86109)) * add ProtectionTier enum and protection_tier field to Scheduling ([1f86109](googleapis@1f86109)) * remove FLOW_MANAGEMENT_UNSPECIFIED from ([1f86109](googleapis@1f86109)) * update API sources and regenerate ([googleapis#18699](googleapis#18699)) ([1aa57db](googleapis@1aa57db)) * update Compute Engine v1 (preview) API to 2026-10-01-preview ([1f86109](googleapis@1f86109)) ### Documentation * see release notes ([1f86109](googleapis@1f86109)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Bigtable had pytest-asyncio pinned to an old version, which was incompatible with newer pytest versions. This PR unpins it, and changes how the event loop is set up to match new expectations
….mutate (googleapis#18874) ## Summary Validate that rows passed to `MutationsBatcher.mutate(row)` (and by extension `MutationsBatcher.mutate_rows(rows)`) are instances of `DirectRow` and are not bound to a different table, matching the existing validation in `Table.mutate_rows()`. ### Problem When `MutationsBatcher` was refactored to wrap `self.table._table_impl.mutations_batcher(...)` directly (googleapis#18200) instead of delegating to `self.table.mutate_rows(...)`, two row-validation checks from `Table.mutate_rows()` were dropped: 1. **`DirectRow` type check (`TypeError`)**: Passing a `ConditionalRow` to `batcher.mutate(cond_row)` called `cond_row._get_mutations()` with the default `state=None`, which returns `self._false_pb_mutations` and unconditionally sends false-branch mutations via `MutateRows` without evaluating the row filter predicate. Passing an `AppendRow` raised a raw `AttributeError: 'AppendRow' object has no attribute '_get_mutations'` instead of `TypeError`. 2. **Table match check (`TableMismatchError`)**: Passing a `DirectRow` bound to another table silently sent its mutations to `batcher.table` instead of raising `TableMismatchError`. ### Solution - Validate `isinstance(row, DirectRow)` in `MutationsBatcher.mutate()`, raising `TypeError("Bulk processing can not be applied for conditional or append mutations.")` if not. - Validate `row.table is None or row.table.name == self.table.name` in `MutationsBatcher.mutate()`, raising `TableMismatchError` if the row belongs to a different table. - Document `:raises:` (`TypeError` and `TableMismatchError`) on `MutationsBatcher.mutate()` and `MutationsBatcher.mutate_rows()`. ## Test Plan - Added unit tests in `packages/google-cloud-bigtable/tests/unit/v2_client/test_batcher.py`: - `test_mutations_batcher_mutate_w_bound_table_row` - `test_mutations_batcher_mutate_wrong_row_type` (`ConditionalRow` and `AppendRow` across `mutate` and `mutate_rows`, verifying no mutations are queued) - `test_mutations_batcher_mutate_table_mismatch` (cross-table `DirectRow` across `mutate` and `mutate_rows`)
Some samples are still implemented in the legacy client only. This PR implements them in the data or admin clients, and adds a suffix to the region tags for the legacy client
…w -2**63 in int mutations (googleapis#18881) ## Summary - **`DeleteRangeFromColumn` qualifier validation and encoding**: `DeleteRangeFromColumn` did not encode `str` qualifiers to `bytes` in `__post_init__`, causing `proto-plus` to treat string qualifiers as base64 during `_to_pb()` serialization and either silently decode into the wrong column bytes or fail with `binascii.Error`. `__post_init__` now encodes `str` qualifiers to UTF-8 `bytes` and raises `TypeError` for non-`bytes`/`str` inputs, matching `SetCell` and `AddToCell`. - **Allow `-2**63` (`INT64_MIN`) in integer mutations and increment rules**: `SetCell`, `AddToCell`, and `IncrementRule` checked `abs(val) > (1 << 63) - 1`, which rejected the valid two's-complement minimum 64-bit signed integer `-2**63` (`-9223372036854775808`) with `ValueError`. Replaced the `abs()` check with `_MIN_INCREMENT_VALUE <= val <= _MAX_INCREMENT_VALUE`. ## Test plan - [x] Added unit tests in `tests/unit/data/test_mutations.py` and `tests/unit/data/test_read_modify_write_rules.py` covering `-2**63` and `2**63 - 1` bounds and `DeleteRangeFromColumn` `str` / invalid qualifier handling.
…es (googleapis#18408) Optimize request ID generation and RPC retry hot paths across Database, Transaction, Snapshot, and Batch: - Use `int.from_bytes(os.urandom(8), "big")` for process-level random ID generation and pre-format the static process prefix once at import time. - Cache per-database request ID prefixes directly in `instance.__dict__` via a non-data descriptor (`_CachedPrefixDescriptor`), lazily computing on first access and invalidating when `_channel_id` changes. - Inline `Database.with_error_augmentation` and construct gRPC metadata lists with unpacking (`[*prior_metadata, ...]`) instead of intermediate list copies and `.append()`. - Replace thread-safe `AtomicCounter` instances with local integer counters (`attempt = 0`) inside sequential retry closures, and pass active OpenTelemetry spans directly to avoid repeated `contextvars` lookups. - Eliminate transient `functools.partial` allocations and redundant `*args, **kwargs` unpacking inside retry closures. - Make `wrap_with_request_id` idempotent on repeated wrapping and replace stale request IDs when retrying failed calls.
…oogleapis#18920) When signing AWS STS GetCallerIdentity requests against regional FIPS endpoints (`sts-fips.{region}.amazonaws.com`), the `Host` header must remain `sts-fips.{region}.amazonaws.com`, whereas the AWS SigV4 credential scope and signing key derivation require the canonical service name (`sts`). Previously, `_generate_authentication_header_map` derived `service_name = host.split(".")[0]`, which produced `sts-fips` and caused AWS STS to reject the signed request with `SignatureDoesNotMatch: Credential should be scoped to correct service: 'sts'`. This change strips any trailing `-fips` suffix from the extracted hostname label when computing `service_name`. ## Manual Testing End-to-end reproduction script and observed pre-fix / post-fix output against GCP STS (`https://sts.googleapis.com/v1/token`) and AWS STS (`https://sts-fips.us-east-2.amazonaws.com`): - https://paste.googleplex.com/6755399436486780
🤖 I have created a release *beep* *boop* --- ## [2.62.1](googleapis/google-cloud-python@google-auth-v2.62.0...google-auth-v2.62.1) (2026-11-02) ### Bug Fixes * **auth:** strip -fips suffix from AWS service name in SigV4 signing ([googleapis#18920](googleapis#18920)) ([2e1899e](googleapis@2e1899e)) * **auth:** use an unencrypted key for mTLS certificate rotation ([googleapis#18709](googleapis#18709)) ([8166325](googleapis@8166325)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
…leapis#18641) ## Summary `AsyncAppendableObjectWriter` overloads `generation`: `None` / `0` creates a new object via `WriteObjectSpec(if_generation_match=generation)`, while `N > 0` reopens an existing object via `AppendObjectSpec(generation=N)`. There was no way to pass `if_generation_match=N` (`N > 0`) on `WriteObjectSpec` (overwrite only if the current generation matches `N`) or other write preconditions (`if_generation_not_match`, `if_metageneration_match`, `if_metageneration_not_match`). This adds a `Preconditions` dataclass (`if_generation_match`, `if_generation_not_match`, `if_metageneration_match`, `if_metageneration_not_match`) accepted via `preconditions: Optional[Preconditions] = None` on `AsyncAppendableObjectWriter.__init__`, `AsyncAppendableObjectWriter.from_blob`, and `_AsyncWriteObjectStream.__init__`: - Generation preconditions (`if_generation_match`, `if_generation_not_match`) require `generation=None`. Combining them with `generation` raises `ValueError`, including `from_blob` when `blob.generation` is set. To overwrite a fetched Blob, pass `generation=None` to `from_blob`, for example with `Preconditions(if_generation_match=blob.generation)`. `generation=0` without `preconditions` still means `if_generation_match=0`. - Creating or overwriting (`generation` is `None` or `0`) sets all 4 fields on `WriteObjectSpec`. Appending to an existing object (`generation > 0`) sets the metageneration preconditions on `AppendObjectSpec`. Metageneration preconditions cannot be combined with `write_handle` (raises `ValueError`), because GCS only checks them when no write handle is sent. - After the writer creates a generation, reconnects send `AppendObjectSpec` without preconditions, because they describe the object that was replaced. Motivation: fsspec/gcsfs#1101 (compare-and-swap writes in gcsfs). ## Test plan ``` cd packages/google-cloud-storage PYTHONPATH=$PWD python -m pytest tests/unit/asyncio/test_async_write_object_stream.py tests/unit/asyncio/test_async_appendable_object_writer.py # 86 passed ruff check --select I --target-version=py310 --line-length=88 <changed files> ruff format --check --target-version=py310 --line-length=88 <changed files> flake8 <changed files> ``` > This change was authored with an AI assistant; the description above was reviewed by the author.
…thread (googleapis#18628) ## Summary Hash read chunks of 1 MiB or more on a small worker pool instead of the asyncio event-loop thread, and write each chunk to its buffer only after its checksum matches. On `main`, `google_crc32c.value()` is 10-12% of the event-loop thread's samples at 2 GB/s per process (py-spy, 1 process x 16 streams), time during which no other stream on that loop is served. `google-crc32c` 1.9.0 and later release the GIL while hashing `bytes` of 1 MiB or more, so the workers run in parallel with the loop thread; this PR raises the minimum `google-crc32c` to 1.9.0. ## Changes - **`asyncio/retry/reads_resumption_strategy.py`:** - Chunks of at least `_CRC32C_OFFLOAD_MIN_BYTES` (defaults to `getattr(google_crc32c, "GIL_RELEASE_THRESHOLD", 1024 * 1024)`; configurable via `GCS_PYTHON_CLIENT_CRC32C_OFFLOAD_MIN_BYTES`, where `0` verifies every chunk inline) that are not part of a full-object read are hashed on a 2-thread `ThreadPoolExecutor`; smaller chunks and full-object reads (which feed the rolling checksum) are hashed inline as before. - Offloaded chunks (and any chunks arriving behind one) are held in `state["pending_checksums"]` and written in arrival order once their checksum matches (`verify_pending_checksums`). `next_expected_offset` advances on receipt and `bytes_written` only on write, so a retry resumes right after the last verified byte. - On a chunk checksum mismatch (which raises `DataCorruption`, as inline verification does) or an exception on the worker (which is re-raised), `discard_pending_checksums` drops every held chunk, cancels queued hashes and rewinds each read to its written end. `recover_state_on_failure` verifies held chunks before a stream is reopened. - The pool is replaced in forked children (`os.register_at_fork`); once interpreter shutdown refuses new work, chunks are hashed inline. - **`setup.py`, `testing/constraints-3.10.txt`, `storage-integration.yaml`:** require `google-crc32c >= 1.9.0`, the first release that hashes large `bytes` without holding the GIL. - **`asyncio/async_multi_range_downloader.py`:** `download_ranges` writes verified chunks after each received message (holding at most `_CRC32C_MAX_PENDING = 32`), drains fully when an attempt ends or fails with a stream error, discards held chunks on cancellation or `DataCorruption`, and documents all of this. ## Usage Enabled automatically for non-full-object read chunks of at least 1 MiB (`getattr(google_crc32c, "GIL_RELEASE_THRESHOLD", 1024 * 1024)`). Set `GCS_PYTHON_CLIENT_CRC32C_OFFLOAD_MIN_BYTES` to override the threshold in bytes, or `0` to verify every chunk inline on the event-loop thread. ## Memory `download_ranges` bounds `pending_checksums` to `_CRC32C_MAX_PENDING = 32` chunks per call before draining on the event loop. For 2 MiB chunks, each held `_PendingChunk` retains both the `data` slice and the enclosing `BidiReadObjectResponse`, bounding pending memory per `download_ranges` call to at most ~128 MiB with the generated `proto-plus`/`upb` parser (~4 MiB per chunk across the `upb` arena copy and `.content` `bytes` copy) or ~64 MiB with the zero-copy parser in googleapis#18627 (~2 MiB per chunk sharing the gRPC buffer). ## Tests `tests/unit/asyncio/retry/test_reads_resumption_strategy.py` and `tests/unit/asyncio/test_async_multi_range_downloader.py`: offload threshold, zero threshold and full-object exclusion; in-order writes behind a pending chunk; mismatch on an offloaded chunk (nothing from it on is written, offsets rewound, the retry requests the bytes again); a worker exception (queue emptied, queued futures cancelled); drain before a retry and at the end of an attempt; discard on cancellation; fork and shutdown behavior of the pool. ``` nox -s unit lint cover ``` ## Benchmark Setup: GCE `c4-standard-192`, Rapid bucket in the same zone, 8 processes x 16 concurrent `AsyncMultiRangeDownloader` streams (128 streams total), `4 x 16 MiB` ranges per `download_ranges()` call into preallocated buffers, 5 s warmup + 15 s timed window per round, 8 interleaved rounds per arm. ### 1. Off-Loop CRC32C Only vs. `main` (Neutral Alone) | Arm | Mean (GB/s) | Median (GB/s) | Min - Max (GB/s) | vs. `main` (Mean / Median) | | :--- | :---: | :---: | :---: | :---: | | `main` (generated parser + inline CRC32C) | 9.62 | 9.83 | 8.25 - 10.70 | - | | `offloop` only (`GCS_PYTHON_CLIENT_ZERO_COPY_BIDI_READ=0`) | 9.64 | 9.96 | 7.32 - 10.85 | +0.2% / +1.3% | With the generated `proto-plus`/`upb` parser active, each 2 MiB chunk is still copied twice on the event-loop thread under the GIL (~254 us per message), so the loop remains saturated and offloading CRC32C alone is neutral. ### 2. Zero-Copy Only vs. Zero-Copy + Off-Loop CRC32C (Additive on Top of googleapis#18627) | Arm | Mean (GB/s) | Median (GB/s) | Min - Max (GB/s) | vs. `main` (Mean / Median) | vs. Zero-Copy Only (Mean / Median) | | :--- | :---: | :---: | :---: | :---: | :---: | | `main` (generated parser + inline CRC32C) | 9.47 | 9.48 | 8.07 - 10.51 | - | - | | `zero-copy` only (googleapis#18626 + googleapis#18627, inline CRC32C) | 11.24 | 11.07 | 9.62 - 13.73 | +18.6% / +16.7% | - | | `zero-copy + offloop` (googleapis#18626 + googleapis#18627 + this PR) | 13.30 | 12.96 | 10.35 - 16.02 | +40.4% / +36.7% | +18.3% / +17.1% | Once googleapis#18627 removes the two `upb`/`proto-plus` copies from the event-loop thread (254 us -> 4.7 us per 2 MiB message, +18.6% mean / +16.7% median over `main`), synchronous `google_crc32c.value()` (~100-200 us per 2 MiB chunk) becomes the largest remaining per-message work on the loop thread; offloading >= 1 MiB chunks onto the worker pool adds another +18.3% mean / +17.1% median (+40.4% mean / +36.7% median total over `main`).
…xtend() (googleapis#18626) ## Summary `google_crc32c.value()`, `extend()` and `Checksum.update()` accept any contiguous bytes-like object (`memoryview`, `bytearray`, `array`, `bytes`) instead of `bytes` only, and the C extension releases the GIL for inputs of 1 MiB or more whose memory belongs to a `bytes` object (a `bytes` or a `memoryview` of one). That threshold is exported as `google_crc32c.GIL_RELEASE_THRESHOLD` (1 MiB). Motivation: the storage client wants to verify chunks it receives as `memoryview` slices of the gRPC message without copying them into `bytes` first; today `value(memoryview(...))` raises `TypeError: argument 1 must be read-only bytes-like object`. ## Changes - `src/google_crc32c/_crc32c.c`: parse the data argument with `y*` into a `Py_buffer` (released after hashing) instead of `y#`, which rejects every exporter with a release function. The 1 MiB GIL release applies when the exported memory is owned by a `bytes` object; a `bytearray` or other writable owner keeps the GIL, since another thread could write to it mid-hash. - `src/google_crc32c/python.py`: the pure-Python implementation hashes the raw bytes of the same inputs (a multi-byte `array` or cast view is hashed byte for byte, as the C extension does, instead of item by item). `Checksum(initial_value)` no longer compares the initial value with `b""`, which raised for numpy arrays. - `GIL_RELEASE_THRESHOLD` (1 MiB) is exported from `_crc32c.c`, `cext.py`, `python.py` and the package, so callers such as the storage client (googleapis#18628) can size the chunks they hash off the event loop. - Docstrings in `cext.py`, `_checksum.py` and `python.py` say bytes-like. - `tests/test___init__.py`: `value`/`extend` on `bytes`, `bytearray`, `memoryview` (sliced, writable, read-only, cast, 2-D) and `array` inputs, `BufferError` on non-contiguous views, and GIL probes: held for `bytearray` and read-only views of it, released for `bytes`, `memoryview(bytes)` and a slice of it. ## Tests ``` nox -s unit lint cover ``` 184 passed, 4 skipped (numpy not installed) with the compiled extension; 89 passed, 99 skipped, 100% coverage in pure-Python mode (`nox -s unit cover`). ## Notes - Behavior change in the pure-Python implementation for multi-byte `array`/cast inputs (previously coerced item by item). It now matches the C extension. - The GIL rule (`bytes`-owned memory only) is a choice: `hashlib` and `zlib.crc32` release the GIL for any buffer. Holding it for writable owners avoids hashing memory another thread may be writing to; happy to drop that restriction if you prefer parity with `hashlib`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add an opt-in zero-copy deserializer for
BidiReadObjectResponseso_AsyncReadObjectStreamhands each chunk'schecksummed_data.contentto the read path as amemoryviewof the gRPC frame instead of thebytescopy the generated parser makes on the event-loop thread. Off by default; enabled withGOOGLE_CLOUD_STORAGE_ZERO_COPY_BIDI_READ=1when the installedgoogle-crc32cacceptsmemoryview(#1).Changes
asyncio/_zero_copy_bidi_read.py(new):deserialize(buf)walks the wire format of data responses (object_data_ranges,read_handle) overmemoryview(buf)and returns duck-typed stand-ins with the attributes the read path uses (object_data_ranges,read_handle,metadata,HasField,_pb). A response carryingmetadata, or bytes that do not parse cleanly, is handed toBidiReadObjectResponse.deserialize, which returns the real message or raises its usualDecodeError. Varint, int64 and tag handling match upb.is_supported()requires the env var and agoogle_crc32c.value(memoryview(b"\0"))probe; google-crc32c <= 1.9.0 rejectsmemoryview, so without fix(crc32c): accept any contiguous bytes-like object in value() and extend() #1 the generated parser is used and nothing changes.wrapped_rpc(transport): the transport'sBidiReadObjectstub with the deserializer swapped in, wrapped withgapic_v1.method_async.wrap_methodlike the generated_wrapped_methodsentry (same error mapping and client-info header), cached per transport.asyncio/async_read_object_stream.py:_AsyncReadObjectStreamuseswrapped_rpc(transport)when available, else the generated wrapped method.With the parser enabled, the
contentpassed touser_buffer.write()is amemoryview;BytesIOaccepts it, custom sinks must too, which is why it is opt-in.Tests
tests/unit/asyncio/test_zero_copy_bidi_read.py: field-by-field comparison with the generated parser (including unknown fields of every wire type at each nesting level), 16 malformed inputs on which both parsers raiseDecodeError, fallback cases, env-var and probe gating,wrapped_rpccaching, and an in-processgrpc.aioserver driving_AsyncReadObjectStreamwith the parser on and off. 100% line and branch coverage of the module.Benchmark
c4-standard-192(us-central1-c), Rapid bucket, 16 concurrent streams per process, 4 x 16 MiB perdownload_rangescall into preallocated buffers, CRC32C verification on (inline), google-crc32c from #1 (mrd_bench.py, median of 3 runs, aggregate GB/s):mainParse plus the read path's field reads for one 2 MiB response: 257 us with the generated parser, 5 us with this one.