Skip to content
This repository was archived by the owner on Feb 23, 2026. It is now read-only.

fix: add support for protobuf 5.x - #644

Merged
parthea merged 14 commits into
mainfrom
add-support-for-protobuf-5-x
Jun 19, 2024
Merged

fix: add support for protobuf 5.x#644
parthea merged 14 commits into
mainfrom
add-support-for-protobuf-5-x

Conversation

@parthea

@partheaparthea commented Apr 27, 2024

Copy link
Copy Markdown
Contributor

Fixes#628 🦕
Fixes#641 🦕
Fixes#642 🦕

Regarding the including_default_value_fields argument of json_format.MessageToDict() in protobuf:

In protobuf version 3.19.6 - The default value of including_default_value_fields was False
https://github.com/protocolbuffers/protobuf/blob/5cba162a5d93f8df786d828621019e03e50edb4f/python/google/protobuf/json_format.py#L92

At the time that the argument was removed in protobuf 5.x - the default value of including_default_value_fields was False
protocolbuffers/protobuf@2699579#diff-8de817c14d6a087981503c9aea38730b1b3e98f4e306db5ff9d525c7c304f234

IOW, setting argument including_default_value_fields to False had no effect as it was the default behaviour.

The Unit tests / unit_prerelease-3.12 presubmit check was added to run tests against the latest pre-release version of protobuf as several dependencies have a constraint on protobuf<5

@product-auto-labelproduct-auto-labelBot added the size: m Pull request size is medium. label Apr 27, 2024
@parthea
partheaforce-pushed the add-support-for-protobuf-5-x branch 7 times, most recently from f8f719b to a650198CompareApril 27, 2024 15:11
@parthea
partheaforce-pushed the add-support-for-protobuf-5-x branch from a650198 to ac9cad8CompareApril 27, 2024 15:12
@parthea
parthea marked this pull request as ready for review April 29, 2024 14:36
@parthea
parthea requested review from a teamApril 29, 2024 14:36
@partheaparthea added the owlbot:run Add this label to trigger the Owlbot post processor. label Apr 29, 2024
@gcf-owl-botgcf-owl-botBot removed the owlbot:run Add this label to trigger the Owlbot post processor. label Apr 29, 2024
@anndro

Copy link
Copy Markdown

Hello @parthea is there any scheduled date for release this pull request?

@zhangskz

Copy link
Copy Markdown

@parthea Is there anything blocking this PR still?

@vchudnov-gvchudnov-g left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A couple of suggestions, and some questions, but nothing major. This looks good!

Comment on lines 191 to 207
# For backwards compatibility with protobuf 3.x 4.x
# Remove once support for protobuf 3.x and 4.x is dropped
# https://github.com/googleapis/python-api-core/issues/643
if PROTOBUF_VERSION[0:2] in ["3.", "4."]:
request_kwargs = json_format.MessageToDict(
request,
preserving_proto_field_name=True,
including_default_value_fields=True, # type: ignore # backward compatibility
)
else:
request_kwargs = json_format.MessageToDict(
request,
preserving_proto_field_name=True,
always_print_fields_with_no_presence=True,
)

transcoded_request = path_template.transcode(http_options, **request_kwargs)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You have this block repeated in four places. I suggest factoring it out into a helper function that only needs to take one parameter:

Suggested change
# For backwards compatibility with protobuf 3.x 4.x
# Remove once support for protobuf 3.x and 4.x is dropped
# https://github.com/googleapis/python-api-core/issues/643
ifPROTOBUF_VERSION[0:2] in ["3.", "4."]:
request_kwargs=json_format.MessageToDict(
request,
preserving_proto_field_name=True,
including_default_value_fields=True, # type: ignore # backward compatibility
)
else:
request_kwargs=json_format.MessageToDict(
request,
preserving_proto_field_name=True,
always_print_fields_with_no_presence=True,
)
transcoded_request=path_template.transcode(http_options, **request_kwargs)
transcoded_request=_transcode_request(request)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in 5a49a53

Comment threadnoxfile.py Outdated
Comment threadnoxfile.py

