Skip to content

chore(migration): Migrate code from googleapis/python-api-core into packages/google-api-core#15567

Draft
parthea wants to merge 573 commits intomainfrom
migration.python-api-core.migration.2026-02-13_19-20-54.migrate
Draft

chore(migration): Migrate code from googleapis/python-api-core into packages/google-api-core#15567
parthea wants to merge 573 commits intomainfrom
migration.python-api-core.migration.2026-02-13_19-20-54.migrate

Conversation

@parthea
Copy link
Contributor

@parthea parthea commented Feb 13, 2026

See #10892.

This PR should be merged with a merge-commit, not a squash-commit, in order to preserve the git history.

release-please bot and others added 30 commits February 2, 2022 15:31
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Source-Link: googleapis/synthtool@571ee2c
Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:660abdf857d3ab9aabcd967c163c70e657fcc5653595c709263af5f3fa23ef67
* chore(deps): update all dependencies to v3

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
Certain APIs with Long-Running Operations deviate from the semantics
in https://google.aip.dev/151 and instead define custom operation
messages, aka Extended Operations.

This change adds a PollingFuture subclass designed to be used with
Extended Operations. It is analogous and broadly similar to
google.api_core.operation.Operation and subclasses
google.api_core.future.polling.PollingFuture.

The full description of Extended Operation semantics is beyond the
scope of this change.
Source-Link: googleapis/synthtool@ca87909
Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:6162c384d685c5fe22521d3f37f6fc732bf99a085f6d47b677dbcae97fc21392
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Co-authored-by: Anthonios Partheniou <partheniou@google.com>
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
The operation wrapped by ExtendedOperation may define other fields or methods
that the user may wish to use.
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Co-authored-by: Anthonios Partheniou <partheniou@google.com>
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
* chore(python): use black==22.3.0

Source-Link: googleapis/synthtool@6fab84a
Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:7cffbc10910c3ab1b852c05114a08d374c195a81cdec1d4a67a1d129331d0bfe

* ci: use black 22.3.0

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
Co-authored-by: Anthonios Partheniou <partheniou@google.com>
)

Source-Link: googleapis/synthtool@7804ade
Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:eede5672562a32821444a8e803fb984a6f61f2237ea3de229d2de24453f4ae7d
Source-Link: googleapis/synthtool@06e8279
Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:b3500c053313dc34e07b1632ba9e4e589f4f77036a7cf39e1fe8906811ae0fce

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
Source-Link: googleapis/synthtool@eb78c98
Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:8a5d3f6a2e43ed8293f34e06a2f56931d1e88a2694c3bb11b15df4eb256ad163

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
* chore(deps): update all dependencies

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
Source-Link: googleapis/synthtool@f15cc72
Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:bc5eed3804aec2f05fad42aacf973821d9500c174015341f721a984a0825b6fd
* test: use == instead of is when comparing equality

* use not instead of ==
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
…374)

Source-Link: googleapis/synthtool@6b4d5a6
Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:f792ee1320e03eda2d13a5281a2989f7ed8a9e50b73ef6da97fac7e1e850b149

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
Source-Link: googleapis/synthtool@453a5d9
Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:81ed5ecdfc7cac5b699ba4537376f3563f6f04122c4ec9e735d3b3dc1d43dd32
feat: adds support for audience in client_options.
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Also adds upper limits for extras.

fix(deps): require googleapis-common-protos >= 1.56.2
pujawadare and others added 24 commits October 30, 2025 11:18
Always put `None` into the request queue when closing a bidi stream.

This ensures that the request queue is always signaled as closed, even if the underlying gRPC call object is not yet available.
* Use error log over `print` to avoid stdout write

* Move common return to end of function

* Update google/api_core/_python_version_support.py

Co-authored-by: Chalmer Lowe <chalmerlowe@google.com>

* Fix lint error

---------

