braintrust 0.5.0__py3-none-any.whl → 0.5.3__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/__init__.py +14 -0
- braintrust/_generated_types.py +56 -3
- braintrust/auto.py +179 -0
- braintrust/conftest.py +23 -4
- braintrust/db_fields.py +10 -0
- braintrust/framework.py +18 -5
- braintrust/generated_types.py +3 -1
- braintrust/logger.py +369 -134
- braintrust/merge_row_batch.py +49 -109
- braintrust/oai.py +51 -0
- braintrust/test_bt_json.py +0 -5
- braintrust/test_context.py +1264 -0
- braintrust/test_framework.py +37 -0
- braintrust/test_http.py +444 -0
- braintrust/test_logger.py +179 -5
- braintrust/test_merge_row_batch.py +160 -0
- braintrust/test_util.py +58 -1
- braintrust/util.py +20 -0
- braintrust/version.py +2 -2
- braintrust/wrappers/agno/__init__.py +2 -3
- braintrust/wrappers/anthropic.py +64 -0
- braintrust/wrappers/claude_agent_sdk/__init__.py +2 -3
- braintrust/wrappers/claude_agent_sdk/test_wrapper.py +9 -0
- braintrust/wrappers/dspy.py +52 -1
- braintrust/wrappers/google_genai/__init__.py +9 -6
- braintrust/wrappers/litellm.py +6 -43
- braintrust/wrappers/pydantic_ai.py +2 -3
- braintrust/wrappers/test_agno.py +9 -0
- braintrust/wrappers/test_anthropic.py +156 -0
- braintrust/wrappers/test_dspy.py +117 -0
- braintrust/wrappers/test_google_genai.py +9 -0
- braintrust/wrappers/test_litellm.py +57 -55
- braintrust/wrappers/test_openai.py +253 -1
- braintrust/wrappers/test_pydantic_ai_integration.py +9 -0
- braintrust/wrappers/test_utils.py +79 -0
- braintrust/wrappers/threads.py +114 -0
- {braintrust-0.5.0.dist-info → braintrust-0.5.3.dist-info}/METADATA +1 -1
- {braintrust-0.5.0.dist-info → braintrust-0.5.3.dist-info}/RECORD +41 -37
- {braintrust-0.5.0.dist-info → braintrust-0.5.3.dist-info}/WHEEL +1 -1
- braintrust/graph_util.py +0 -147
- {braintrust-0.5.0.dist-info → braintrust-0.5.3.dist-info}/entry_points.txt +0 -0
- {braintrust-0.5.0.dist-info → braintrust-0.5.3.dist-info}/top_level.txt +0 -0
braintrust/graph_util.py
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
# Generic graph algorithms.
|
|
2
|
-
|
|
3
|
-
import dataclasses
|
|
4
|
-
from typing import Protocol
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
# An UndirectedGraph consists of a set of vertex labels and a set of edges
|
|
8
|
-
# between vertices.
|
|
9
|
-
@dataclasses.dataclass
|
|
10
|
-
class UndirectedGraph:
|
|
11
|
-
vertices: set[int]
|
|
12
|
-
edges: set[tuple[int, int]]
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# An AdjacencyListGraph is a mapping from vertex label to the list of vertices
|
|
16
|
-
# where there is a directed edge from the key to the value.
|
|
17
|
-
AdjacencyListGraph = dict[int, set[int]]
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class FirstVisitF(Protocol):
|
|
21
|
-
def __call__(self, vertex: int, *, parent_vertex: int | None, **kwargs) -> None:
|
|
22
|
-
"""Extras:
|
|
23
|
-
- parent_vertex: the vertex which spawned the current vertex as its
|
|
24
|
-
child during the depth-first search. `parent_vertex` is guaranteed
|
|
25
|
-
to have been visited before the current one.
|
|
26
|
-
"""
|
|
27
|
-
...
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class LastVisitF(Protocol):
|
|
31
|
-
def __call__(self, vertex: int) -> None: ...
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def depth_first_search(
|
|
35
|
-
graph: AdjacencyListGraph,
|
|
36
|
-
first_visit_f: FirstVisitF | None = None,
|
|
37
|
-
last_visit_f: LastVisitF | None = None,
|
|
38
|
-
visitation_order: list[int] | None = None,
|
|
39
|
-
) -> None:
|
|
40
|
-
"""A general depth-first search algorithm over a directed graph. As it
|
|
41
|
-
traverses the graph, it invokes user-provided hooks when a vertex is *first*
|
|
42
|
-
visited (before visiting its children) and when it is *last* visited (after
|
|
43
|
-
visiting all its children).
|
|
44
|
-
|
|
45
|
-
The first_visit_f and last_visit_f functions may be passed additional
|
|
46
|
-
information beyond the vertex being visited as kwargs. See their type
|
|
47
|
-
signatures for more details. For future proofing, you will likely want to
|
|
48
|
-
capture **kwargs as a catchall in your functions.
|
|
49
|
-
|
|
50
|
-
An optional `visitation_order` can be specified, which controls the order in
|
|
51
|
-
which vertices will be first visited (outside of visiting them through a
|
|
52
|
-
different vertex). It can also be used to limit the set of starting vertices
|
|
53
|
-
considered. Otherwise, the DFS will visit all vertices in an unspecfied
|
|
54
|
-
order.
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
# Check the validity of the graph.
|
|
58
|
-
for vs in graph.values():
|
|
59
|
-
for v in vs:
|
|
60
|
-
assert v in graph
|
|
61
|
-
|
|
62
|
-
first_visited_vertices = set()
|
|
63
|
-
visitation_order = visitation_order if visitation_order is not None else graph.keys()
|
|
64
|
-
events = list(reversed([("first", x, dict(parent_vertex=None)) for x in visitation_order]))
|
|
65
|
-
while events:
|
|
66
|
-
event_type, vertex, extras = events.pop()
|
|
67
|
-
|
|
68
|
-
if event_type == "last":
|
|
69
|
-
if last_visit_f:
|
|
70
|
-
last_visit_f(vertex)
|
|
71
|
-
continue
|
|
72
|
-
|
|
73
|
-
# First visit of a node. If we've already visited it, skip.
|
|
74
|
-
if vertex in first_visited_vertices:
|
|
75
|
-
continue
|
|
76
|
-
first_visited_vertices.add(vertex)
|
|
77
|
-
if first_visit_f:
|
|
78
|
-
first_visit_f(vertex, parent_vertex=extras["parent_vertex"])
|
|
79
|
-
|
|
80
|
-
# Add 'first' visitation events for all the children of the vertex to
|
|
81
|
-
# the stack. But before this, add a 'last' visitation event for this
|
|
82
|
-
# vertex, so that once we've completed all the children, we get the last
|
|
83
|
-
# visitation event for this one.
|
|
84
|
-
events.append(("last", vertex, dict()))
|
|
85
|
-
for child in graph[vertex]:
|
|
86
|
-
events.append(("first", child, dict(parent_vertex=vertex)))
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def undirected_connected_components(graph: UndirectedGraph) -> list[list[int]]:
|
|
90
|
-
"""Group together all the connected components of an undirected graph.
|
|
91
|
-
Return each group as a list of vertices.
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
# Perhaps the most performant way to implement this is via union find. But
|
|
95
|
-
# in lieu of that, we can use a depth-first search over a direct-ified
|
|
96
|
-
# version of the graph. Upon the first visit of each vertex, we assign it a
|
|
97
|
-
# label equal to the label of the parent vertex. If there is no parent
|
|
98
|
-
# vertex, we assign a new label. At the end, we can group together all the
|
|
99
|
-
# vertices with the same label.
|
|
100
|
-
|
|
101
|
-
directed_graph = {v: set() for v in graph.vertices}
|
|
102
|
-
for i, j in graph.edges:
|
|
103
|
-
directed_graph[i].add(j)
|
|
104
|
-
directed_graph[j].add(i)
|
|
105
|
-
|
|
106
|
-
label_counter = 0
|
|
107
|
-
vertex_labels = {}
|
|
108
|
-
|
|
109
|
-
def first_visit_f(vertex, parent_vertex, **kwargs):
|
|
110
|
-
if parent_vertex is not None:
|
|
111
|
-
label = vertex_labels[parent_vertex]
|
|
112
|
-
else:
|
|
113
|
-
nonlocal label_counter
|
|
114
|
-
# pylint: disable=used-before-assignment
|
|
115
|
-
label = label_counter
|
|
116
|
-
label_counter += 1
|
|
117
|
-
vertex_labels[vertex] = label
|
|
118
|
-
|
|
119
|
-
depth_first_search(directed_graph, first_visit_f=first_visit_f)
|
|
120
|
-
output = [[] for _ in range(label_counter)]
|
|
121
|
-
for vertex, label in vertex_labels.items():
|
|
122
|
-
output[label].append(vertex)
|
|
123
|
-
|
|
124
|
-
return output
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
def topological_sort(graph: AdjacencyListGraph, visitation_order: list[int] | None = None) -> list[int]:
|
|
128
|
-
"""The topological_sort function accepts a graph as input, with edges from
|
|
129
|
-
parents to children. It returns an ordering where parents are guaranteed to
|
|
130
|
-
come before their children.
|
|
131
|
-
|
|
132
|
-
The `visitation_order` is forwarded directly to `depth_first_search`.
|
|
133
|
-
|
|
134
|
-
Ordering with respect to cycles is unspecified. It is the caller's
|
|
135
|
-
responsibility to check for cycles if it matters.
|
|
136
|
-
"""
|
|
137
|
-
|
|
138
|
-
# We use DFS, where upon the 'last' visitation of a node, we append it to
|
|
139
|
-
# the final ordering. Then we reverse the list at the end.
|
|
140
|
-
reverse_ordering = []
|
|
141
|
-
|
|
142
|
-
def last_visit_f(vertex, **kwargs):
|
|
143
|
-
reverse_ordering.append(vertex)
|
|
144
|
-
|
|
145
|
-
depth_first_search(graph, last_visit_f=last_visit_f, visitation_order=visitation_order)
|
|
146
|
-
reverse_ordering.reverse()
|
|
147
|
-
return reverse_ordering
|
|
File without changes
|
|
File without changes
|