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 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
@@ -34,6 +34,7 @@ class Score(SerializableDataClass):
34
34
 
35
35
  def as_dict(self):
36
36
  return {
37
+ "name": self.name,
37
38
  "score": self.score,
38
39
  "metadata": self.metadata,
39
40
  }
@@ -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
@@ -1,4 +1,4 @@
1
- VERSION = "0.3.13"
1
+ VERSION = "0.3.14"
2
2
 
3
3
  # this will be templated during the build
4
- GIT_COMMIT = "cef88a007fa60f4cd873f1d891a54ce5e173f3aa"
4
+ GIT_COMMIT = "dbbc1894ef31143816e5913676301261bc44aa4c"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braintrust
3
- Version: 0.3.13
3
+ Version: 0.3.14
4
4
  Summary: SDK for integrating Braintrust
5
5
  Home-page: https://www.braintrust.dev
6
6
  Author: Braintrust
@@ -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=bEk38AlNtT-umtdCJ9lnSXlbKXsvjBOyTTsmzUKiVtM,5586
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=NTbxgXa_qsu7bwl4bUoLuj9HNDuaGQiDlu0-addkAQc,210560
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=aHs5bMDI7e8Un4VdfAejHM8T38PDqdiia4YDU303YkY,3632
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=YyNQY-UJ0O_hVg8XR4VJGGwb-qChpEoYLN6jfWC4rEQ,118
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.13.dist-info/METADATA,sha256=cZM8kCyxf7v0SHVRVPHBElZcVIis1GcwcXTOea54WPo,3702
113
- braintrust-0.3.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
114
- braintrust-0.3.13.dist-info/entry_points.txt,sha256=Zpc0_09g5xm8as5jHqqFq7fhwO0xHSNct_TrEMONS7Q,60
115
- braintrust-0.3.13.dist-info/top_level.txt,sha256=hw1-y-UFMf60RzAr8x_eM7SThbIuWfQsQIbVvqSF83A,11
116
- braintrust-0.3.13.dist-info/RECORD,,
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,,