Co-authored-by: Chalmer Lowe <chalmerlowe@google.com>
…y38/py39 (#859)

* fix: remove call to importlib.metadata.packages_distributions() for py38/py39

* cover

* update comment
Additional clean up following
googleapis/python-api-core#856

---------

Co-authored-by: ohmayr <omairn@google.com>
Co-authored-by: Victor Chudnovsky <vchudnov@google.com>
… performance test setup (#865)

Fix flaky tests due to imprecision in floating point calculation and
performance test setup
This change is needed as part of b/463296248
As per[ this
README](https://github.com/googleapis/repo-automation-bots/blob/main/packages/sync-repo-settings/README.md),
the `sync-repo-settings` bot is deprecated. The bot has already been
disabled for this repo and this configuration is now obsolete.
This change is needed as part of b/463296248. Instead of having 4
different presubmits that run 4 different nox unit tests, we now have
all 4 patterns tested under a single nox session. This follows the
pattern that we have in google-cloud-python where there is a single unit
test nox session.
The Python SDK will use a hybrid approach for mTLS enablement:

If the GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable is set
(either true or false or any value), the SDK will respect that setting.
This is necessary for test scenarios and users who need to explicitly
control mTLS behavior.
If the GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable is not
set, the SDK will automatically enable mTLS only if it detects Managed
Workload Identity (MWID) or X.509 Workforce Identity Federation (WIF)
certificate sources. In other cases where the variable is not set, mTLS
will remain disabled.

---------

Signed-off-by: Radhika Agrawal <agrawalradhika@google.com>
Mypy tests are are currently failing, due to a combination of a typing
change in the auth library, and the deprecation of Python 3.7

This PR fixes mypy, and makes the types a bit more explicit
The `pytype` nox session was not running as a presubmit so I've removed
it. `pytype` is deprecated as per [this
note](https://github.com/google/pytype?tab=readme-ov-file#an-update-on-pytype).
PR created by the Librarian CLI to initialize a release. Merging this PR
will auto trigger a release.

Librarian Version: v1.0.1
Language Image:
us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator@sha256:c8612d3fffb3f6a32353b2d1abd16b61e87811866f7ec9d65b59b02eb452a620
<details><summary>google-api-core: 2.29.0</summary>

##
[2.29.0](googleapis/python-api-core@v2.28.1...v2.29.0)
(2026-01-08)

### Features

* make parse_version_to_tuple public (#864)
([c969186f](googleapis/python-api-core@c969186f))

* Auto enable mTLS when supported certificates are detected (#869)
([f8bf6f96](googleapis/python-api-core@f8bf6f96))

### Bug Fixes

* remove call to importlib.metadata.packages_distributions() for
py38/py39 (#859)
([628003e2](googleapis/python-api-core@628003e2))

* Log version check errors (#858)
([6493118c](googleapis/python-api-core@6493118c))

* flaky tests due to imprecision in floating point calculation and
performance test setup (#865)
([93404080](googleapis/python-api-core@93404080))

* closes tailing streams in bidi classes. (#851)
([c97b3a00](googleapis/python-api-core@c97b3a00))

</details>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [actions/checkout](https://redirect.github.com/actions/checkout) |
action | major | `v4` → `v6` |
|
[actions/setup-python](https://redirect.github.com/actions/setup-python)
| action | major | `v5` → `v6` |
| [python](https://redirect.github.com/actions/python-versions) |
uses-with | minor | `3.10` → `3.14` |

---

### Release Notes

<details>
<summary>actions/checkout (actions/checkout)</summary>

### [`v6`](https://redirect.github.com/actions/checkout/compare/v5...v6)

[Compare
Source](https://redirect.github.com/actions/checkout/compare/v5...v6)

### [`v5`](https://redirect.github.com/actions/checkout/compare/v4...v5)

[Compare
Source](https://redirect.github.com/actions/checkout/compare/v4...v5)

</details>

<details>
<summary>actions/setup-python (actions/setup-python)</summary>

###
[`v6`](https://redirect.github.com/actions/setup-python/compare/v5...v6)

[Compare
Source](https://redirect.github.com/actions/setup-python/compare/v5...v6)

</details>

<details>
<summary>actions/python-versions (python)</summary>

###
[`v3.14.2`](https://redirect.github.com/actions/python-versions/releases/tag/3.14.2-20014991423):
3.14.2

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.14.1-19879739908...3.14.2-20014991423)

Python 3.14.2

###
[`v3.14.1`](https://redirect.github.com/actions/python-versions/releases/tag/3.14.1-19879739908):
3.14.1

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.14.0-18313368925...3.14.1-19879739908)

Python 3.14.1

###
[`v3.14.0`](https://redirect.github.com/actions/python-versions/releases/tag/3.14.0-18313368925):
3.14.0

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.11-20014977833...3.14.0-18313368925)

Python 3.14.0

###
[`v3.13.11`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.11-20014977833):
3.13.11

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.10-19879712315...3.13.11-20014977833)

Python 3.13.11

###
[`v3.13.10`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.10-19879712315):
3.13.10

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.9-18515951191...3.13.10-19879712315)

Python 3.13.10

###
[`v3.13.9`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.9-18515951191):
3.13.9

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.8-18331000654...3.13.9-18515951191)

Python 3.13.9

###
[`v3.13.8`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.8-18331000654):
3.13.8

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.7-16980743123...3.13.8-18331000654)

Python 3.13.8

###
[`v3.13.7`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.7-16980743123):
3.13.7

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.6-16792117939...3.13.7-16980743123)

Python 3.13.7

###
[`v3.13.6`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.6-16792117939):
3.13.6

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.5-15601068749...3.13.6-16792117939)

Python 3.13.6

###
[`v3.13.5`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.5-15601068749):
3.13.5

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.4-15433317575...3.13.5-15601068749)

Python 3.13.5

###
[`v3.13.4`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.4-15433317575):
3.13.4

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.3-14344076652...3.13.4-15433317575)

Python 3.13.4

###
[`v3.13.3`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.3-14344076652):
3.13.3

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.2-13708744326...3.13.3-14344076652)

Python 3.13.3

###
[`v3.13.2`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.2-13708744326):
3.13.2

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.1-13437882550...3.13.2-13708744326)

Python 3.13.2

###
[`v3.13.1`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.1-13437882550):
3.13.1

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.13.0-13707372259...3.13.1-13437882550)

Python 3.13.1

###
[`v3.13.0`](https://redirect.github.com/actions/python-versions/releases/tag/3.13.0-13707372259):
3.13.0

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.12-18393146713...3.13.0-13707372259)

Python 3.13.0

###
[`v3.12.12`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.12-18393146713):
3.12.12

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.11-15433310049...3.12.12-18393146713)

Python 3.12.12

###
[`v3.12.11`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.11-15433310049):
3.12.11

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.10-14343898437...3.12.11-15433310049)

Python 3.12.11

###
[`v3.12.10`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.10-14343898437):
3.12.10

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.9-13149478207...3.12.10-14343898437)

Python 3.12.10

###
[`v3.12.9`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.9-13149478207):
3.12.9

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.8-12154062663...3.12.9-13149478207)

Python 3.12.9

###
[`v3.12.8`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.8-12154062663):
3.12.8

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.7-11128208086...3.12.8-12154062663)

Python 3.12.8

###
[`v3.12.7`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.7-11128208086):
3.12.7

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.6-10765725458...3.12.7-11128208086)

