vellum-ai 0.12.13__py3-none-any.whl → 0.12.15__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- vellum/__init__.py +9 -0
- vellum/client/__init__.py +2 -6
- vellum/client/core/client_wrapper.py +1 -1
- vellum/client/environment.py +3 -3
- vellum/client/resources/ad_hoc/client.py +2 -6
- vellum/client/resources/container_images/client.py +0 -8
- vellum/client/resources/metric_definitions/client.py +2 -6
- vellum/client/resources/workflows/client.py +8 -8
- vellum/client/types/__init__.py +6 -0
- vellum/client/types/audio_prompt_block.py +29 -0
- vellum/client/types/function_call_prompt_block.py +30 -0
- vellum/client/types/image_prompt_block.py +29 -0
- vellum/client/types/prompt_block.py +12 -1
- vellum/client/types/workflow_push_response.py +1 -0
- vellum/plugins/pydantic.py +12 -2
- vellum/types/audio_prompt_block.py +3 -0
- vellum/types/function_call_prompt_block.py +3 -0
- vellum/types/image_prompt_block.py +3 -0
- vellum/workflows/descriptors/tests/test_utils.py +3 -0
- vellum/workflows/nodes/bases/base.py +4 -1
- vellum/workflows/nodes/bases/base_adornment_node.py +75 -0
- vellum/workflows/nodes/bases/tests/test_base_node.py +13 -0
- vellum/workflows/nodes/core/inline_subworkflow_node/node.py +2 -0
- vellum/workflows/nodes/core/map_node/node.py +49 -45
- vellum/workflows/nodes/core/retry_node/node.py +10 -45
- vellum/workflows/nodes/core/try_node/node.py +12 -84
- vellum/workflows/nodes/utils.py +44 -1
- vellum/workflows/references/constant.py +21 -0
- vellum/workflows/runner/runner.py +4 -3
- vellum/workflows/types/cycle_map.py +34 -0
- vellum/workflows/workflows/base.py +4 -11
- {vellum_ai-0.12.13.dist-info → vellum_ai-0.12.15.dist-info}/METADATA +2 -2
- {vellum_ai-0.12.13.dist-info → vellum_ai-0.12.15.dist-info}/RECORD +52 -39
- vellum_cli/config.py +4 -0
- vellum_cli/pull.py +20 -5
- vellum_cli/push.py +7 -0
- vellum_cli/tests/test_pull.py +19 -1
- vellum_ee/workflows/display/nodes/vellum/__init__.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/base_node.py +18 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +10 -41
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +4 -14
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py +174 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +2 -10
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +2 -10
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +5 -19
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +2 -8
- vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +14 -25
- vellum_ee/workflows/server/__init__.py +0 -0
- vellum_ee/workflows/server/virtual_file_loader.py +42 -0
- {vellum_ai-0.12.13.dist-info → vellum_ai-0.12.15.dist-info}/LICENSE +0 -0
- {vellum_ai-0.12.13.dist-info → vellum_ai-0.12.15.dist-info}/WHEEL +0 -0
- {vellum_ai-0.12.13.dist-info → vellum_ai-0.12.15.dist-info}/entry_points.txt +0 -0
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
from deepdiff import DeepDiff
|
2
|
+
|
3
|
+
from vellum_ee.workflows.display.workflows import VellumWorkflowDisplay
|
4
|
+
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
5
|
+
|
6
|
+
from tests.workflows.basic_generic_node.workflow import BasicGenericNodeWorkflow
|
7
|
+
|
8
|
+
|
9
|
+
def test_serialize_workflow(vellum_client):
|
10
|
+
# GIVEN a Workflow that uses a generic node
|
11
|
+
# WHEN we serialize it
|
12
|
+
workflow_display = get_workflow_display(
|
13
|
+
base_display_class=VellumWorkflowDisplay, workflow_class=BasicGenericNodeWorkflow
|
14
|
+
)
|
15
|
+
|
16
|
+
serialized_workflow: dict = workflow_display.serialize()
|
17
|
+
|
18
|
+
# THEN we should get a serialized representation of the Workflow
|
19
|
+
assert serialized_workflow.keys() == {
|
20
|
+
"workflow_raw_data",
|
21
|
+
"input_variables",
|
22
|
+
"output_variables",
|
23
|
+
}
|
24
|
+
|
25
|
+
# AND its input variables should be what we expect
|
26
|
+
input_variables = serialized_workflow["input_variables"]
|
27
|
+
assert len(input_variables) == 1
|
28
|
+
assert not DeepDiff(
|
29
|
+
[
|
30
|
+
{
|
31
|
+
"id": "a07c2273-34a7-42b5-bcad-143b6127cc8a",
|
32
|
+
"key": "input",
|
33
|
+
"type": "STRING",
|
34
|
+
"default": None,
|
35
|
+
"required": True,
|
36
|
+
"extensions": {"color": None},
|
37
|
+
},
|
38
|
+
],
|
39
|
+
input_variables,
|
40
|
+
ignore_order=True,
|
41
|
+
)
|
42
|
+
|
43
|
+
# AND its output variables should be what we expect
|
44
|
+
output_variables = serialized_workflow["output_variables"]
|
45
|
+
assert len(output_variables) == 1
|
46
|
+
assert not DeepDiff(
|
47
|
+
[
|
48
|
+
{"id": "2b6389d0-266a-4be4-843e-4e543dd3d727", "key": "output", "type": "STRING"},
|
49
|
+
],
|
50
|
+
output_variables,
|
51
|
+
ignore_order=True,
|
52
|
+
)
|
53
|
+
|
54
|
+
# AND its raw data should be what we expect
|
55
|
+
workflow_raw_data = serialized_workflow["workflow_raw_data"]
|
56
|
+
assert workflow_raw_data.keys() == {"edges", "nodes", "display_data", "definition"}
|
57
|
+
assert len(workflow_raw_data["edges"]) == 2
|
58
|
+
assert len(workflow_raw_data["nodes"]) == 3
|
59
|
+
|
60
|
+
# AND each node should be serialized correctly
|
61
|
+
entrypoint_node = workflow_raw_data["nodes"][0]
|
62
|
+
assert entrypoint_node == {
|
63
|
+
"id": "f1e4678f-c470-400b-a40e-c8922cc99a86",
|
64
|
+
"type": "ENTRYPOINT",
|
65
|
+
"inputs": [],
|
66
|
+
"data": {"label": "Entrypoint Node", "source_handle_id": "40201804-8beb-43ad-8873-a027759512f1"},
|
67
|
+
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
68
|
+
"definition": {
|
69
|
+
"name": "BaseNode",
|
70
|
+
"module": [
|
71
|
+
"vellum",
|
72
|
+
"workflows",
|
73
|
+
"nodes",
|
74
|
+
"bases",
|
75
|
+
"base",
|
76
|
+
],
|
77
|
+
"bases": [],
|
78
|
+
},
|
79
|
+
}
|
80
|
+
|
81
|
+
api_node = workflow_raw_data["nodes"][1]
|
82
|
+
assert not DeepDiff(
|
83
|
+
{
|
84
|
+
"id": "c2ed23f7-f6cb-4a56-a91c-2e5f9d8fda7f",
|
85
|
+
"type": "GENERIC",
|
86
|
+
},
|
87
|
+
api_node,
|
88
|
+
)
|
89
|
+
|
90
|
+
final_output_node = workflow_raw_data["nodes"][2]
|
91
|
+
assert not DeepDiff(
|
92
|
+
{
|
93
|
+
"id": "50e3b446-afcd-4a5d-8c6f-5f05eaf2200e",
|
94
|
+
"type": "TERMINAL",
|
95
|
+
"data": {
|
96
|
+
"label": "Final Output",
|
97
|
+
"name": "output",
|
98
|
+
"target_handle_id": "8bd9f4f3-9f66-4d95-8e84-529b0002c531",
|
99
|
+
"output_id": "2b6389d0-266a-4be4-843e-4e543dd3d727",
|
100
|
+
"output_type": "STRING",
|
101
|
+
"node_input_id": "7a9f2d3a-0b23-4bd4-b567-e9493135b727",
|
102
|
+
},
|
103
|
+
"inputs": [
|
104
|
+
{
|
105
|
+
"id": "7a9f2d3a-0b23-4bd4-b567-e9493135b727",
|
106
|
+
"key": "node_input",
|
107
|
+
"value": {
|
108
|
+
"rules": [
|
109
|
+
{
|
110
|
+
"type": "NODE_OUTPUT",
|
111
|
+
"data": {
|
112
|
+
"node_id": "c2ed23f7-f6cb-4a56-a91c-2e5f9d8fda7f",
|
113
|
+
"output_id": "0a9c7a80-fc89-4a71-aac0-66489e4ddb85",
|
114
|
+
},
|
115
|
+
}
|
116
|
+
],
|
117
|
+
"combinator": "OR",
|
118
|
+
},
|
119
|
+
}
|
120
|
+
],
|
121
|
+
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
122
|
+
"definition": {
|
123
|
+
"name": "FinalOutputNode",
|
124
|
+
"module": ["vellum", "workflows", "nodes", "displayable", "final_output_node", "node"],
|
125
|
+
"bases": [
|
126
|
+
{"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"], "bases": []}
|
127
|
+
],
|
128
|
+
},
|
129
|
+
},
|
130
|
+
final_output_node,
|
131
|
+
ignore_order=True,
|
132
|
+
)
|
133
|
+
|
134
|
+
# AND each edge should be serialized correctly
|
135
|
+
serialized_edges = workflow_raw_data["edges"]
|
136
|
+
assert not DeepDiff(
|
137
|
+
[
|
138
|
+
{
|
139
|
+
"id": "445dd2de-82b2-482b-89f6-5f49d8eb21a9",
|
140
|
+
"source_node_id": "f1e4678f-c470-400b-a40e-c8922cc99a86",
|
141
|
+
"source_handle_id": "40201804-8beb-43ad-8873-a027759512f1",
|
142
|
+
"target_node_id": "c2ed23f7-f6cb-4a56-a91c-2e5f9d8fda7f",
|
143
|
+
"target_handle_id": "b7bfb298-959a-4d2b-8b85-bbd0d2522703",
|
144
|
+
"type": "DEFAULT",
|
145
|
+
},
|
146
|
+
{
|
147
|
+
"id": "b741c861-cf67-4649-b9ef-b43a4add72b1",
|
148
|
+
"source_node_id": "c2ed23f7-f6cb-4a56-a91c-2e5f9d8fda7f",
|
149
|
+
"source_handle_id": "89dccfa5-cc1a-4612-bd87-86cb444f6dd4",
|
150
|
+
"target_node_id": "50e3b446-afcd-4a5d-8c6f-5f05eaf2200e",
|
151
|
+
"target_handle_id": "8bd9f4f3-9f66-4d95-8e84-529b0002c531",
|
152
|
+
"type": "DEFAULT",
|
153
|
+
},
|
154
|
+
],
|
155
|
+
serialized_edges,
|
156
|
+
ignore_order=True,
|
157
|
+
)
|
158
|
+
|
159
|
+
# AND the display data should be what we expect
|
160
|
+
display_data = workflow_raw_data["display_data"]
|
161
|
+
assert display_data == {
|
162
|
+
"viewport": {
|
163
|
+
"x": 0.0,
|
164
|
+
"y": 0.0,
|
165
|
+
"zoom": 1.0,
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
# AND the definition should be what we expect
|
170
|
+
definition = workflow_raw_data["definition"]
|
171
|
+
assert definition == {
|
172
|
+
"name": "BasicGenericNodeWorkflow",
|
173
|
+
"module": ["tests", "workflows", "basic_generic_node", "workflow"],
|
174
|
+
}
|
@@ -1,8 +1,5 @@
|
|
1
|
-
from unittest import mock
|
2
|
-
|
3
1
|
from deepdiff import DeepDiff
|
4
2
|
|
5
|
-
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
6
3
|
from vellum_ee.workflows.display.workflows import VellumWorkflowDisplay
|
7
4
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
8
5
|
|
@@ -15,12 +12,7 @@ def test_serialize_workflow():
|
|
15
12
|
workflow_display = get_workflow_display(
|
16
13
|
base_display_class=VellumWorkflowDisplay, workflow_class=BasicInlineSubworkflowWorkflow
|
17
14
|
)
|
18
|
-
|
19
|
-
# TODO: Support serialization of BaseNode
|
20
|
-
# https://app.shortcut.com/vellum/story/4871/support-serialization-of-base-node
|
21
|
-
with mock.patch.object(BaseNodeVellumDisplay, "serialize") as mocked_serialize:
|
22
|
-
mocked_serialize.return_value = {"type": "MOCKED"}
|
23
|
-
serialized_workflow: dict = workflow_display.serialize()
|
15
|
+
serialized_workflow: dict = workflow_display.serialize()
|
24
16
|
|
25
17
|
# THEN we should get a serialized representation of the Workflow
|
26
18
|
assert serialized_workflow.keys() == {
|
@@ -156,7 +148,7 @@ def test_serialize_workflow():
|
|
156
148
|
"bases": [],
|
157
149
|
},
|
158
150
|
},
|
159
|
-
{"type": "
|
151
|
+
{"id": "1381c078-efa2-4255-89a1-7b4cb742c7fc", "type": "GENERIC"},
|
160
152
|
{
|
161
153
|
"id": "a773c3a5-78cb-4250-8d29-7282e8a579d3",
|
162
154
|
"type": "TERMINAL",
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
from unittest import mock
|
2
|
-
|
3
1
|
from deepdiff import DeepDiff
|
4
2
|
|
5
|
-
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
6
3
|
from vellum_ee.workflows.display.workflows import VellumWorkflowDisplay
|
7
4
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
8
5
|
|
@@ -13,12 +10,7 @@ def test_serialize_workflow():
|
|
13
10
|
# GIVEN a Workflow that uses a MapNode
|
14
11
|
# WHEN we serialize it
|
15
12
|
workflow_display = get_workflow_display(base_display_class=VellumWorkflowDisplay, workflow_class=SimpleMapExample)
|
16
|
-
|
17
|
-
# TODO: Support serialization of BaseNode
|
18
|
-
# https://app.shortcut.com/vellum/story/4871/support-serialization-of-base-node
|
19
|
-
with mock.patch.object(BaseNodeVellumDisplay, "serialize") as mocked_serialize:
|
20
|
-
mocked_serialize.return_value = {"type": "MOCKED"}
|
21
|
-
serialized_workflow: dict = workflow_display.serialize()
|
13
|
+
serialized_workflow: dict = workflow_display.serialize()
|
22
14
|
|
23
15
|
# THEN we should get a serialized representation of the Workflow
|
24
16
|
assert serialized_workflow.keys() == {
|
@@ -141,7 +133,7 @@ def test_serialize_workflow():
|
|
141
133
|
"bases": [],
|
142
134
|
},
|
143
135
|
},
|
144
|
-
{"type": "
|
136
|
+
{"id": "baf6d316-dc75-41e8-96c0-015aede96309", "type": "GENERIC"},
|
145
137
|
{
|
146
138
|
"id": "6f4883b2-70b1-4e1c-ae15-7d0f5aec810b",
|
147
139
|
"type": "TERMINAL",
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
from unittest import mock
|
2
|
-
|
3
1
|
from deepdiff import DeepDiff
|
4
2
|
|
5
|
-
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
6
3
|
from vellum_ee.workflows.display.workflows import VellumWorkflowDisplay
|
7
4
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
8
5
|
|
@@ -15,12 +12,7 @@ def test_serialize_workflow__await_all():
|
|
15
12
|
workflow_display = get_workflow_display(
|
16
13
|
base_display_class=VellumWorkflowDisplay, workflow_class=AwaitAllPassingWorkflow
|
17
14
|
)
|
18
|
-
|
19
|
-
# TODO: Support serialization of BaseNode
|
20
|
-
# https://app.shortcut.com/vellum/story/4871/support-serialization-of-base-node
|
21
|
-
with mock.patch.object(BaseNodeVellumDisplay, "serialize") as mocked_serialize:
|
22
|
-
mocked_serialize.return_value = {"type": "MOCKED"}
|
23
|
-
serialized_workflow: dict = workflow_display.serialize()
|
15
|
+
serialized_workflow: dict = workflow_display.serialize()
|
24
16
|
|
25
17
|
# THEN we should get a serialized representation of the Workflow
|
26
18
|
assert serialized_workflow.keys() == {
|
@@ -76,18 +68,12 @@ def test_serialize_workflow__await_all():
|
|
76
68
|
},
|
77
69
|
}
|
78
70
|
|
79
|
-
passthrough_nodes = [node for node in workflow_raw_data["nodes"] if node["type"] == "
|
71
|
+
passthrough_nodes = [node for node in workflow_raw_data["nodes"] if node["type"] == "GENERIC"]
|
80
72
|
assert not DeepDiff(
|
81
73
|
[
|
82
|
-
{
|
83
|
-
|
84
|
-
},
|
85
|
-
{
|
86
|
-
"type": "MOCKED",
|
87
|
-
},
|
88
|
-
{
|
89
|
-
"type": "MOCKED",
|
90
|
-
},
|
74
|
+
{"id": "127ef456-91bc-43c6-bd8b-1772db5e3cb5", "type": "GENERIC"},
|
75
|
+
{"id": "59243c65-053f-4ea6-9157-3f3edb1477bf", "type": "GENERIC"},
|
76
|
+
{"id": "634f0202-9ea9-4c62-b152-1a58c595cffb", "type": "GENERIC"},
|
91
77
|
],
|
92
78
|
passthrough_nodes,
|
93
79
|
ignore_order=True,
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
from unittest import mock
|
2
|
-
|
3
1
|
from deepdiff import DeepDiff
|
4
2
|
|
5
|
-
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
6
3
|
from vellum_ee.workflows.display.workflows import VellumWorkflowDisplay
|
7
4
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
8
5
|
|
@@ -13,10 +10,7 @@ def test_serialize_workflow():
|
|
13
10
|
# GIVEN a Workflow with a TryNode
|
14
11
|
# WHEN we serialize it
|
15
12
|
workflow_display = get_workflow_display(base_display_class=VellumWorkflowDisplay, workflow_class=SimpleTryExample)
|
16
|
-
|
17
|
-
with mock.patch.object(BaseNodeVellumDisplay, "serialize") as mocked_serialize:
|
18
|
-
mocked_serialize.return_value = {"type": "MOCKED"}
|
19
|
-
serialized_workflow: dict = workflow_display.serialize()
|
13
|
+
serialized_workflow: dict = workflow_display.serialize()
|
20
14
|
|
21
15
|
# THEN we should get a serialized representation of the Workflow
|
22
16
|
assert serialized_workflow.keys() == {
|
@@ -82,4 +76,4 @@ def test_serialize_workflow():
|
|
82
76
|
}
|
83
77
|
|
84
78
|
try_node = workflow_raw_data["nodes"][1]
|
85
|
-
assert try_node == {"type": "
|
79
|
+
assert try_node == {"id": "1381c078-efa2-4255-89a1-7b4cb742c7fc", "type": "GENERIC"}
|
vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
import pytest
|
2
|
-
from unittest import mock
|
3
2
|
|
4
3
|
from deepdiff import DeepDiff
|
5
4
|
|
6
|
-
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
7
5
|
from vellum_ee.workflows.display.workflows import VellumWorkflowDisplay
|
8
6
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
9
7
|
|
@@ -13,17 +11,12 @@ from tests.workflows.complex_final_output_node.missing_workflow_output import Mi
|
|
13
11
|
|
14
12
|
def test_serialize_workflow__missing_final_output_node():
|
15
13
|
# GIVEN a Workflow that is missing a Terminal Node
|
14
|
+
workflow_display = get_workflow_display(
|
15
|
+
base_display_class=VellumWorkflowDisplay, workflow_class=MissingFinalOutputNodeWorkflow
|
16
|
+
)
|
16
17
|
|
17
|
-
#
|
18
|
-
|
19
|
-
with mock.patch.object(BaseNodeVellumDisplay, "serialize") as mocked_serialize:
|
20
|
-
mocked_serialize.return_value = {"type": "MOCKED"}
|
21
|
-
workflow_display = get_workflow_display(
|
22
|
-
base_display_class=VellumWorkflowDisplay, workflow_class=MissingFinalOutputNodeWorkflow
|
23
|
-
)
|
24
|
-
|
25
|
-
# WHEN we serialize it
|
26
|
-
serialized_workflow: dict = workflow_display.serialize()
|
18
|
+
# WHEN we serialize it
|
19
|
+
serialized_workflow: dict = workflow_display.serialize()
|
27
20
|
|
28
21
|
# THEN we should get a serialized representation of the Workflow
|
29
22
|
assert serialized_workflow.keys() == {
|
@@ -97,9 +90,10 @@ def test_serialize_workflow__missing_final_output_node():
|
|
97
90
|
},
|
98
91
|
}
|
99
92
|
|
100
|
-
passthrough_node = next(node for node in workflow_raw_data["nodes"] if node["type"] == "
|
93
|
+
passthrough_node = next(node for node in workflow_raw_data["nodes"] if node["type"] == "GENERIC")
|
101
94
|
assert passthrough_node == {
|
102
|
-
"
|
95
|
+
"id": "32d88cab-e9fa-4a56-9bc2-fb6e1fd0897f",
|
96
|
+
"type": "GENERIC",
|
103
97
|
}
|
104
98
|
|
105
99
|
final_output_nodes = [node for node in workflow_raw_data["nodes"] if node["type"] == "TERMINAL"]
|
@@ -218,17 +212,12 @@ def test_serialize_workflow__missing_final_output_node():
|
|
218
212
|
|
219
213
|
def test_serialize_workflow__missing_workflow_output():
|
220
214
|
# GIVEN a Workflow that contains a terminal node that is unreferenced by the Workflow's Outputs
|
215
|
+
workflow_display = get_workflow_display(
|
216
|
+
base_display_class=VellumWorkflowDisplay, workflow_class=MissingWorkflowOutputWorkflow
|
217
|
+
)
|
221
218
|
|
222
|
-
#
|
223
|
-
|
224
|
-
|
225
|
-
mocked_serialize.return_value = {"type": "MOCKED"}
|
226
|
-
workflow_display = get_workflow_display(
|
227
|
-
base_display_class=VellumWorkflowDisplay, workflow_class=MissingWorkflowOutputWorkflow
|
228
|
-
)
|
229
|
-
|
230
|
-
# WHEN we serialize it, it should throw an error
|
231
|
-
with pytest.raises(ValueError) as exc_info:
|
232
|
-
workflow_display.serialize()
|
219
|
+
# WHEN we serialize it, it should throw an error
|
220
|
+
with pytest.raises(ValueError) as exc_info:
|
221
|
+
workflow_display.serialize()
|
233
222
|
|
234
223
|
assert exc_info.value.args[0] == "Unable to serialize terminal nodes that are not referenced by workflow outputs."
|
File without changes
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import importlib
|
2
|
+
|
3
|
+
|
4
|
+
class VirtualFileLoader(importlib.abc.Loader):
|
5
|
+
def __init__(self, code: str, is_package: bool):
|
6
|
+
self.code = code
|
7
|
+
self.is_package = is_package
|
8
|
+
|
9
|
+
def create_module(self, spec):
|
10
|
+
return None # use default module creation
|
11
|
+
|
12
|
+
def exec_module(self, module):
|
13
|
+
if not self.is_package:
|
14
|
+
exec(self.code, module.__dict__)
|
15
|
+
|
16
|
+
|
17
|
+
class VirtualFileFinder(importlib.abc.MetaPathFinder, importlib.abc.Loader):
|
18
|
+
def __init__(self, files: dict[str, str], namespace: str):
|
19
|
+
self.files = files
|
20
|
+
self.namespace = namespace
|
21
|
+
|
22
|
+
def find_spec(self, fullname, path, target=None):
|
23
|
+
# Do the namespacing on the fly to avoid having to copy the file dict
|
24
|
+
prefixed_name = fullname if fullname.startswith(self.namespace) else f"{self.namespace}.{fullname}"
|
25
|
+
|
26
|
+
key_name = "__init__" if fullname == self.namespace else fullname.replace(f"{self.namespace}.", "")
|
27
|
+
|
28
|
+
files_key = f"{key_name.replace('.', '/')}.py"
|
29
|
+
if not self.files.get(files_key):
|
30
|
+
files_key = f"{key_name.replace('.', '/')}/__init__.py"
|
31
|
+
|
32
|
+
file = self.files.get(files_key)
|
33
|
+
is_package = "__init__" in files_key
|
34
|
+
|
35
|
+
if file:
|
36
|
+
return importlib.machinery.ModuleSpec(
|
37
|
+
prefixed_name,
|
38
|
+
VirtualFileLoader(file, is_package),
|
39
|
+
origin=prefixed_name,
|
40
|
+
is_package=is_package,
|
41
|
+
)
|
42
|
+
return None
|
File without changes
|
File without changes
|
File without changes
|