Skip to content

Commit 5dfe192

Browse files
committed
Pretty format yaml cassettes
1 parent b25a9e4 commit 5dfe192

File tree

3 files changed

+143
-26
lines changed

3 files changed

+143
-26
lines changed

instrumentation-genai/opentelemetry-instrumentation-vertexai-v2/tests/cassettes/test_vertexai_generate_content.yaml

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
11
interactions:
22
- request:
3-
body: "{\n \"contents\": [\n {\n \"role\": \"user\",\n \"parts\":
4-
[\n {\n \"fileData\": {\n \"mimeType\": \"image/jpeg\",\n
5-
\ \"fileUri\": \"gs://generativeai-downloads/images/scones.jpg\"\n
6-
\ }\n },\n {\n \"text\": \"what is shown in this
7-
image?\"\n }\n ]\n }\n ]\n}"
3+
body: |-
4+
{
5+
"contents": [
6+
{
7+
"role": "user",
8+
"parts": [
9+
{
10+
"fileData": {
11+
"mimeType": "image/jpeg",
12+
"fileUri": "gs://generativeai-downloads/images/scones.jpg"
13+
}
14+
},
15+
{
16+
"text": "what is shown in this image?"
17+
}
18+
]
19+
}
20+
]
21+
}
822
headers:
923
Accept:
1024
- '*/*'
@@ -22,26 +36,60 @@ interactions:
2236
uri: https://us-central1-aiplatform.googleapis.com/v1beta1/projects/fake-project/locations/us-central1/publishers/google/models/gemini-pro-vision:generateContent?%24alt=json%3Benum-encoding%3Dint
2337
response:
2438
body:
25-
string: "{\n \"candidates\": [\n {\n \"content\": {\n \"role\":
26-
\"model\",\n \"parts\": [\n {\n \"text\": \" The
27-
image shows a table with a cup of coffee, a bowl of blueberries, and a plate
28-
of scones. There are also some flowers on the table.\"\n }\n ]\n
29-
\ },\n \"finishReason\": 1,\n \"safetyRatings\": [\n {\n
30-
\ \"category\": 1,\n \"probability\": 1,\n \"probabilityScore\":
31-
0.02331543,\n \"severity\": 1,\n \"severityScore\": 0.05493164\n
32-
\ },\n {\n \"category\": 2,\n \"probability\":
33-
1,\n \"probabilityScore\": 0.026367188,\n \"severity\":
34-
1,\n \"severityScore\": 0.05493164\n },\n {\n \"category\":
35-
3,\n \"probability\": 1,\n \"probabilityScore\": 0.046142578,\n
36-
\ \"severity\": 1,\n \"severityScore\": 0.030639648\n },\n
37-
\ {\n \"category\": 4,\n \"probability\": 1,\n \"probabilityScore\":
38-
0.080566406,\n \"severity\": 1,\n \"severityScore\": 0.095214844\n
39-
\ }\n ],\n \"avgLogprobs\": -0.11595650642148909\n }\n
40-
\ ],\n \"usageMetadata\": {\n \"promptTokenCount\": 265,\n \"candidatesTokenCount\":
41-
31,\n \"totalTokenCount\": 296\n },\n \"modelVersion\": \"gemini-pro-vision\"\n}\n"
39+
string: |-
40+
{
41+
"candidates": [
42+
{
43+
"content": {
44+
"role": "model",
45+
"parts": [
46+
{
47+
"text": " The image shows a table with a cup of coffee, a bowl of blueberries, and a plate of scones with blueberries on top. There are also pink flowers on the table."
48+
}
49+
]
50+
},
51+
"finishReason": 1,
52+
"safetyRatings": [
53+
{
54+
"category": 1,
55+
"probability": 1,
56+
"probabilityScore": 0.025512695,
57+
"severity": 1,
58+
"severityScore": 0.06933594
59+
},
60+
{
61+
"category": 2,
62+
"probability": 1,
63+
"probabilityScore": 0.026367188,
64+
"severity": 1,
65+
"severityScore": 0.07080078
66+
},
67+
{
68+
"category": 3,
69+
"probability": 1,
70+
"probabilityScore": 0.041503906,
71+
"severity": 1,
72+
"severityScore": 0.03466797
73+
},
74+
{
75+
"category": 4,
76+
"probability": 1,
77+
"probabilityScore": 0.091308594,
78+
"severity": 1,
79+
"severityScore": 0.09033203
80+
}
81+
],
82+
"avgLogprobs": -0.09557106835501535
83+
}
84+
],
85+
"usageMetadata": {
86+
"promptTokenCount": 265,
87+
"candidatesTokenCount": 35,
88+
"totalTokenCount": 300
89+
},
90+
"modelVersion": "gemini-pro-vision"
91+
}
4292
headers:
43-
Cache-Control:
44-
- private
4593
Content-Type:
4694
- application/json; charset=UTF-8
4795
Transfer-Encoding:
@@ -51,7 +99,7 @@ interactions:
5199
- X-Origin
52100
- Referer
53101
content-length:
54-
- '1275'
102+
- '1299'
55103
status:
56104
code: 200
57105
message: OK

