Skip to content

Conversation

@parthea
Copy link
Contributor

@parthea parthea commented Dec 16, 2025

chore: librarian update image pull request: 20251216T195732Z

…prod/images-prod/python-librarian-generator@sha256:b8058df4c45e9a6e07f6b4d65b458d0d059241dd34c814f151c8bf6b89211209
@parthea parthea requested review from a team as code owners December 16, 2025 19:57
@parthea parthea requested a review from gkevinzheng December 16, 2025 19:57
@product-auto-label product-auto-label bot added the size: xl Pull request size is extra large. label Dec 16, 2025
@product-auto-label product-auto-label bot added the api: clouderrorreporting Issues related to the googleapis/python-error-reporting API. label Dec 16, 2025
@gemini-code-assist
Copy link

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 primarily focuses on a routine update to the python-librarian-generator image, which has triggered several automated changes across the codebase. Key updates include renaming owlbot.py files to librarian.py, refreshing documentation metadata such as copyright years and Sphinx version requirements, and introducing robust runtime checks for Python and google.protobuf dependency versions. Additionally, the handling of mTLS client certificates has been refactored for better consistency, and an obsolete fixup script has been removed, streamlining the project's maintenance.

Highlights

  • Librarian Image Update: The core change involves updating the python-librarian-generator image to a new SHA256 hash, indicating an update to the underlying generation tool.
  • Renaming of Owlbot to Librarian: Files previously named owlbot.py have been renamed to librarian.py, reflecting a shift in naming convention or tool identity.
  • Documentation Metadata Updates: The docs/conf.py file has been updated to reflect the new copyright year (2025), an increased Sphinx version requirement (from 1.5.5 to 4.5.0), and a change in the GitHub repository link.
  • Runtime Environment Checks: New logic has been introduced in __init__.py files to perform runtime checks for Python version compatibility (supporting Python 3.9+) and google.protobuf dependency versions (requiring 4.25.8+), issuing FutureWarning for unsupported versions.
  • mTLS Client Certificate Handling Refactoring: The logic for determining mTLS client certificate usage has been refactored into a new static method _use_client_cert_effective() within client service files, centralizing the decision-making process and improving robustness.
  • Removal of Fixup Script: A script named scripts/fixup_errorreporting_v1beta1_keywords.py has been removed, suggesting that its functionality is no longer required or has been integrated elsewhere.
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 changed the title chore: librarian update image pull request: 20251216T195732Z feat(gapic): support mTLS certificates when available Dec 16, 2025
Copy link

@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 appears to be an automated update from the librarian tool, primarily updating the generator image and applying the resulting changes. The changes include refactoring the mTLS client certificate logic for better maintainability, which is a positive improvement. I've identified a couple of areas for improvement in the newly generated code. Specifically, there's a bug in a new version parsing function in __init__.py that could lead to incorrect behavior, for which I've suggested a more robust fix. Additionally, a new test function in the unit tests is quite repetitive, and I've proposed a refactoring to make it more concise and maintainable using pytest's parameterization features.

Comment on lines +98 to +116
def parse_version_to_tuple(version_string: str):
"""Safely converts a semantic version string to a comparable tuple of integers.
Example: "4.25.8" -> (4, 25, 8)
Ignores non-numeric parts and handles common version formats.
Args:
version_string: Version string in the format "x.y.z" or "x.y.z<suffix>"
Returns:
Tuple of integers for the parsed version string.
"""
parts = []
for part in version_string.split("."):
try:
parts.append(int(part))
except ValueError:
# If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here.
# This is a simplification compared to 'packaging.parse_version', but sufficient
# for comparing strictly numeric semantic versions.
break
return tuple(parts)

Choose a reason for hiding this comment

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

medium

The custom parse_version_to_tuple implementation is buggy for versions with pre-release identifiers that are not separated by a dot (e.g., 1.2.3a1 would be incorrectly parsed as (1, 2) instead of (1, 2, 3)). This can lead to incorrect version comparisons.

Since google-api-core (a dependency of this library) already depends on the packaging library, you can use packaging.version.parse for a more robust and correct implementation. This avoids maintaining a custom, bug-prone parsing function.

        def parse_version_to_tuple(version_string: str):
            """Safely converts a semantic version string to a comparable tuple of integers.
            Example: "4.25.8" -> (4, 25, 8)
            Handles pre-release identifiers correctly.
            Args:
                version_string: Version string in semantic versioning format.
            Returns:
                Tuple of integers for the parsed version's release segment.
            """
            from packaging.version import parse as parse_version
            return parse_version(version_string).release

Comment on lines +222 to +319
def test_use_client_cert_effective():
# Test case 1: Test when `should_use_client_cert` returns True.
# We mock the `should_use_client_cert` function to simulate a scenario where
# the google-auth library supports automatic mTLS and determines that a
# client certificate should be used.
if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch(
"google.auth.transport.mtls.should_use_client_cert", return_value=True
):
assert ErrorGroupServiceClient._use_client_cert_effective() is True