Python 3.12.7

###
[`v3.12.6`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.6-10765725458):
3.12.6

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.5-10375840348...3.12.6-10765725458)

Python 3.12.6

###
[`v3.12.5`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.5-10375840348):
3.12.5

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.4-9947065640...3.12.5-10375840348)

Python 3.12.5

###
[`v3.12.4`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.4-9947065640):
3.12.4

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.3-11057844995...3.12.4-9947065640)

Python 3.12.4

###
[`v3.12.3`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.3-11057844995):
3.12.3

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.2-11057786931...3.12.3-11057844995)

Python 3.12.3

###
[`v3.12.2`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.2-11057786931):
3.12.2

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.1-11057762749...3.12.2-11057786931)

Python 3.12.2

###
[`v3.12.1`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.1-11057762749):
3.12.1

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.12.0-11057302691...3.12.1-11057762749)

Python 3.12.1

###
[`v3.12.0`](https://redirect.github.com/actions/python-versions/releases/tag/3.12.0-11057302691):
3.12.0

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.14-18393181605...3.12.0-11057302691)

Python 3.12.0

###
[`v3.11.14`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.14-18393181605):
3.11.14

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.13-15433298024...3.11.14-18393181605)

Python 3.11.14

###
[`v3.11.13`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.13-15433298024):
3.11.13

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.12-14343939122...3.11.13-15433298024)

Python 3.11.13

###
[`v3.11.12`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.12-14343939122):
3.11.12

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.11-12160100664...3.11.12-14343939122)

Python 3.11.12

###
[`v3.11.11`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.11-12160100664):
3.11.11

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.10-10765870205...3.11.11-12160100664)

Python 3.11.11

###
[`v3.11.10`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.10-10765870205):
3.11.10

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.9-9947079978...3.11.10-10765870205)

Python 3.11.10

###
[`v3.11.9`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.9-9947079978):
3.11.9

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.8-11113201752...3.11.9-9947079978)

Python 3.11.9

###
[`v3.11.8`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.8-11113201752):
3.11.8

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.7-11113197120...3.11.8-11113201752)

Python 3.11.8

###
[`v3.11.7`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.7-11113197120):
3.11.7

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.6-11113179737...3.11.7-11113197120)

