Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add support for protobuf 5.x #644

Merged
merged 14 commits into from
Jun 19, 2024
Merged

Conversation

parthea
Copy link
Collaborator

@parthea parthea commented Apr 27, 2024

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-label product-auto-label bot added the size: m Pull request size is medium. label Apr 27, 2024
@parthea parthea force-pushed the add-support-for-protobuf-5-x branch 7 times, most recently from f8f719b to a650198 Compare April 27, 2024 15:11
@parthea parthea force-pushed the add-support-for-protobuf-5-x branch from a650198 to ac9cad8 Compare April 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 team as code owners April 29, 2024 14:36
@parthea parthea added the owlbot:run Add this label to trigger the Owlbot post processor. label Apr 29, 2024
@gcf-owl-bot gcf-owl-bot bot removed the owlbot:run Add this label to trigger the Owlbot post processor. label Apr 29, 2024
@anndro
Copy link

anndro commented May 16, 2024

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

@zhangskz
Copy link

@parthea Is there anything blocking this PR still?

Copy link
Contributor

@vchudnov-g vchudnov-g left a comment

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
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
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)
transcoded_request = _transcode_request(request)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 5a49a53

noxfile.py Outdated Show resolved Hide resolved

if prerelease:
install_prerelease_dependencies(
session, f"{constraints_dir}/constraints-{PYTHON_VERSIONS[0]}.txt"
Copy link
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
Collaborator Author

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

def install_prerelease_dependencies(session, constraints_path):
with open(constraints_path, encoding="utf-8") as constraints_file:
constraints_text = constraints_file.read()
# Ignore leading whitespace and comment lines.
constraints_deps = [
match.group(1)
for match in re.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.

python-api-core/noxfile.py

Lines 99 to 100 in 7fbce0d

for dep in prerel_deps:
session.install("--pre", "--no-deps", "--upgrade", dep)

@@ -72,17 +76,46 @@ def blacken(session):
session.run("black", *BLACK_EXCLUDES, *BLACK_PATHS)


def default(session, install_grpc=True):
def install_prerelease_dependencies(session, constraints_path):
Copy link
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
Collaborator Author

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.

noxfile.py Outdated
def unit(session):
"""Run the unit test suite."""
default(session)


@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
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
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in e1efa83

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
option: ["", "_grpc_gcp", "_wo_grpc"]
option: ["", "_grpc_gcp", "_wo_grpc", "_prerelease"]
Copy link
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.9
         include:
          - option: "_prerelease"
            python: 3.12

Copy link
Collaborator Author

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

@parthea parthea assigned parthea and unassigned vchudnov-g and ohmayr Jun 4, 2024
@parthea parthea assigned ohmayr and unassigned parthea Jun 11, 2024
@parthea
Copy link
Collaborator Author

parthea commented Jun 11, 2024

@ohmayr PTAL

Comment on lines +17 to +19
from google.api_core.operations_v1.abstract_operations_client import (
AbstractOperationsClient,
)
Copy link
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
Collaborator Author

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

@@ -164,10 +234,10 @@ def lint_setup_py(session):
session.run("python", "setup.py", "check", "--restructuredtext", "--strict")


@nox.session(python="3.8")
@nox.session(python=DEFAULT_PYTHON_VERSION)
Copy link
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
Collaborator Author

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

@@ -199,7 +199,6 @@ def _list_operations(
json_format.ParseDict(transcoded_request["query_params"], query_params_request)
query_params = json_format.MessageToDict(
query_params_request,
including_default_value_fields=False,
preserving_proto_field_name=False,
use_integers_for_enums=False,
)
Copy link
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
Collaborator Author

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

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.

@parthea parthea assigned parthea and unassigned ohmayr Jun 19, 2024
@parthea parthea enabled auto-merge (squash) June 19, 2024 15:21
@parthea parthea merged commit fda0ca6 into main Jun 19, 2024
31 checks passed
@parthea parthea deleted the add-support-for-protobuf-5-x branch June 19, 2024 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size: m Pull request size is medium.
Projects
None yet
6 participants