instrumentation-genai/opentelemetry-instrumentation-vertexai-v2/tests/conftest.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"""Unit tests configuration module."""
22

3+
import json
34
import re
45
from typing import Any, Mapping, MutableMapping
56

67
import pytest
78
import vertexai
9+
import yaml
810
from google.auth.credentials import AnonymousCredentials
911
from vcr import VCR
1012
from vcr.record_mode import RecordMode
@@ -97,3 +99,70 @@ def before_response_cb(response: MutableMapping[str, Any]):
9799
"before_record_response": before_response_cb,
98100
"ignore_hosts": ["oauth2.googleapis.com"],
99101
}
102+
103+
104+
class LiteralBlockScalar(str):
105+
"""Formats the string as a literal block scalar, preserving whitespace and
106+
without interpreting escape characters"""
107+
108+
109+
def literal_block_scalar_presenter(dumper, data):
110+
"""Represents a scalar string as a literal block, via '|' syntax"""
111+
return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
112+
113+
114+
yaml.add_representer(LiteralBlockScalar, literal_block_scalar_presenter)
115+
116+
117+
def process_string_value(string_value):
118+
"""Pretty-prints JSON or returns long strings as a LiteralBlockScalar"""
119+
try:
120+
json_data = json.loads(string_value)
121+
return LiteralBlockScalar(json.dumps(json_data, indent=2))
122+
except (ValueError, TypeError):
123+
if len(string_value) > 80:
124+
return LiteralBlockScalar(string_value)
125+
return string_value
126+
127+
128+
def convert_body_to_literal(data):
129+
"""Searches the data for body strings, attempting to pretty-print JSON"""
130+
if isinstance(data, dict):
131+
for key, value in data.items():
132+
# Handle response body case (e.g., response.body.string)
133+
if key == "body" and isinstance(value, dict) and "string" in value:
134+
value["string"] = process_string_value(value["string"])
135+
136+
# Handle request body case (e.g., request.body)
137+
elif key == "body" and isinstance(value, str):
138+
data[key] = process_string_value(value)
139+
140+
else:
141+
convert_body_to_literal(value)
142+
143+
elif isinstance(data, list):
144+
for idx, choice in enumerate(data):
145+
data[idx] = convert_body_to_literal(choice)
146+
147+
return data
148+
149+
150+
class PrettyPrintJSONBody:
151+
"""This makes request and response body recordings more readable."""
152+
153+
@staticmethod
154+
def serialize(cassette_dict):
155+
cassette_dict = convert_body_to_literal(cassette_dict)
156+
return yaml.dump(
157+
cassette_dict, default_flow_style=False, allow_unicode=True
158+
)
159+
160+
@staticmethod
161+
def deserialize(cassette_string):
162+
return yaml.load(cassette_string, Loader=yaml.Loader)
163+
164+
165+
@pytest.fixture(scope="module", autouse=True)
166+
def fixture_vcr(vcr):
167+
vcr.register_serializer("yaml", PrettyPrintJSONBody)
168+
return vcr

instrumentation-genai/opentelemetry-instrumentation-vertexai-v2/tests/test_gemini.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def test_vertexai_generate_content(exporter):
3030
"gen_ai.operation.name": "text_completion",
3131
"gen_ai.request.model": "gemini-pro-vision",
3232
"gen_ai.response.model": "gemini-pro-vision",
33-
"gen_ai.usage.output_tokens": 31,
33+
"gen_ai.usage.output_tokens": 35,
3434
"gen_ai.usage.input_tokens": 265,
3535
}
3636

0 commit comments

Comments
 (0)