Python 3.11.7

###
[`v3.11.6`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.6-11113179737):
3.11.6

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.5-11113174019...3.11.6-11113179737)

Python 3.11.6

###
[`v3.11.5`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.5-11113174019):
3.11.5

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.4-11113170699...3.11.5-11113174019)

Python 3.11.5

###
[`v3.11.4`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.4-11113170699):
3.11.4

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.3-11059198104...3.11.4-11113170699)

Python 3.11.4

###
[`v3.11.3`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.3-11059198104):
3.11.3

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.2-11059137522...3.11.3-11059198104)

Python 3.11.3

###
[`v3.11.2`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.2-11059137522):
3.11.2

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.1-11058799881...3.11.2-11059137522)

Python 3.11.2

###
[`v3.11.1`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.1-11058799881):
3.11.1

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.11.0-11058707212...3.11.1-11058799881)

Python 3.11.1

###
[`v3.11.0`](https://redirect.github.com/actions/python-versions/releases/tag/3.11.0-11058707212):
3.11.0

[Compare
Source](https://redirect.github.com/actions/python-versions/compare/3.10.19-18393196481...3.11.0-11058707212)

Python 3.11.0

</details>

---

### Configuration

📅 **Schedule**: 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.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- 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/python-api-core).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi43NC41IiwidXBkYXRlZEluVmVyIjoiNDIuNzQuNSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

---------

Co-authored-by: Anthonios Partheniou <partheniou@google.com>
Fixes googleapis/python-api-core#880

## Problem:
When the retry mechanism re-raises non-retryable exceptions, it
explicitly clears the exception chain by using raise final_exc from
None. This breaks explicit exception chaining created with raise ...
from ..., making the original cause (__cause__) inaccessible for
debugging.

## Fix:
Modified `_default_exception_factory()` in `retry_base.py` to preserve
the `__cause__` attribute when re-raising non-retryable exceptions.
Instead of returning `(exc_list[-1], None)`, we now return
`(exc_list[-1], getattr(exc_list[-1], '__cause__', None))`.

This ensures that exception chains are maintained through the retry
mechanism, preserving debugging information and meeting developer
expectations for exception handling.

## Testing:
Added a new test case in `tests/unit/retry/test_retry_base.py` that
checks that the cause from the chained exception is preserved by
`build_retry_error`.
Automated: Change comment references from `gsutil` to `gcloud storage`

This CL is part of the on going effort to migrate from the legacy
`gsutil` tool to the new and improved `gcloud storage` command-line
interface.
`gcloud storage` is the recommended and modern tool for interacting with
Google Cloud Storage, offering better performance, unified
authentication, and a more consistent command structure with other
`gcloud` components. 🚀

### Automation Details

This change was **generated automatically** by an agent that targets
users of `gsutil`.
The transformations applied are based on the [gsutil to gcloud storage
migration guide](http://go/gsutil-gcloud-storage-migration-guide).

### ⚠️ Action Required: Please Review and Test Carefully

While we have based the automation on the migration guide, every use
case is unique.
**It is crucial that you thoroughly test these changes in environments
appropriate to your use-case before merging.**
Be aware of potential differences between `gsutil` and `gcloud storage`
that could impact your workflows.
For instance, the structure of command output may have changed,
requiring updates to any scripts that parse it. Similarly, command
behavior can differ subtly; the `gcloud storage rsync` command has a
different file deletion logic than `gsutil rsync`, which could lead to
unintended file deletions.

Our migration guides can help guide you through a list of mappings and
some notable differences between the two tools.

Standard presubmit tests are run as part of this CL's workflow. **If you
need to target an additional test workflow or require assistance with
testing, please let us know.**

Please verify that all your Cloud Storage operations continue to work as
expected to avoid any potential disruptions in production.

### Support and Collaboration

The `GCS CLI` team is here to help! If you encounter any issues, have a
complex use case that this automated change doesn't cover, or face any
other blockers, please don't hesitate to reach out.
We are happy to work with you to test and adjust these changes as
needed.

**Contact:** `gcs-cli-hyd@google.com`

We appreciate your partnership in this important migration effort!

#gsutil-migration
This fix removes the `nox.options.sessions` that were left in the
noxfile when those sessions were removed in #873.
Require Python 3.9+
Require protobuf 4.25.8+
Simplify code accordingly.

Fixes #15019 

This also required removing 3.7 and 3.8 as required checks in the repo
config, under branch protection rules.
… into migration.python-api-core.migration.2026-02-13_19-20-54.migrate
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @parthea, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request executes a significant structural migration of the google-api-core Python library. The core objective is to relocate the entire codebase, its associated documentation, configuration, and testing infrastructure into a new, dedicated packages/google-api-core directory. This change is purely organizational, aiming to improve repository structure and management without altering any existing functionality or introducing new features. It ensures that all components of the library are consolidated under a single, well-defined package path.

Highlights

  • Codebase Relocation: The entire google-api-core library, including all Python modules, is moved into packages/google-api-core.
  • Documentation Migration: All Sphinx documentation source files and static assets are relocated to packages/google-api-core/docs.
  • Configuration Files: Project configuration files such as .coveragerc, .flake8, .gitignore, .pre-commit-config.yaml, pyproject.toml, and renovate.json are moved to the new package directory.
  • Changelog and Metadata: The CHANGELOG.md, CODE_OF_CONDUCT.md, CONTRIBUTING.rst, LICENSE, MANIFEST.in, README.rst, SECURITY.md, and .repo-metadata.json files are now located within packages/google-api-core.
  • Test Suite Relocation: All unit and asyncio tests, along with testing constraints, are moved to packages/google-api-core/tests and packages/google-api-core/testing.
  • Script Relocation: Utility scripts for README generation and secret decryption are moved to packages/google-api-core/scripts.
Changelog
  • packages/google-api-core/.coveragerc
    • Added code coverage configuration.
  • packages/google-api-core/.flake8
    • Added flake8 linting configuration.
  • packages/google-api-core/.gitignore
    • Added Git ignore patterns.
  • packages/google-api-core/.librarian/state.yaml
    • Added librarian tool state configuration.
  • packages/google-api-core/.pre-commit-config.yaml
    • Added pre-commit hook configuration.
  • packages/google-api-core/.repo-metadata.json
    • Added repository metadata.
  • packages/google-api-core/CHANGELOG.md
    • Added historical changelog entries.
  • packages/google-api-core/CODE_OF_CONDUCT.md
    • Added project Code of Conduct.
  • packages/google-api-core/CONTRIBUTING.rst
    • Added contribution guidelines.
  • packages/google-api-core/LICENSE
    • Added Apache 2.0 license.
  • packages/google-api-core/MANIFEST.in
    • Added distribution manifest.
  • packages/google-api-core/README.rst
    • Added project README.
  • packages/google-api-core/SECURITY.md
    • Added security policy.
  • packages/google-api-core/docs/_static/custom.css
    • Added custom documentation CSS.
  • packages/google-api-core/docs/_templates/layout.html
    • Added custom documentation layout.
  • packages/google-api-core/docs/auth.rst
    • Added authentication documentation.
  • packages/google-api-core/docs/client_info.rst
    • Added client information documentation.
  • packages/google-api-core/docs/client_options.rst
    • Added client options documentation.
  • packages/google-api-core/docs/conf.py
    • Added Sphinx documentation configuration.
  • packages/google-api-core/docs/exceptions.rst
    • Added exceptions documentation.
  • packages/google-api-core/docs/futures.rst
    • Added futures documentation.
  • packages/google-api-core/docs/helpers.rst
    • Added helpers documentation.
  • packages/google-api-core/docs/iam.rst
    • Added IAM documentation.
  • packages/google-api-core/docs/index.rst
    • Added documentation index.
  • packages/google-api-core/docs/multiprocessing.rst
    • Added multiprocessing documentation.
  • packages/google-api-core/docs/operation.rst
    • Added long-running operations documentation.
  • packages/google-api-core/docs/operations_client.rst
    • Added operations client documentation.
  • packages/google-api-core/docs/page_iterator.rst
    • Added page iterators documentation.
  • packages/google-api-core/docs/path_template.rst
    • Added path templates documentation.
  • packages/google-api-core/docs/retry.rst
    • Added retry documentation.
  • packages/google-api-core/docs/timeout.rst
    • Added timeout documentation.
  • packages/google-api-core/google/api_core/init.py
    • Added package initialization.
  • packages/google-api-core/google/api_core/_python_package_support.py
    • Added Python package support utilities.
  • packages/google-api-core/google/api_core/_python_version_support.py
    • Added Python version support utilities.
  • packages/google-api-core/google/api_core/_rest_streaming_base.py
    • Added base class for REST streaming.
  • packages/google-api-core/google/api_core/bidi.py
    • Added synchronous bidirectional streaming helpers.
  • packages/google-api-core/google/api_core/bidi_async.py
    • Added asynchronous bidirectional streaming helpers.
  • packages/google-api-core/google/api_core/bidi_base.py
    • Added base class for bidirectional streaming.
  • packages/google-api-core/google/api_core/client_info.py
    • Added client information utilities.
  • packages/google-api-core/google/api_core/client_logging.py
    • Added client logging utilities.
  • packages/google-api-core/google/api_core/client_options.py
    • Added client options class.
  • packages/google-api-core/google/api_core/datetime_helpers.py
    • Added datetime helper functions.
  • packages/google-api-core/google/api_core/exceptions.py
    • Added custom exception classes.
  • packages/google-api-core/google/api_core/extended_operation.py
    • Added extended operation futures.
  • packages/google-api-core/google/api_core/future/init.py
    • Added futures package initialization.
  • packages/google-api-core/google/api_core/future/_helpers.py
    • Added private future helpers.
  • packages/google-api-core/google/api_core/future/async_future.py
    • Added asynchronous future implementation.
  • packages/google-api-core/google/api_core/future/base.py
    • Added base future classes.
  • packages/google-api-core/google/api_core/future/polling.py
    • Added polling future implementation.
  • packages/google-api-core/google/api_core/gapic_v1/init.py
    • Added GAPIC v1 package initialization.
  • packages/google-api-core/google/api_core/gapic_v1/client_info.py
    • Added GAPIC v1 client information.
  • packages/google-api-core/google/api_core/gapic_v1/config.py
    • Added GAPIC v1 configuration helpers.
  • packages/google-api-core/google/api_core/gapic_v1/config_async.py
    • Added asynchronous GAPIC v1 configuration helpers.
  • packages/google-api-core/google/api_core/gapic_v1/method.py
    • Added GAPIC v1 method wrapping helpers.
  • packages/google-api-core/google/api_core/gapic_v1/method_async.py
    • Added asynchronous GAPIC v1 method wrapping helpers.
  • packages/google-api-core/google/api_core/gapic_v1/routing_header.py
    • Added GAPIC v1 routing header helpers.
  • packages/google-api-core/google/api_core/general_helpers.py
    • Added general helper functions.
  • packages/google-api-core/google/api_core/grpc_helpers.py
    • Added gRPC helper functions.
  • packages/google-api-core/google/api_core/grpc_helpers_async.py
    • Added asynchronous gRPC helper functions.
  • packages/google-api-core/google/api_core/iam.py
    • Added IAM policy definitions.
  • packages/google-api-core/google/api_core/operation.py
    • Added long-running operation futures.
  • packages/google-api-core/google/api_core/operation_async.py
    • Added asynchronous long-running operation futures.
  • packages/google-api-core/google/api_core/operations_v1/init.py
    • Added operations v1 package initialization.
  • packages/google-api-core/google/api_core/operations_v1/abstract_operations_base_client.py
    • Added abstract base client for operations.
  • packages/google-api-core/google/api_core/operations_v1/abstract_operations_client.py
    • Added abstract operations client.
  • packages/google-api-core/google/api_core/operations_v1/operations_async_client.py
    • Added asynchronous operations client.
  • packages/google-api-core/google/api_core/operations_v1/operations_client.py
    • Added operations client.
  • packages/google-api-core/google/api_core/operations_v1/operations_client_config.py
    • Added operations client configuration.
  • packages/google-api-core/google/api_core/operations_v1/operations_rest_client_async.py
    • Added asynchronous REST operations client.
  • packages/google-api-core/google/api_core/operations_v1/pagers.py
    • Added operations pagers.
  • packages/google-api-core/google/api_core/operations_v1/pagers_async.py
    • Added asynchronous operations pagers.
  • packages/google-api-core/google/api_core/operations_v1/pagers_base.py
    • Added base operations pagers.
  • packages/google-api-core/google/api_core/operations_v1/transports/init.py
    • Added operations transports initialization.
  • packages/google-api-core/google/api_core/operations_v1/transports/base.py
    • Added base operations transport.
  • packages/google-api-core/google/api_core/operations_v1/transports/rest.py
    • Added REST operations transport.
  • packages/google-api-core/google/api_core/operations_v1/transports/rest_asyncio.py
    • Added asynchronous REST operations transport.
  • packages/google-api-core/google/api_core/page_iterator.py
    • Added page iterator utilities.
  • packages/google-api-core/google/api_core/page_iterator_async.py
    • Added asynchronous page iterator utilities.
  • packages/google-api-core/google/api_core/path_template.py
    • Added path template utilities.
  • packages/google-api-core/google/api_core/protobuf_helpers.py
    • Added protobuf helper functions.
  • packages/google-api-core/google/api_core/py.typed
    • Added PEP 561 marker file.
  • packages/google-api-core/google/api_core/rest_helpers.py
    • Added REST helper functions.
  • packages/google-api-core/google/api_core/rest_streaming.py
    • Added REST streaming helpers.
  • packages/google-api-core/google/api_core/rest_streaming_async.py
    • Added asynchronous REST streaming helpers.
  • packages/google-api-core/google/api_core/retry/init.py
    • Added retry package initialization.
  • packages/google-api-core/google/api_core/retry/retry_base.py
    • Added base retry classes and functions.
  • packages/google-api-core/google/api_core/retry/retry_streaming.py
    • Added streaming retry wrapper.
  • packages/google-api-core/google/api_core/retry/retry_streaming_async.py
    • Added asynchronous streaming retry wrapper.
  • packages/google-api-core/google/api_core/retry/retry_unary.py
    • Added unary retry helpers.
  • packages/google-api-core/google/api_core/retry/retry_unary_async.py
    • Added asynchronous unary retry helpers.
  • packages/google-api-core/google/api_core/retry_async.py
    • Added asynchronous retry utilities.
  • packages/google-api-core/google/api_core/timeout.py
    • Added timeout decorators.
  • packages/google-api-core/google/api_core/universe.py
    • Added universe domain helpers.
  • packages/google-api-core/google/api_core/version.py
    • Updated package version to 2.29.1.
  • packages/google-api-core/google/api_core/version_header.py
    • Added API version header utilities.
  • packages/google-api-core/noxfile.py
    • Added Nox configuration for testing.
  • packages/google-api-core/pyproject.toml
    • Added project configuration and dependencies.
  • packages/google-api-core/renovate.json
    • Added Renovate configuration.
  • packages/google-api-core/scripts/decrypt-secrets.sh
    • Added script for decrypting secrets.
  • packages/google-api-core/scripts/readme-gen/readme_gen.py
    • Added README generation script.
  • packages/google-api-core/scripts/readme-gen/templates/README.tmpl.rst
    • Added README template.
  • packages/google-api-core/scripts/readme-gen/templates/auth.tmpl.rst
    • Added authentication template.
  • packages/google-api-core/scripts/readme-gen/templates/auth_api_key.tmpl.rst
    • Added API key authentication template.
  • packages/google-api-core/scripts/readme-gen/templates/install_deps.tmpl.rst
    • Added install dependencies template.
  • packages/google-api-core/scripts/readme-gen/templates/install_portaudio.tmpl.rst
    • Added install PortAudio template.
  • packages/google-api-core/setup.py
    • Added setup script.
  • packages/google-api-core/testing/.gitignore
    • Added testing gitignore.
  • packages/google-api-core/testing/constraints-3.9.txt
    • Added Python 3.9 dependency constraints.
  • packages/google-api-core/testing/constraints-async-rest-3.9.txt
    • Added Python 3.9 async REST dependency constraints.
  • packages/google-api-core/tests/asyncio/future/test_async_future.py
    • Added asynchronous future unit tests.
  • packages/google-api-core/tests/asyncio/gapic/test_config_async.py
    • Added asynchronous GAPIC config unit tests.
  • packages/google-api-core/tests/asyncio/gapic/test_method_async.py
    • Added asynchronous GAPIC method unit tests.
  • packages/google-api-core/tests/asyncio/operations_v1/test_operations_async_client.py
    • Added asynchronous operations client unit tests.
  • packages/google-api-core/tests/asyncio/retry/test_retry_streaming_async.py
    • Added asynchronous streaming retry unit tests.
  • packages/google-api-core/tests/asyncio/retry/test_retry_unary_async.py
    • Added asynchronous unary retry unit tests.
  • packages/google-api-core/tests/asyncio/test_bidi_async.py
    • Added asynchronous bidirectional streaming unit tests.
Activity
  • The pull request was created by parthea.
  • The PR description explicitly states that it should be merged with a merge-commit to preserve git history, referencing issue Adopt split repo: _python-api-core_ #10892. This suggests a planned, significant structural change.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@parthea parthea self-assigned this Feb 13, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request migrates the google-api-core library into a sub-package structure. The migration appears comprehensive, including source code, tests, CI configurations, and documentation. My review focuses on improving the robustness of time-based logic, enhancing error handling for REST responses, and ensuring adherence to internal rules regarding dictionary serialization. Specifically, I recommend using monotonic time for throttling, handling potential JSON parsing errors in async REST transports, and programmatically sorting log dictionaries before serialization.

Comment on lines +57 to +59
def _process_chunk(self, chunk: str):
if self._level == 0:
if chunk[0] != "[":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing chunk[0] without checking if the chunk is empty will raise an IndexError. It's safer to ensure the chunk contains data before attempting to validate the start of the JSON array.

    def _process_chunk(self, chunk: str):
        if not chunk:
            return
        if self._level == 0:
            if chunk[0] != "[":

Comment on lines +183 to +199
with self._entry_lock:
cutoff_time = datetime.datetime.now() - self._time_window

# drop the entries that are too old, as they are no longer relevant
while self._past_entries and self._past_entries[0] < cutoff_time:
self._past_entries.popleft()

if len(self._past_entries) < self._access_limit:
self._past_entries.append(datetime.datetime.now())
return 0.0 # no waiting was needed

to_wait = (self._past_entries[0] - cutoff_time).total_seconds()
time.sleep(to_wait)

self._past_entries.append(datetime.datetime.now())
return to_wait

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using datetime.datetime.now() for interval calculations can be problematic if the system clock is adjusted. It is recommended to use time.monotonic() for measuring elapsed time and calculating wait durations to ensure robustness against clock jumps.

Suggested change
with self._entry_lock:
cutoff_time = datetime.datetime.now() - self._time_window
# drop the entries that are too old, as they are no longer relevant
while self._past_entries and self._past_entries[0] < cutoff_time:
self._past_entries.popleft()
if len(self._past_entries) < self._access_limit:
self._past_entries.append(datetime.datetime.now())
return 0.0 # no waiting was needed
to_wait = (self._past_entries[0] - cutoff_time).total_seconds()
time.sleep(to_wait)
self._past_entries.append(datetime.datetime.now())
return to_wait
def __enter__(self):
with self._entry_lock:
cutoff_time = time.monotonic() - self._time_window.total_seconds()
# drop the entries that are too old, as they are no longer relevant
while self._past_entries and self._past_entries[0] < cutoff_time:
self._past_entries.popleft()
if len(self._past_entries) < self._access_limit:
self._past_entries.append(time.monotonic())
return 0.0 # no waiting was needed
to_wait = self._past_entries[0] - cutoff_time
time.sleep(to_wait)
self._past_entries.append(time.monotonic())
return to_wait

value = getattr(record, field_name, None)
if value is not None:
log_obj[field_name] = value
return json.dumps(log_obj)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Per the general rules, dictionaries should be programmatically sorted before being serialized to ensure consistent key ordering in the output.

Suggested change
return json.dumps(log_obj)
return json.dumps(dict(sorted(log_obj.items())))
References
  1. To ensure dictionary keys remain sorted without manual effort, programmatically sort the dictionary before returning it (e.g., using dict(sorted(metadata.items()))) instead of relying on manual ordering in the code.


# Return the response
api_response = operations_pb2.ListOperationsResponse()
json_format.Parse(response.content, api_response, ignore_unknown_fields=False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Setting ignore_unknown_fields=False can cause the client to break if the server adds new fields to the response. It is generally safer to set this to True for forward compatibility, which is consistent with other parts of this library.

Suggested change
json_format.Parse(response.content, api_response, ignore_unknown_fields=False)
json_format.Parse(response.content, api_response, ignore_unknown_fields=True)

Comment on lines +308 to +310
payload = json.loads(content.decode("utf-8"))
request_url = "{host}{uri}".format(host=self._host, uri=uri)
raise core_exceptions.format_http_response_error(response, method, request_url, payload) # type: ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The response content might not be valid JSON (e.g., if an intermediate proxy returns an HTML error page). Parsing it directly with json.loads can raise a JSONDecodeError. It is safer to handle this exception and provide a fallback payload.

Suggested change
payload = json.loads(content.decode("utf-8"))
request_url = "{host}{uri}".format(host=self._host, uri=uri)
raise core_exceptions.format_http_response_error(response, method, request_url, payload) # type: ignore
decoded_content = content.decode("utf-8")
try:
payload = json.loads(decoded_content)
except json.JSONDecodeError:
payload = {"error": {"message": decoded_content or "unknown error"}}
request_url = "{host}{uri}".format(host=self._host, uri=uri)
raise core_exceptions.format_http_response_error(response, method, request_url, payload) # type: ignore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.