braintrust 0.3.13__py3-none-any.whl → 0.3.14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- braintrust/gitutil.py +4 -0
- braintrust/logger.py +1 -1
- braintrust/score.py +1 -0
- braintrust/test_score.py +157 -0
- braintrust/version.py +2 -2
- {braintrust-0.3.13.dist-info → braintrust-0.3.14.dist-info}/METADATA +1 -1
- {braintrust-0.3.13.dist-info → braintrust-0.3.14.dist-info}/RECORD +10 -9
- {braintrust-0.3.13.dist-info → braintrust-0.3.14.dist-info}/WHEEL +0 -0
- {braintrust-0.3.13.dist-info → braintrust-0.3.14.dist-info}/entry_points.txt +0 -0
- {braintrust-0.3.13.dist-info → braintrust-0.3.14.dist-info}/top_level.txt +0 -0
braintrust/gitutil.py
CHANGED
|
@@ -88,8 +88,12 @@ def get_past_n_ancestors(n=1000, remote=None):
|
|
|
88
88
|
if ancestor_output is None:
|
|
89
89
|
return
|
|
90
90
|
ancestor = repo.commit(ancestor_output)
|
|
91
|
+
count = 0
|
|
91
92
|
for _ in range(n):
|
|
93
|
+
if count >= n:
|
|
94
|
+
break
|
|
92
95
|
yield ancestor.hexsha
|
|
96
|
+
count += 1
|
|
93
97
|
try:
|
|
94
98
|
if ancestor.parents:
|
|
95
99
|
ancestor = ancestor.parents[0]
|
braintrust/logger.py
CHANGED
|
@@ -1104,7 +1104,7 @@ class _HTTPBackgroundLogger:
|
|
|
1104
1104
|
_HTTPBackgroundLogger._write_payload_to_dir(payload_dir=self.all_publish_payloads_dir, payload=dataStr)
|
|
1105
1105
|
for i in range(self.num_tries):
|
|
1106
1106
|
start_time = time.time()
|
|
1107
|
-
resp = conn.post("/logs3", data=dataStr)
|
|
1107
|
+
resp = conn.post("/logs3", data=dataStr.encode("utf-8"))
|
|
1108
1108
|
if resp.ok:
|
|
1109
1109
|
return
|
|
1110
1110
|
resp_errmsg = f"{resp.status_code}: {resp.text}"
|
braintrust/score.py
CHANGED
braintrust/test_score.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import unittest
|
|
3
|
+
|
|
4
|
+
from .score import Score
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestScore(unittest.TestCase):
|
|
8
|
+
def test_as_dict_includes_all_required_fields(self):
|
|
9
|
+
"""Test that as_dict() includes name, score, and metadata fields."""
|
|
10
|
+
score = Score(name="test_scorer", score=0.85, metadata={"key": "value"})
|
|
11
|
+
result = score.as_dict()
|
|
12
|
+
|
|
13
|
+
self.assertIn("name", result)
|
|
14
|
+
self.assertIn("score", result)
|
|
15
|
+
self.assertIn("metadata", result)
|
|
16
|
+
|
|
17
|
+
self.assertEqual(result["name"], "test_scorer")
|
|
18
|
+
self.assertEqual(result["score"], 0.85)
|
|
19
|
+
self.assertEqual(result["metadata"], {"key": "value"})
|
|
20
|
+
|
|
21
|
+
def test_as_dict_with_null_score(self):
|
|
22
|
+
"""Test that as_dict() works correctly with null score."""
|
|
23
|
+
score = Score(name="null_scorer", score=None, metadata={})
|
|
24
|
+
result = score.as_dict()
|
|
25
|
+
|
|
26
|
+
self.assertEqual(result["name"], "null_scorer")
|
|
27
|
+
self.assertIsNone(result["score"])
|
|
28
|
+
self.assertEqual(result["metadata"], {})
|
|
29
|
+
|
|
30
|
+
def test_as_dict_with_empty_metadata(self):
|
|
31
|
+
"""Test that as_dict() works correctly with empty metadata."""
|
|
32
|
+
score = Score(name="empty_metadata_scorer", score=1.0)
|
|
33
|
+
result = score.as_dict()
|
|
34
|
+
|
|
35
|
+
self.assertEqual(result["name"], "empty_metadata_scorer")
|
|
36
|
+
self.assertEqual(result["score"], 1.0)
|
|
37
|
+
self.assertEqual(result["metadata"], {})
|
|
38
|
+
|
|
39
|
+
def test_as_dict_with_complex_metadata(self):
|
|
40
|
+
"""Test that as_dict() works correctly with complex nested metadata."""
|
|
41
|
+
complex_metadata = {
|
|
42
|
+
"reason": "Test reason",
|
|
43
|
+
"details": {"nested": {"deeply": "value"}},
|
|
44
|
+
"list": [1, 2, 3],
|
|
45
|
+
"bool": True,
|
|
46
|
+
}
|
|
47
|
+
score = Score(name="complex_scorer", score=0.5, metadata=complex_metadata)
|
|
48
|
+
result = score.as_dict()
|
|
49
|
+
|
|
50
|
+
self.assertEqual(result["name"], "complex_scorer")
|
|
51
|
+
self.assertEqual(result["score"], 0.5)
|
|
52
|
+
self.assertEqual(result["metadata"], complex_metadata)
|
|
53
|
+
|
|
54
|
+
def test_as_json_serialization(self):
|
|
55
|
+
"""Test that as_json() produces valid JSON string."""
|
|
56
|
+
score = Score(name="json_scorer", score=0.75, metadata={"test": "data"})
|
|
57
|
+
json_str = score.as_json()
|
|
58
|
+
|
|
59
|
+
# Should be valid JSON
|
|
60
|
+
parsed = json.loads(json_str)
|
|
61
|
+
|
|
62
|
+
self.assertEqual(parsed["name"], "json_scorer")
|
|
63
|
+
self.assertEqual(parsed["score"], 0.75)
|
|
64
|
+
self.assertEqual(parsed["metadata"], {"test": "data"})
|
|
65
|
+
|
|
66
|
+
def test_from_dict_round_trip(self):
|
|
67
|
+
"""Test that Score can be serialized to dict and deserialized back."""
|
|
68
|
+
original = Score(
|
|
69
|
+
name="round_trip_scorer", score=0.95, metadata={"info": "test"}
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Serialize to dict
|
|
73
|
+
as_dict = original.as_dict()
|
|
74
|
+
|
|
75
|
+
# Deserialize from dict
|
|
76
|
+
restored = Score.from_dict(as_dict)
|
|
77
|
+
|
|
78
|
+
self.assertEqual(restored.name, original.name)
|
|
79
|
+
self.assertEqual(restored.score, original.score)
|
|
80
|
+
self.assertEqual(restored.metadata, original.metadata)
|
|
81
|
+
|
|
82
|
+
def test_array_of_scores_serialization(self):
|
|
83
|
+
"""Test that arrays of Score objects can be serialized correctly."""
|
|
84
|
+
scores = [
|
|
85
|
+
Score(name="score_1", score=0.8, metadata={"index": 1}),
|
|
86
|
+
Score(name="score_2", score=0.6, metadata={"index": 2}),
|
|
87
|
+
Score(name="score_3", score=None, metadata={}),
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
# Serialize each score
|
|
91
|
+
serialized = [s.as_dict() for s in scores]
|
|
92
|
+
|
|
93
|
+
# Check that all scores have required fields
|
|
94
|
+
for i, s_dict in enumerate(serialized):
|
|
95
|
+
self.assertIn("name", s_dict)
|
|
96
|
+
self.assertIn("score", s_dict)
|
|
97
|
+
self.assertIn("metadata", s_dict)
|
|
98
|
+
self.assertEqual(s_dict["name"], f"score_{i + 1}")
|
|
99
|
+
|
|
100
|
+
# Check specific values
|
|
101
|
+
self.assertEqual(serialized[0]["score"], 0.8)
|
|
102
|
+
self.assertEqual(serialized[1]["score"], 0.6)
|
|
103
|
+
self.assertIsNone(serialized[2]["score"])
|
|
104
|
+
|
|
105
|
+
def test_array_of_scores_json_serialization(self):
|
|
106
|
+
"""Test that arrays of Score objects can be JSON serialized."""
|
|
107
|
+
scores = [
|
|
108
|
+
Score(name="json_score_1", score=0.9),
|
|
109
|
+
Score(name="json_score_2", score=0.7),
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
# Serialize to JSON
|
|
113
|
+
serialized = [s.as_dict() for s in scores]
|
|
114
|
+
json_str = json.dumps(serialized)
|
|
115
|
+
|
|
116
|
+
# Parse back
|
|
117
|
+
parsed = json.loads(json_str)
|
|
118
|
+
|
|
119
|
+
self.assertEqual(len(parsed), 2)
|
|
120
|
+
self.assertEqual(parsed[0]["name"], "json_score_1")
|
|
121
|
+
self.assertEqual(parsed[0]["score"], 0.9)
|
|
122
|
+
self.assertEqual(parsed[1]["name"], "json_score_2")
|
|
123
|
+
self.assertEqual(parsed[1]["score"], 0.7)
|
|
124
|
+
|
|
125
|
+
def test_score_validation_enforces_bounds(self):
|
|
126
|
+
"""Test that Score validates score values are between 0 and 1."""
|
|
127
|
+
# Valid scores
|
|
128
|
+
Score(name="valid_0", score=0.0)
|
|
129
|
+
Score(name="valid_1", score=1.0)
|
|
130
|
+
Score(name="valid_mid", score=0.5)
|
|
131
|
+
Score(name="valid_null", score=None)
|
|
132
|
+
|
|
133
|
+
# Invalid scores
|
|
134
|
+
with self.assertRaises(ValueError):
|
|
135
|
+
Score(name="invalid_negative", score=-0.1)
|
|
136
|
+
|
|
137
|
+
with self.assertRaises(ValueError):
|
|
138
|
+
Score(name="invalid_over_one", score=1.1)
|
|
139
|
+
|
|
140
|
+
def test_score_does_not_include_deprecated_error_field(self):
|
|
141
|
+
"""Test that as_dict() does not include the deprecated error field."""
|
|
142
|
+
score = Score(name="test_scorer", score=0.5)
|
|
143
|
+
result = score.as_dict()
|
|
144
|
+
|
|
145
|
+
# The error field should not be in the serialized output
|
|
146
|
+
self.assertNotIn("error", result)
|
|
147
|
+
|
|
148
|
+
# Even if error was set (though deprecated), it shouldn't be in as_dict
|
|
149
|
+
score_with_error = Score(name="error_scorer", score=0.5)
|
|
150
|
+
score_with_error.error = Exception("test") # Set after construction
|
|
151
|
+
result_with_error = score_with_error.as_dict()
|
|
152
|
+
|
|
153
|
+
self.assertNotIn("error", result_with_error)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
if __name__ == "__main__":
|
|
157
|
+
unittest.main()
|
braintrust/version.py
CHANGED
|
@@ -10,11 +10,11 @@ braintrust/framework.py,sha256=Uf2DogzQG4suCcmABeQzc-5SWCO5tB2ic1OeQFZo_o4,57618
|
|
|
10
10
|
braintrust/framework2.py,sha256=DTnCql0_Be9kYZ7QkgJHEUAW4_tU-vuqni3vxdCcnyk,16784
|
|
11
11
|
braintrust/generated_types.py,sha256=StMC58Mg_Imc4Z-xpLzqZql2E5K14b92FAnxj0aOrtw,4521
|
|
12
12
|
braintrust/git_fields.py,sha256=oT1h1nVkidGrIIamtIQfOpbuEzd1n-nup9bx54J_u0A,1480
|
|
13
|
-
braintrust/gitutil.py,sha256=
|
|
13
|
+
braintrust/gitutil.py,sha256=01hCZG291992Knj9q1gOjb42XvfzruMm5yeA68FufAw,5676
|
|
14
14
|
braintrust/graph_util.py,sha256=lABIOMzxHf6E5LfDYfqa4OUR4uaW7xgUYNq5WGewD4w,5594
|
|
15
15
|
braintrust/http_headers.py,sha256=9ZsDcsAKG04SGowsgchZktD6rG_oSTKWa8QyGUPA4xE,154
|
|
16
16
|
braintrust/id_gen.py,sha256=PVkz-pS-9AzgmnAgpV-jgOFFo4hfl6e3IP9dVt6FouQ,1595
|
|
17
|
-
braintrust/logger.py,sha256=
|
|
17
|
+
braintrust/logger.py,sha256=Pesk94By7gPiVLoqA7NJjlLq4XslP7EmioRrusjVd6c,210576
|
|
18
18
|
braintrust/merge_row_batch.py,sha256=NX4jRE9uuFB3Z7btrarQp_di84_NGTjvzpJhksn82W8,9882
|
|
19
19
|
braintrust/oai.py,sha256=DW_i6bXXDprwZ_uwcdIE25MUxx5y5DDdqr0ucdIWP9I,33187
|
|
20
20
|
braintrust/object.py,sha256=vYLyYWncsqLD00zffZUJwGTSkcJF9IIXmgIzrx3Np5c,632
|
|
@@ -23,7 +23,7 @@ braintrust/prompt.py,sha256=c7UR-UeJ8Hf-DGyFRyUxSgXEOkZFhVd9-IhvyPhy1xI,1938
|
|
|
23
23
|
braintrust/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
braintrust/queue.py,sha256=5Mjb5FvqC9hq9f4qykCQIxrZ8MFrQlCvf7XIlKyYRGA,3738
|
|
25
25
|
braintrust/resource_manager.py,sha256=Rs4yEd_ShV5YV6WC0YqxkQKXEfBtbTUZ4S4G78oF5Mk,723
|
|
26
|
-
braintrust/score.py,sha256=
|
|
26
|
+
braintrust/score.py,sha256=44MyCUiMb9Bn1kyYqa3Kej33Cx2-5MnQ-_Rcl5pJfQw,3663
|
|
27
27
|
braintrust/serializable_data_class.py,sha256=TjlLpUmVAJ_VW7-aiEecBVQ5d3k4bgQsVeJo_5yIAU0,2471
|
|
28
28
|
braintrust/span_identifier_v1.py,sha256=_i33QR-LIalyBkV28cWWh0OUPtA7cjv-VCc894-XdD0,5209
|
|
29
29
|
braintrust/span_identifier_v2.py,sha256=qLi2iXs-KmIfrQ3BjW6_yLpMYqKh-7_LrotiR4cplwc,9024
|
|
@@ -37,12 +37,13 @@ braintrust/test_id_gen.py,sha256=mgArTyEBV-Xv21ARHPSHEPBsJshZrvIiPjBLNOKsAko,249
|
|
|
37
37
|
braintrust/test_logger.py,sha256=Z3euqSHmc4kqsyKo838tkYGK8B1rTkIdxl7QZYR1CLk,98516
|
|
38
38
|
braintrust/test_otel.py,sha256=janmEtu6dyFQL8N68WjRTS-65Kr5vSNSSwIaBWqXlyw,27243
|
|
39
39
|
braintrust/test_queue.py,sha256=MdH6R9uSk_4akY4Db514Cpukwiy2RJ76Lqts1nQwZJY,8432
|
|
40
|
+
braintrust/test_score.py,sha256=3hgwO_g_yq9VxX6no2YXfEMpBegVeUYLPh0NX4T5rHs,5879
|
|
40
41
|
braintrust/test_serializable_data_class.py,sha256=b04Ym64YtC6GJRGbKIN4J20RG1QN1FlnODwtEQh4sv0,1897
|
|
41
42
|
braintrust/test_span_components.py,sha256=UnF6ZL4k41XZ-CnfbjuqLeK4MZLtHTMdID3CMh3g1os,16344
|
|
42
43
|
braintrust/test_util.py,sha256=gyqe2JspRP7oXlp6ENztZe2fdRTOEMZMKpQi00y1DSc,4538
|
|
43
44
|
braintrust/test_version.py,sha256=hk5JKjEFbNJ_ONc1VEkqHquflzre34RpFhCEYLTK8iA,1051
|
|
44
45
|
braintrust/util.py,sha256=Ec6sRkQw5BckGrFjdA4YTyu_2BaKmHh4tWDwAi_ysOw,7227
|
|
45
|
-
braintrust/version.py,sha256=
|
|
46
|
+
braintrust/version.py,sha256=3wAzsDK5T1yqm2oCx82UysM0PDJBVh8gI90sxUVKfQg,118
|
|
46
47
|
braintrust/xact_ids.py,sha256=bdyp88HjlyIkglgLSqYlCYscdSH6EWVyE14sR90Xl1s,658
|
|
47
48
|
braintrust/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
49
|
braintrust/cli/__main__.py,sha256=wCBKHGVmn3IT_yMXk5qfDwyI2SV2gf1tLr0NTxm9T8k,1519
|
|
@@ -109,8 +110,8 @@ braintrust/wrappers/claude_agent_sdk/__init__.py,sha256=CSXJWy-z2fHF7h4VJjLSnXJv
|
|
|
109
110
|
braintrust/wrappers/claude_agent_sdk/_wrapper.py,sha256=uzElIOwwPmF_Y5fbWcKWEPC8HnSzW7byzpiuVKK0TXE,15613
|
|
110
111
|
braintrust/wrappers/claude_agent_sdk/test_wrapper.py,sha256=0NmohdECudFvWtc-5PbANtTXzexkkwIJhGbujydDrT8,6826
|
|
111
112
|
braintrust/wrappers/google_genai/__init__.py,sha256=PGFMuR3c4Gc3SUt24eP7z5AzdS2Dc1uF1d3QPCnLnuo,16018
|
|
112
|
-
braintrust-0.3.
|
|
113
|
-
braintrust-0.3.
|
|
114
|
-
braintrust-0.3.
|
|
115
|
-
braintrust-0.3.
|
|
116
|
-
braintrust-0.3.
|
|
113
|
+
braintrust-0.3.14.dist-info/METADATA,sha256=9ibXkb190ZtT4_UgxlPjgU4y6eKJI_Y6h0eyrzm9oEs,3702
|
|
114
|
+
braintrust-0.3.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
115
|
+
braintrust-0.3.14.dist-info/entry_points.txt,sha256=Zpc0_09g5xm8as5jHqqFq7fhwO0xHSNct_TrEMONS7Q,60
|
|
116
|
+
braintrust-0.3.14.dist-info/top_level.txt,sha256=hw1-y-UFMf60RzAr8x_eM7SThbIuWfQsQIbVvqSF83A,11
|
|
117
|
+
braintrust-0.3.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|