[google-genai] Test instrumentation on google-genai v1.64.0 (#4253)

* [google-genai] Test instrumentation on google-genai v1.63.0

* Add package version upper bound

* bump latest version for python 3.9

* fix README

* bump google-auth version for python 3.9

* add package upper limit to pyproject.toml

* [google-genai] Test instrumentation on google-genai v1.64.0

* fix upper case method in cassette not matching lower case one generated by aiohttp

* fix async calls hanging in vcrpy

* Remove package upper limit

* fix import error in python 3.9

* fix google-genai module lower bound

* Add link to vcr issue

* Add comment about request method

* Fix lint errors

* Fix spellcheck

---------

Co-authored-by: Aaron Abbott <aaronabbott@google.com>
This commit is contained in:
Rima-ag
2026-02-27 06:29:04 +01:00
committed by GitHub
parent 8fec6b672e
commit e1c56f2fc5
4 changed files with 59 additions and 4 deletions

View File

@@ -3,7 +3,7 @@
| --------------- | ------------------ | --------------- | -------------- |
| [opentelemetry-instrumentation-anthropic](./opentelemetry-instrumentation-anthropic) | anthropic >= 0.16.0 | No | development
| [opentelemetry-instrumentation-claude-agent-sdk](./opentelemetry-instrumentation-claude-agent-sdk) | claude-agent-sdk >= 0.1.14 | No | development
| [opentelemetry-instrumentation-google-genai](./opentelemetry-instrumentation-google-genai) | google-genai >= 1.0.0 | No | development
| [opentelemetry-instrumentation-google-genai](./opentelemetry-instrumentation-google-genai) | google-genai >= 1.32.0 | No | development
| [opentelemetry-instrumentation-langchain](./opentelemetry-instrumentation-langchain) | langchain >= 0.3.21 | No | development
| [opentelemetry-instrumentation-openai-agents-v2](./opentelemetry-instrumentation-openai-agents-v2) | openai-agents >= 0.3.3 | No | development
| [opentelemetry-instrumentation-openai-v2](./opentelemetry-instrumentation-openai-v2) | openai >= 1.26.0 | Yes | development

View File

@@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
_instruments = ("google-genai >= 1.0.0",)
_instruments = ("google-genai >= 1.32.0",)

View File

@@ -40,6 +40,14 @@ import yaml
from google.genai import types
from vcr.record_mode import RecordMode
try:
# These modules are only supported in python >= 3.10
from aiohttp.client_exceptions import ClientConnectionError
from vcr.stubs import aiohttp_stubs
except ImportError:
ClientConnectionError = None
aiohttp_stubs = None
from opentelemetry.instrumentation._semconv import (
OTEL_SEMCONV_STABILITY_OPT_IN,
_OpenTelemetrySemanticConventionStability,
@@ -135,6 +143,9 @@ def _redact_headers(headers):
def _before_record_request(request):
# aiohttp reports the request method in lower case while it is recorded in the cassette in upper case.
if request.method:
request.method = request.method.upper()
if request.headers:
_redact_headers(request.headers)
uri = request.uri
@@ -316,6 +327,48 @@ def setup_vcr(vcr):
return vcr
@pytest.fixture(name="patch_vcr_aiohttp_stream", scope="module", autouse=True)
def fixture_patch_vcr_aiohttp_stream():
# Allows the async tests to not be stuck in infinite loop when streaming
# a VCR cassette with aiohttp stubs.
# https://github.com/kevin1024/vcrpy/issues/927
if ClientConnectionError is None or aiohttp_stubs is None:
return
class _ReplayMockStream(aiohttp_stubs.MockStream):
# Keep vcrpy's stream behavior, but ignore aiohttp's
# close-time ClientConnectionError("Connection closed") during
# cassette replay, where the full response is already buffered
# and this condition should be treated as normal EOF.
def set_exception(self, exc):
if isinstance(exc, ClientConnectionError) and exc.args == (
"Connection closed",
):
return
super().set_exception(exc)
class _ReplayMockClientResponse(aiohttp_stubs.MockClientResponse):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._mock_content_stream = None
@property
def content(self):
# vcrpy's aiohttp MockClientResponse.content creates a fresh stream object
# on every property access. google-genai async streaming repeatedly reads
# response.content.readline() and expects the same stream instance until EOF is
# reached.
if self._mock_content_stream is None:
body = self._body or b""
stream = _ReplayMockStream()
stream.feed_data(body)
stream.feed_eof()
self._mock_content_stream = stream
return self._mock_content_stream
aiohttp_stubs.MockClientResponse = _ReplayMockClientResponse
@pytest.fixture(name="instrumentor")
def fixture_instrumentor():
return GoogleGenAiSdkInstrumentor()

View File

@@ -40,8 +40,10 @@ pytest==7.4.4
pytest-asyncio==0.21.0
pytest-vcr==1.0.2
google-auth==2.38.0
google-genai==1.32.0
google-auth==2.47.0
google-genai==1.47.0; python_version < "3.10"
google-genai==1.64.0; python_version >= "3.10"
# Install locally from the folder. This path is relative to the
# root directory, given invocation from "tox" at root level.