if prerelease:
install_prerelease_dependencies(
session, f"{constraints_dir}/constraints-{PYTHON_VERSIONS[0]}.txt"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm confused: in line 206, where we call default(..., prerelease=True), the decorator constrains python=PYTHON_VERSIONS[-1]. But here we are referencing the constraints for PYTHON_VERSIONS[0]. Could you clarify?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As per the comment in below, the constraints file for the lowest supported python version contains a list of all of the dependencies of the library. The function install_prerelease_dependencies will extract the dependencies from the file.

# This constraints file is used to check that lower bounds
# are correct in setup.py
# List *all* library dependencies and extras in this file.
# Pin the version to the lower bound.
#
# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev",
# Then this file should have foo==1.14.0

definstall_prerelease_dependencies(session, constraints_path):
withopen(constraints_path, encoding="utf-8") asconstraints_file:
constraints_text=constraints_file.read()
# Ignore leading whitespace and comment lines.
constraints_deps= [
match.group(1)
formatchinre.finditer(
r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE
)
]

Once we have a list of dependencies, we will install them independently with the --pre and --no-deps option. `--upgrade is also added to ensure that we get the latest pre-release.

fordepinprerel_deps:
session.install("--pre", "--no-deps", "--upgrade", dep)

Comment threadnoxfile.py


def default(session, install_grpc=True):
def install_prerelease_dependencies(session, constraints_path):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I have gaps in my mental model for testing prerelease;

This installs our dependencies at pre-release versions, right?

Is the only difference, then, the use of --pre below? If it's the same set of dependencies, it seems it would be clearer to have them loaded in the same place for pre-release and stable versions, and add the extra install parameters conditionally on each thing we install.

(It might be easier to talk synchronously about this.)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

There is a difference in that we don't allow transitive dependencies in the install_prerelease_dependencies session as we want to ensure that we're installing the pre-release version of each dependency. In the non-prerelease session, we are installing transitive dependencies.

Comment threadnoxfile.py Outdated

@nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"])
@nox.session(python=PYTHON_VERSIONS[-1])
def unit_prerelease(session):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

So this tests running against the pre-release versions of the dependencies, right? And we only bother to do this with the latest Python run-time.

A comment might be helpful. Also, my personal preference would to rename this (and similar code elsewhere) as unit_with_prerelease_deps. Every time I read something like unit_prerelease my mind first assumes we're testing the pre-release version of this library, not of its dependencies.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in e1efa83

Comment thread.github/workflows/unittest.yml Outdated
strategy:
matrix:
option: ["", "_grpc_gcp", "_wo_grpc"]
option: ["", "_grpc_gcp", "_wo_grpc", "_prerelease"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this more succinct code should work (I haven't tested it) and would be easier to maintain.
Ref: https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#expanding-or-adding-matrix-configurations

option: ["", "_grpc_gcp", "_wo_grpc"]
python:
-"3.7"-"3.8"-"3.9"-"3.10"-"3.11"-"3.12"exclude:
-option: "_wo_grpc"python: 3.7-option: "_wo_grpc"python: 3.8-option: "_wo_grpc"python: 3.9include:
-option: "_prerelease"python: 3.12

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This comment is obsolete with the changes in e1efa83

@partheaparthea assigned parthea and unassigned vchudnov-g and ohmayrJun 4, 2024
@partheaparthea assigned ohmayr and unassigned partheaJun 11, 2024
@parthea

Copy link
Copy Markdown
ContributorAuthor

@ohmayr PTAL

Comment on lines +17 to +19
from google.api_core.operations_v1.abstract_operations_client import (
AbstractOperationsClient,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is this file changed?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I ran black on all of the files and this file was formatted

Comment threadnoxfile.py


@nox.session(python="3.8")
@nox.session(python=DEFAULT_PYTHON_VERSION)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just to clarify, do we want to run this against all versions?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

We normally only run it on 1 version but we can expand it if there is value

including_default_value_fields=False,
preserving_proto_field_name=False,
use_integers_for_enums=False,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is essentially also converting a message to a dict. So we could use a similar approach to what we're doing for request_params and define a helper function so we're consistent. But it's more of a preference and could be a follow up.

I'll leave it up to you since this isn't a blocker!

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I took a closer look at making this change and I don't believe the helper function will result in fewer lines of code. The reason that we had the helper function elsewhere was to remove duplication for the protobuf 3.x/4.x compatibility code but we don't have the duplication here.

@JackCloudman

Copy link
Copy Markdown

Hello, I am eagerly anticipating the next release! Could you please provide any updates on the release date? Thank the whole team for your hard work and dedication.

@partheaparthea assigned parthea and unassigned ohmayrJun 19, 2024
@parthea
parthea enabled auto-merge (squash) June 19, 2024 15:21
@parthea
parthea merged commit fda0ca6 into mainJun 19, 2024
@parthea
parthea deleted the add-support-for-protobuf-5-x branch June 19, 2024 15:22
This was referenced May 30, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

size: mPull request size is medium.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mypy presubmit fails with types-protobuf==5.x Add pre-release testing Support protobuf 5.26.0 when released

6 participants

@parthea@anndro@zhangskz@JackCloudman@vchudnov-g@ohmayr