# Test case 2: Test when `should_use_client_cert` returns False.
# We mock the `should_use_client_cert` function to simulate a scenario where
# the google-auth library supports automatic mTLS and determines that a
# client certificate should NOT be used.
if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch(
"google.auth.transport.mtls.should_use_client_cert", return_value=False
):
assert ErrorGroupServiceClient._use_client_cert_effective() is False

# Test case 3: Test when `should_use_client_cert` is unavailable and the
# `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true".
if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
assert ErrorGroupServiceClient._use_client_cert_effective() is True

# Test case 4: Test when `should_use_client_cert` is unavailable and the
# `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false".
if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch.dict(
os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}
):
assert ErrorGroupServiceClient._use_client_cert_effective() is False

# Test case 5: Test when `should_use_client_cert` is unavailable and the
# `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True".
if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}):
assert ErrorGroupServiceClient._use_client_cert_effective() is True

# Test case 6: Test when `should_use_client_cert` is unavailable and the
# `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False".
if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch.dict(
os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}
):
assert ErrorGroupServiceClient._use_client_cert_effective() is False

# Test case 7: Test when `should_use_client_cert` is unavailable and the
# `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE".
if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}):
assert ErrorGroupServiceClient._use_client_cert_effective() is True

# Test case 8: Test when `should_use_client_cert` is unavailable and the
# `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE".
if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch.dict(
os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}
):
assert ErrorGroupServiceClient._use_client_cert_effective() is False

# Test case 9: Test when `should_use_client_cert` is unavailable and the
# `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set.
# In this case, the method should return False, which is the default value.
if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch.dict(os.environ, clear=True):
assert ErrorGroupServiceClient._use_client_cert_effective() is False

# Test case 10: Test when `should_use_client_cert` is unavailable and the
# `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value.
# The method should raise a ValueError as the environment variable must be either
# "true" or "false".
if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch.dict(
os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}
):
with pytest.raises(ValueError):
ErrorGroupServiceClient._use_client_cert_effective()

# Test case 11: Test when `should_use_client_cert` is available and the
# `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value.
# The method should return False as the environment variable is set to an invalid value.
if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch.dict(
os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}
):
assert ErrorGroupServiceClient._use_client_cert_effective() is False

# Test case 12: Test when `should_use_client_cert` is available and the
# `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also,
# the GOOGLE_API_CONFIG environment variable is unset.
if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}):
with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}):
assert ErrorGroupServiceClient._use_client_cert_effective() is False

Choose a reason for hiding this comment

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

medium

The test test_use_client_cert_effective is quite long and contains a lot of repetitive code, especially for testing different casings of 'true' and 'false' for the environment variable. You can significantly shorten and simplify this test by using pytest.mark.parametrize and splitting the test logic based on the availability of should_use_client_cert.

@pytest.mark.skipif(not hasattr(google.auth.transport.mtls, "should_use_client_cert"), reason="google-auth does not have should_use_client_cert")
def test_use_client_cert_effective_with_should_use_client_cert():
    # Test that `should_use_client_cert` is used and the env var is ignored.
    with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
        with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=True):
            assert ErrorGroupServiceClient._use_client_cert_effective() is True

        with mock.patch("google.auth.transport.mtls.should_use_client_cert", return_value=False):
            assert ErrorGroupServiceClient._use_client_cert_effective() is False


@pytest.mark.skipif(hasattr(google.auth.transport.mtls, "should_use_client_cert"), reason="google-auth has should_use_client_cert")
class TestUseClientCertEffectiveEnvVar:
    @pytest.mark.parametrize("true_val", ["true", "True", "TRUE"])
    def test_env_var_true(self, true_val):
        with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": true_val}):
            assert ErrorGroupServiceClient._use_client_cert_effective() is True

    @pytest.mark.parametrize("false_val", ["false", "False", "FALSE"])
    def test_env_var_false(self, false_val):
        with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": false_val}):
            assert ErrorGroupServiceClient._use_client_cert_effective() is False

    def test_env_var_unset(self):
        with mock.patch.dict(os.environ, clear=True):
            assert ErrorGroupServiceClient._use_client_cert_effective() is False

    def test_env_var_invalid(self):
        with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}):
            with pytest.raises(ValueError):
                ErrorGroupServiceClient._use_client_cert_effective()

@parthea parthea merged commit 7e99258 into main Dec 16, 2025
27 of 28 checks passed
@parthea parthea deleted the librarian-20251216T195732Z branch December 16, 2025 20:10
daniel-sanche added a commit that referenced this pull request Dec 16, 2025
PR created by the Librarian CLI to initialize a release. Merging this PR
will auto trigger a release.

Librarian Version: v0.7.0
Language Image:
us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator@sha256:b8058df4c45e9a6e07f6b4d65b458d0d059241dd34c814f151c8bf6b89211209
<details><summary>google-cloud-error-reporting: 1.14.0</summary>

##
[1.14.0](v1.13.0...v1.14.0)
(2025-12-16)

### Features

* support mTLS certificates when available (#717)
([7e99258](7e99258b))

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

Labels

api: clouderrorreporting Issues related to the googleapis/python-error-reporting API. size: xl Pull request size is extra large.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants