vellum-ai 0.13.15__py3-none-any.whl → 0.13.18__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.
- vellum/client/core/client_wrapper.py +1 -1
- vellum/client/resources/workflows/client.py +0 -10
- vellum/workflows/nodes/core/templating_node/node.py +4 -47
- vellum/workflows/nodes/displayable/code_execution_node/node.py +29 -23
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +169 -5
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +98 -1
- vellum/workflows/nodes/utils.py +50 -1
- vellum/workflows/references/external_input.py +14 -0
- vellum/workflows/state/base.py +7 -0
- vellum/workflows/state/tests/test_state.py +42 -0
- {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.18.dist-info}/METADATA +1 -1
- {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.18.dist-info}/RECORD +25 -24
- vellum_cli/pull.py +57 -20
- vellum_cli/push.py +1 -5
- vellum_cli/tests/test_pull.py +115 -8
- vellum_cli/tests/test_push.py +0 -8
- vellum_ee/workflows/display/nodes/base_node_display.py +2 -2
- vellum_ee/workflows/display/nodes/get_node_display_class.py +16 -20
- vellum_ee/workflows/display/nodes/vellum/__init__.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/retry_node.py +10 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +23 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +2 -2
- {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.18.dist-info}/LICENSE +0 -0
- {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.18.dist-info}/WHEEL +0 -0
- {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.18.dist-info}/entry_points.txt +0 -0
@@ -64,6 +64,22 @@ def test_state_snapshot__nested_dictionary_edit():
|
|
64
64
|
assert snapshot_count[id(state)] == 1
|
65
65
|
|
66
66
|
|
67
|
+
def test_state_snapshot__external_input_edit():
|
68
|
+
# GIVEN an initial state instance
|
69
|
+
state = MockState(foo="bar")
|
70
|
+
assert snapshot_count[id(state)] == 0
|
71
|
+
|
72
|
+
# WHEN we add an external input to state
|
73
|
+
class MockExternalInputs(BaseNode.ExternalInputs):
|
74
|
+
message: str
|
75
|
+
|
76
|
+
# WHEN we edit external inputs dictionary
|
77
|
+
state.meta.external_inputs[MockExternalInputs.message] = "hello"
|
78
|
+
|
79
|
+
# THEN the snapshot is emitted
|
80
|
+
assert snapshot_count[id(state)] == 1
|
81
|
+
|
82
|
+
|
67
83
|
def test_state_deepcopy():
|
68
84
|
# GIVEN an initial state instance
|
69
85
|
state = MockState(foo="bar")
|
@@ -116,6 +132,32 @@ def test_state_json_serialization__with_node_output_updates():
|
|
116
132
|
assert json_state["meta"]["node_outputs"] == {"MockNode.Outputs.baz": "hello"}
|
117
133
|
|
118
134
|
|
135
|
+
def test_state_deepcopy__with_external_input_updates():
|
136
|
+
# GIVEN an initial state instance
|
137
|
+
state = MockState(foo="bar")
|
138
|
+
|
139
|
+
# AND we add an external input to state
|
140
|
+
class MockExternalInputs(BaseNode.ExternalInputs):
|
141
|
+
message: str
|
142
|
+
|
143
|
+
state.meta.external_inputs[MockExternalInputs.message] = "hello"
|
144
|
+
|
145
|
+
# AND we deepcopy the state
|
146
|
+
deepcopied_state = deepcopy(state)
|
147
|
+
|
148
|
+
# AND we update the original state
|
149
|
+
state.meta.external_inputs[MockExternalInputs.message] = "world"
|
150
|
+
|
151
|
+
# THEN the copied state is not updated
|
152
|
+
assert deepcopied_state.meta.external_inputs[MockExternalInputs.message] == "hello"
|
153
|
+
|
154
|
+
# AND the original state has had the correct number of snapshots
|
155
|
+
assert snapshot_count[id(state)] == 2
|
156
|
+
|
157
|
+
# AND the copied state has had the correct number of snapshots
|
158
|
+
assert snapshot_count[id(deepcopied_state)] == 0
|
159
|
+
|
160
|
+
|
119
161
|
def test_state_json_serialization__with_queue():
|
120
162
|
# GIVEN an initial state instance
|
121
163
|
state = MockState(foo="bar")
|
@@ -6,29 +6,29 @@ vellum_cli/config.py,sha256=LVRB-SEJcpQYfg2QGcjKHmRSAijdSFADbS90gDY4AI8,6829
|
|
6
6
|
vellum_cli/image_push.py,sha256=SJwhwWJsLjwGNezNVd_oCVpFMfPsAB3dfLWmriZZUtw,4419
|
7
7
|
vellum_cli/logger.py,sha256=PuRFa0WCh4sAGFS5aqWB0QIYpS6nBWwPJrIXpWxugV4,1022
|
8
8
|
vellum_cli/ping.py,sha256=lWyJw6sziXjyTopTYRdFF5hV-sYPVDdX0yVbG5fzcY4,585
|
9
|
-
vellum_cli/pull.py,sha256=
|
10
|
-
vellum_cli/push.py,sha256=
|
9
|
+
vellum_cli/pull.py,sha256=7yvg4oBOgsbBEsgXtCpYlNR4AOR8hPICamY-4HI-3kM,9031
|
10
|
+
vellum_cli/push.py,sha256=qQCI_cHvVjeDGA8FLYmSN7UE_wIJQnUXX_5cGsm9OTs,9076
|
11
11
|
vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
12
|
vellum_cli/tests/conftest.py,sha256=AFYZryKA2qnUuCPBxBKmHLFoPiE0WhBFFej9tNwSHdc,1526
|
13
13
|
vellum_cli/tests/test_config.py,sha256=uvKGDc8BoVyT9_H0Z-g8469zVxomn6Oi3Zj-vK7O_wU,2631
|
14
14
|
vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
|
15
15
|
vellum_cli/tests/test_ping.py,sha256=QtbhYKMYn1DFnDyBij2mkQO32j9KOpZ5Pf0yek7k_Ao,1284
|
16
|
-
vellum_cli/tests/test_pull.py,sha256=
|
17
|
-
vellum_cli/tests/test_push.py,sha256=
|
16
|
+
vellum_cli/tests/test_pull.py,sha256=CEnVpb9i-_I0wOSabjgJxleRuvvAHFfDB0_f4CvpwMI,23742
|
17
|
+
vellum_cli/tests/test_push.py,sha256=kcM8jp6vTRBwfk6cAC_tHa4Eliuy_zZ-X1DfIpSEIW0,18299
|
18
18
|
vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
20
|
vellum_ee/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
21
|
vellum_ee/workflows/display/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
22
|
vellum_ee/workflows/display/base.py,sha256=3ZFUYRNKL24fBqXhKpa_Dq2W1a-a86J20dmJYA3H2eY,1755
|
23
23
|
vellum_ee/workflows/display/nodes/__init__.py,sha256=5XOcZJXYUgaLS55QgRJzyQ_W1tpeprjnYAeYVezqoGw,160
|
24
|
-
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=
|
24
|
+
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=ErIK_1DYax0LlFX4AvV1oua8I7JlpXNncjGNadVe-bo,15801
|
25
25
|
vellum_ee/workflows/display/nodes/base_node_vellum_display.py,sha256=pLO0dORfRu--Ne9NgoyFT_CNjfpr5fGCsgbsMkUF5GM,2845
|
26
|
-
vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=
|
26
|
+
vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=0S6ksPp53WXWh1RQVH71nj2bkCWBj4ZaFYhTxW3N2F4,1230
|
27
27
|
vellum_ee/workflows/display/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
28
|
vellum_ee/workflows/display/nodes/tests/test_base_node_display.py,sha256=QqR3Ly0RNrXwOeLdW5nERDFt0gRPf76n1bPES6o5UN4,1093
|
29
29
|
vellum_ee/workflows/display/nodes/types.py,sha256=St1BB6no528OyELGiyRabWao0GGw6mLhstQAvEACbGk,247
|
30
30
|
vellum_ee/workflows/display/nodes/utils.py,sha256=sloya5TpXsnot1HURc9L51INwflRqUzHxRVnCS9Cd-4,973
|
31
|
-
vellum_ee/workflows/display/nodes/vellum/__init__.py,sha256=
|
31
|
+
vellum_ee/workflows/display/nodes/vellum/__init__.py,sha256=Moeuvm0u7c_6wtxUWOJqTJYbrnG4Rp_5mKRoYpfewvQ,1578
|
32
32
|
vellum_ee/workflows/display/nodes/vellum/api_node.py,sha256=hoV-cUtS6H9kmRQXHd2py95GRWI_dAnnaPwvlNBkDOQ,8571
|
33
33
|
vellum_ee/workflows/display/nodes/vellum/code_execution_node.py,sha256=z00Z3L0d4PsUQo4S8FRDTtOFLtjdi17TJbatNVF4nM8,4288
|
34
34
|
vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=ybLIa4uclqVIy3VAQvI1ivg2tnK5Ug_1R5a69DFqL7E,11104
|
@@ -41,6 +41,7 @@ vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=VlO3UwkspCOdDQ-h3v8k
|
|
41
41
|
vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=HkNMgdQELiON42jdO-xDLmqrEKdGx1RVqrz2DXNTLS8,3239
|
42
42
|
vellum_ee/workflows/display/nodes/vellum/note_node.py,sha256=TMb8txILu2uWjzoxaghjgjlzeBAgzn4vkP_8zSh2qoE,1151
|
43
43
|
vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=LFjLUrH6sJ4czPnExdRqFr0PB_yKBMLXLvK5GAzIAgc,3273
|
44
|
+
vellum_ee/workflows/display/nodes/vellum/retry_node.py,sha256=i0XGbKecLiHtf7mBf2rbqldPgLcs1TitIphzcHRIvkA,341
|
44
45
|
vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=TxcAGZDl_hvJ7Y1hUi9YVEVrj9Ie0hKkASdpfRL4_cs,9227
|
45
46
|
vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py,sha256=lfevlHpGEX14dEDym6qmnkw3nvzQPTB1_D2ch12B_Rk,2701
|
46
47
|
vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=JVIMPR3WpveOCWZubHKZkE04mavnTdb_9QY_r3XliRg,3424
|
@@ -55,13 +56,13 @@ vellum_ee/workflows/display/tests/test_vellum_workflow_display.py,sha256=h4bE187
|
|
55
56
|
vellum_ee/workflows/display/tests/workflow_serialization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
57
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
58
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py,sha256=EenmEdBtHUFQ0OS-kE7Vboax3JnDdj-K4Qixt5oR0Po,2253
|
58
|
-
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256=
|
59
|
+
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256=6wgLNd-Ae-33SPIYhOvQ9KJ8-5ach98v_Z3g7nrN_xs,8026
|
59
60
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py,sha256=yPXhdZxEDunNl5LL5Obb0jeO34djt7F-GiaTJhp_fmo,16742
|
60
61
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py,sha256=-12ZkZb3f5gyoNASV2yeQtMo5HmNsVEo8nXwL6IC-I8,6261
|
61
62
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py,sha256=6th6kCwzql6lddjkTQx4Jbvvs4ChqtJwctW-B4QuBhI,37352
|
62
63
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py,sha256=EbVgg_3_ipTt3MOop4RARX0fmNjwqZtkhIXzx9nGw7Y,4487
|
63
64
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py,sha256=bXZWxOKAVjZlbP3iLHPHGA4aPs0EguKlQqmYPNGv3cU,16391
|
64
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py,sha256=
|
65
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py,sha256=s2mBoL5Vvpoc-rcWcSGQjLp4yzVVwFmkTbS3--ErzCI,29486
|
65
66
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py,sha256=n3F_Eyru0DYOszBH4jplz7Mzt2FfBNxGlCkTFqvrX-M,48399
|
66
67
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py,sha256=8LhQgW0uzVOhzz0AwdM-EYugVO-0mGWglxWo_lON4D8,6079
|
67
68
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py,sha256=yWDykoHUjuiVYdevcJxWmYDDmbIszpHKYBu19vqR-I8,5746
|
@@ -112,7 +113,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
|
|
112
113
|
vellum/client/__init__.py,sha256=8nZt88C9SVwWanjLbIQMU3rzb32h5UZfFMBx3VPHB50,111887
|
113
114
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
114
115
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
115
|
-
vellum/client/core/client_wrapper.py,sha256=
|
116
|
+
vellum/client/core/client_wrapper.py,sha256=JapYtCCqy-ryd-fk1i1krQS6K630bgNpUw4zE0Lct8s,1869
|
116
117
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
117
118
|
vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
|
118
119
|
vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
|
@@ -168,7 +169,7 @@ vellum/client/resources/workflow_deployments/types/workflow_deployments_list_req
|
|
168
169
|
vellum/client/resources/workflow_sandboxes/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
169
170
|
vellum/client/resources/workflow_sandboxes/client.py,sha256=3wVQxkjrJ5bIS8fB5FpKXCP2dX38299ghWrJ8YmXxwQ,7435
|
170
171
|
vellum/client/resources/workflows/__init__.py,sha256=Z4xi8Nxd9U4t35FQSepTt1p-ns0X1xtdNs168kUcuBk,153
|
171
|
-
vellum/client/resources/workflows/client.py,sha256=
|
172
|
+
vellum/client/resources/workflows/client.py,sha256=hM7FDn05XHhQk599ti8CI4moIg0RVoEFil3Wp9v9UZk,11215
|
172
173
|
vellum/client/resources/workflows/types/__init__.py,sha256=-uFca4ypncAOvfsg6sjD-5C9zWdA5qNvU6m675GphVg,177
|
173
174
|
vellum/client/resources/workflows/types/workflows_pull_request_format.py,sha256=dOWE_jnDnniIJLoeseeCms23aklghyBkoPmBFzcqqZk,165
|
174
175
|
vellum/client/resources/workspace_secrets/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
@@ -1326,7 +1327,7 @@ vellum/workflows/nodes/core/retry_node/node.py,sha256=QEpxhKOyxDkRoAn2b0PToZWtAG
|
|
1326
1327
|
vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1327
1328
|
vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=RM_OHwxrHwyxvlQQBJPqVBxpedFuWQ9h2-Xa3kP75sc,4399
|
1328
1329
|
vellum/workflows/nodes/core/templating_node/__init__.py,sha256=GmyuYo81_A1_Bz6id69ozVFS6FKiuDsZTiA3I6MaL2U,70
|
1329
|
-
vellum/workflows/nodes/core/templating_node/node.py,sha256=
|
1330
|
+
vellum/workflows/nodes/core/templating_node/node.py,sha256=zCYhq88qLTvoC9LetVrD9sLXkwHZsaWekxMhru_nV70,3752
|
1330
1331
|
vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=5iZWQWdJKDHMXBY8bhpb-Dpy9FTfW1HXxGUTivykZAA,4621
|
1331
1332
|
vellum/workflows/nodes/core/try_node/__init__.py,sha256=JVD4DrldTIqFQQFrubs9KtWCCc0YCAc7Fzol5ZWIWeM,56
|
1332
1333
|
vellum/workflows/nodes/core/try_node/node.py,sha256=_lTmSYCiz7lktaxpNWUCglNi8_5Sfy8Rpiov5SeKVMw,3920
|
@@ -1350,12 +1351,12 @@ vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMD
|
|
1350
1351
|
vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
|
1351
1352
|
vellum/workflows/nodes/displayable/bases/utils.py,sha256=ckMUenSsNkiYmSw6FmjSMHYaCk8Y8_sUjL6lkFFEqts,5412
|
1352
1353
|
vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
|
1353
|
-
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=
|
1354
|
+
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=KZ5d3_mdpsrPF_ScmEqSfBhfup421RscO9hNiGa52T4,9068
|
1354
1355
|
vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1355
1356
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1356
1357
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
|
1357
|
-
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=
|
1358
|
-
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=
|
1358
|
+
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=ueVDw0GTSGzBZMFLs0NTir_0AE-pUrAYvpgg3Stex7Q,12350
|
1359
|
+
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=zRYM7B2t7355LzaAn6LkIn4tM5K7eQ0Kvje4NO6Kq30,3443
|
1359
1360
|
vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
|
1360
1361
|
vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
|
1361
1362
|
vellum/workflows/nodes/displayable/final_output_node/__init__.py,sha256=G7VXM4OWpubvSJtVkGmMNeqgb9GkM7qZT838eL18XU4,72
|
@@ -1386,7 +1387,7 @@ vellum/workflows/nodes/experimental/README.md,sha256=eF6DfIL8t-HbF9-mcofOMymKrra
|
|
1386
1387
|
vellum/workflows/nodes/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1387
1388
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha256=lsyD9laR9p7kx5-BXGH2gUTM242UhKy8SMV0SR6S2iE,90
|
1388
1389
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=1EGeiaT-Zoo6pttQFKKBcdf3dmhAbjKGaErYD5FFwlc,10185
|
1389
|
-
vellum/workflows/nodes/utils.py,sha256=
|
1390
|
+
vellum/workflows/nodes/utils.py,sha256=T7krLipDSI007JkkH2zsfyQ-tfOBH4hyFzQ0YJKYpuw,4025
|
1390
1391
|
vellum/workflows/outputs/__init__.py,sha256=AyZ4pRh_ACQIGvkf0byJO46EDnSix1ZCAXfvh-ms1QE,94
|
1391
1392
|
vellum/workflows/outputs/base.py,sha256=a7W6rNSDSawwGAXYjNTF2iHb9lnZu7WFSOagZIyy__k,7976
|
1392
1393
|
vellum/workflows/ports/__init__.py,sha256=bZuMt-R7z5bKwpu4uPW7LlJeePOQWmCcDSXe5frUY5g,101
|
@@ -1397,7 +1398,7 @@ vellum/workflows/references/__init__.py,sha256=glHFC1VfXmcbNvH5VzFbkT03d8_D7MMcv
|
|
1397
1398
|
vellum/workflows/references/constant.py,sha256=6yUT4q1sMj1hkI_tzzQ9AYcmeeDYFUNCqUq_W2DN0S8,540
|
1398
1399
|
vellum/workflows/references/environment_variable.py,sha256=-gfOcdYwVp9ztSUYz6h2WI2Cg95zqxq5hhFf3Yr7aQg,791
|
1399
1400
|
vellum/workflows/references/execution_count.py,sha256=JILHqt8ELdc9ct-WsVCA5X-rKiP1rmJODw-XTf4kpHI,722
|
1400
|
-
vellum/workflows/references/external_input.py,sha256=
|
1401
|
+
vellum/workflows/references/external_input.py,sha256=WyBC6uMDu77431YVSU_WvTt-nGLC_bW65tIsplUJXa4,2056
|
1401
1402
|
vellum/workflows/references/input.py,sha256=3INu-TLTi4dziWmva6LO3WvgDlPzsjayUx61cVvqLJA,325
|
1402
1403
|
vellum/workflows/references/lazy.py,sha256=SXwZUCTzUR-R2-uK0XHALtvp1x84l-QkNY-Ds6KynYA,1932
|
1403
1404
|
vellum/workflows/references/node.py,sha256=LP854wDVs-9I_aZ7-nkbwXqL2H7W2_3LED2e9FixNS8,1418
|
@@ -1411,12 +1412,12 @@ vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8v
|
|
1411
1412
|
vellum/workflows/runner/runner.py,sha256=LvP1UwLmwV1nCZYYrsiwtCzay73voMp1TDRVVBrlMj8,29196
|
1412
1413
|
vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2235
|
1413
1414
|
vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
|
1414
|
-
vellum/workflows/state/base.py,sha256=
|
1415
|
+
vellum/workflows/state/base.py,sha256=IIl76sJtn0GfbFWBqMnpGuvtZyVyQMEXv0QKDfLy8Wg,14763
|
1415
1416
|
vellum/workflows/state/context.py,sha256=_NeGQpYo8yNuh0Tfh3OvcB_bG_-GC8b3ZLLl83Pf8-I,1279
|
1416
1417
|
vellum/workflows/state/encoder.py,sha256=WdUidpOaBDx5lilJl8V8McFDHQYiCLCJR9dmktdzdZY,1836
|
1417
1418
|
vellum/workflows/state/store.py,sha256=VYGBQgN1bpd1as5eGiouV_7scg8QsRs4_1aqZAGIsRQ,793
|
1418
1419
|
vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1419
|
-
vellum/workflows/state/tests/test_state.py,sha256=
|
1420
|
+
vellum/workflows/state/tests/test_state.py,sha256=ucy7U8886J3CinIKQhOqv4dvkKWQk0fyK3JjTSiKZC4,5266
|
1420
1421
|
vellum/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1421
1422
|
vellum/workflows/tests/test_sandbox.py,sha256=JKwaluI-lODQo7Ek9sjDstjL_WTdSqUlVik6ZVTfVOA,1826
|
1422
1423
|
vellum/workflows/types/__init__.py,sha256=KxUTMBGzuRCfiMqzzsykOeVvrrkaZmTTo1a7SLu8gRM,68
|
@@ -1441,8 +1442,8 @@ vellum/workflows/vellum_client.py,sha256=ODrq_TSl-drX2aezXegf7pizpWDVJuTXH-j6528
|
|
1441
1442
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
1442
1443
|
vellum/workflows/workflows/base.py,sha256=k0kUWWko4fHyCqLSU_1cBK_pXZpl9MXekWiG-bdOAo0,18353
|
1443
1444
|
vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
|
1444
|
-
vellum_ai-0.13.
|
1445
|
-
vellum_ai-0.13.
|
1446
|
-
vellum_ai-0.13.
|
1447
|
-
vellum_ai-0.13.
|
1448
|
-
vellum_ai-0.13.
|
1445
|
+
vellum_ai-0.13.18.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1446
|
+
vellum_ai-0.13.18.dist-info/METADATA,sha256=aLUy-xu3bfn69UAWushKWy3YWWoMMruLabea-UEOO1o,5335
|
1447
|
+
vellum_ai-0.13.18.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1448
|
+
vellum_ai-0.13.18.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1449
|
+
vellum_ai-0.13.18.dist-info/RECORD,,
|
vellum_cli/pull.py
CHANGED
@@ -31,6 +31,16 @@ class WorkflowConfigResolutionResult(UniversalBaseModel):
|
|
31
31
|
pk: Optional[str] = None
|
32
32
|
|
33
33
|
|
34
|
+
class RunnerConfig(UniversalBaseModel):
|
35
|
+
container_image_name: Optional[str] = None
|
36
|
+
container_image_tag: Optional[str] = None
|
37
|
+
|
38
|
+
|
39
|
+
class PullContentsMetadata(UniversalBaseModel):
|
40
|
+
label: Optional[str] = None
|
41
|
+
runner_config: Optional[RunnerConfig] = None
|
42
|
+
|
43
|
+
|
34
44
|
def _resolve_workflow_config(
|
35
45
|
config: VellumCliConfig,
|
36
46
|
module: Optional[str] = None,
|
@@ -42,14 +52,33 @@ def _resolve_workflow_config(
|
|
42
52
|
|
43
53
|
if module:
|
44
54
|
workflow_config = next((w for w in config.workflows if w.module == module), None)
|
55
|
+
if not workflow_config and workflow_sandbox_id:
|
56
|
+
workflow_config = WorkflowConfig(
|
57
|
+
workflow_sandbox_id=workflow_sandbox_id,
|
58
|
+
module=module,
|
59
|
+
)
|
60
|
+
config.workflows.append(workflow_config)
|
61
|
+
return WorkflowConfigResolutionResult(
|
62
|
+
workflow_config=workflow_config,
|
63
|
+
pk=workflow_sandbox_id,
|
64
|
+
)
|
65
|
+
|
45
66
|
return WorkflowConfigResolutionResult(
|
46
67
|
workflow_config=workflow_config,
|
47
68
|
pk=workflow_config.workflow_sandbox_id if workflow_config else None,
|
48
69
|
)
|
49
70
|
elif workflow_sandbox_id:
|
71
|
+
workflow_config = next((w for w in config.workflows if w.workflow_sandbox_id == workflow_sandbox_id), None)
|
72
|
+
if workflow_config:
|
73
|
+
return WorkflowConfigResolutionResult(
|
74
|
+
workflow_config=workflow_config,
|
75
|
+
pk=workflow_sandbox_id,
|
76
|
+
)
|
77
|
+
|
78
|
+
# We use an empty module name to indicate that we want to backfill it once we have the Workflow Sandbox Label
|
50
79
|
workflow_config = WorkflowConfig(
|
51
80
|
workflow_sandbox_id=workflow_sandbox_id,
|
52
|
-
module=
|
81
|
+
module="",
|
53
82
|
)
|
54
83
|
config.workflows.append(workflow_config)
|
55
84
|
return WorkflowConfigResolutionResult(
|
@@ -98,7 +127,6 @@ def pull_command(
|
|
98
127
|
workflow_sandbox_id=workflow_sandbox_id,
|
99
128
|
workflow_deployment=workflow_deployment,
|
100
129
|
)
|
101
|
-
save_lock_file = not module
|
102
130
|
|
103
131
|
workflow_config = workflow_config_result.workflow_config
|
104
132
|
if not workflow_config:
|
@@ -108,7 +136,11 @@ def pull_command(
|
|
108
136
|
if not pk:
|
109
137
|
raise ValueError("No workflow sandbox ID found in project to pull from.")
|
110
138
|
|
111
|
-
|
139
|
+
if workflow_config.module:
|
140
|
+
logger.info(f"Pulling workflow into {workflow_config.module}...")
|
141
|
+
else:
|
142
|
+
logger.info(f"Pulling workflow from {pk}...")
|
143
|
+
|
112
144
|
client = create_vellum_client()
|
113
145
|
query_parameters = {}
|
114
146
|
|
@@ -129,11 +161,30 @@ def pull_command(
|
|
129
161
|
zip_bytes = b"".join(response)
|
130
162
|
zip_buffer = io.BytesIO(zip_bytes)
|
131
163
|
|
132
|
-
target_dir = os.path.join(os.getcwd(), *workflow_config.module.split("."))
|
133
164
|
error_content = ""
|
134
|
-
metadata_json: Optional[dict] = None
|
135
165
|
|
136
166
|
with zipfile.ZipFile(zip_buffer) as zip_file:
|
167
|
+
if METADATA_FILE_NAME in zip_file.namelist():
|
168
|
+
metadata_json: Optional[dict] = None
|
169
|
+
with zip_file.open(METADATA_FILE_NAME) as source:
|
170
|
+
metadata_json = json.load(source)
|
171
|
+
|
172
|
+
pull_contents_metadata = PullContentsMetadata.model_validate(metadata_json)
|
173
|
+
|
174
|
+
if pull_contents_metadata.runner_config:
|
175
|
+
workflow_config.container_image_name = pull_contents_metadata.runner_config.container_image_name
|
176
|
+
workflow_config.container_image_tag = pull_contents_metadata.runner_config.container_image_tag
|
177
|
+
if workflow_config.container_image_name and not workflow_config.container_image_tag:
|
178
|
+
workflow_config.container_image_tag = "latest"
|
179
|
+
|
180
|
+
if not workflow_config.module and pull_contents_metadata.label:
|
181
|
+
workflow_config.module = snake_case(pull_contents_metadata.label)
|
182
|
+
|
183
|
+
if not workflow_config.module:
|
184
|
+
raise ValueError(f"Failed to resolve a module name for Workflow {pk}")
|
185
|
+
|
186
|
+
target_dir = os.path.join(os.getcwd(), *workflow_config.module.split("."))
|
187
|
+
|
137
188
|
# Delete files in target_dir that aren't in the zip file
|
138
189
|
if os.path.exists(target_dir):
|
139
190
|
ignore_patterns = (
|
@@ -163,7 +214,6 @@ def pull_command(
|
|
163
214
|
error_content = content
|
164
215
|
continue
|
165
216
|
if file_name == METADATA_FILE_NAME:
|
166
|
-
metadata_json = json.loads(content)
|
167
217
|
continue
|
168
218
|
|
169
219
|
target_file = os.path.join(target_dir, file_name)
|
@@ -172,15 +222,6 @@ def pull_command(
|
|
172
222
|
logger.info(f"Writing to {target_file}...")
|
173
223
|
target.write(content)
|
174
224
|
|
175
|
-
if metadata_json:
|
176
|
-
runner_config = metadata_json.get("runner_config")
|
177
|
-
|
178
|
-
if runner_config:
|
179
|
-
workflow_config.container_image_name = runner_config.get("container_image_name")
|
180
|
-
workflow_config.container_image_tag = runner_config.get("container_image_tag")
|
181
|
-
if workflow_config.container_image_name and not workflow_config.container_image_tag:
|
182
|
-
workflow_config.container_image_tag = "latest"
|
183
|
-
|
184
225
|
if include_json:
|
185
226
|
logger.warning(
|
186
227
|
"""The pulled JSON representation of the Workflow should be used for debugging purposely only. \
|
@@ -190,16 +231,12 @@ Its schema should be considered unstable and subject to change at any time."""
|
|
190
231
|
if include_sandbox:
|
191
232
|
if not workflow_config.ignore:
|
192
233
|
workflow_config.ignore = "sandbox.py"
|
193
|
-
save_lock_file = True
|
194
234
|
elif isinstance(workflow_config.ignore, str) and "sandbox.py" != workflow_config.ignore:
|
195
235
|
workflow_config.ignore = [workflow_config.ignore, "sandbox.py"]
|
196
|
-
save_lock_file = True
|
197
236
|
elif isinstance(workflow_config.ignore, list) and "sandbox.py" not in workflow_config.ignore:
|
198
237
|
workflow_config.ignore.append("sandbox.py")
|
199
|
-
save_lock_file = True
|
200
238
|
|
201
|
-
|
202
|
-
config.save()
|
239
|
+
config.save()
|
203
240
|
|
204
241
|
if error_content:
|
205
242
|
logger.error(error_content)
|
vellum_cli/push.py
CHANGED
@@ -12,7 +12,6 @@ from dotenv import load_dotenv
|
|
12
12
|
from vellum.client.core.api_error import ApiError
|
13
13
|
from vellum.resources.workflows.client import OMIT
|
14
14
|
from vellum.types import WorkflowPushDeploymentConfigRequest
|
15
|
-
from vellum.workflows.utils.names import snake_to_title_case
|
16
15
|
from vellum.workflows.vellum_client import create_vellum_client
|
17
16
|
from vellum.workflows.workflows.base import BaseWorkflow
|
18
17
|
from vellum_cli.config import DEFAULT_WORKSPACE_CONFIG, WorkflowConfig, WorkflowDeploymentConfig, load_vellum_cli_config
|
@@ -111,8 +110,6 @@ def push_command(
|
|
111
110
|
"container_image_name": workflow_config.container_image_name,
|
112
111
|
}
|
113
112
|
|
114
|
-
label = snake_to_title_case(workflow_config.module.split(".")[-1])
|
115
|
-
|
116
113
|
deployment_config: WorkflowPushDeploymentConfigRequest = OMIT
|
117
114
|
deployment_config_serialized: str = OMIT
|
118
115
|
if deploy:
|
@@ -158,7 +155,6 @@ def push_command(
|
|
158
155
|
# Remove this once we could serialize using the artifact in Vembda
|
159
156
|
# https://app.shortcut.com/vellum/story/5585
|
160
157
|
exec_config=json.dumps(exec_config),
|
161
|
-
label=label,
|
162
158
|
workflow_sandbox_id=workflow_config.workflow_sandbox_id or workflow_sandbox_id,
|
163
159
|
artifact=artifact,
|
164
160
|
# We should check with fern if we could auto-serialize typed object fields for us
|
@@ -230,7 +226,7 @@ def push_command(
|
|
230
226
|
) # type: ignore[attr-defined]
|
231
227
|
else:
|
232
228
|
logger.info(
|
233
|
-
f"""Successfully pushed {
|
229
|
+
f"""Successfully pushed {workflow_config.module} to Vellum!
|
234
230
|
Visit at: https://app.vellum.ai/workflow-sandboxes/{response.workflow_sandbox_id}"""
|
235
231
|
)
|
236
232
|
|
vellum_cli/tests/test_pull.py
CHANGED
@@ -39,6 +39,7 @@ def test_pull(vellum_client, mock_module, base_command):
|
|
39
39
|
# GIVEN a module on the user's filesystem
|
40
40
|
temp_dir = mock_module.temp_dir
|
41
41
|
module = mock_module.module
|
42
|
+
workflow_sandbox_id = mock_module.workflow_sandbox_id
|
42
43
|
|
43
44
|
# AND the workflow pull API call returns a zip file
|
44
45
|
vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
|
@@ -56,6 +57,27 @@ def test_pull(vellum_client, mock_module, base_command):
|
|
56
57
|
with open(workflow_py) as f:
|
57
58
|
assert f.read() == "print('hello')"
|
58
59
|
|
60
|
+
# AND the vellum.lock.json file is created
|
61
|
+
vellum_lock_json = os.path.join(temp_dir, "vellum.lock.json")
|
62
|
+
assert os.path.exists(vellum_lock_json)
|
63
|
+
with open(vellum_lock_json) as f:
|
64
|
+
lock_data = json.load(f)
|
65
|
+
assert lock_data == {
|
66
|
+
"version": "1.0",
|
67
|
+
"workflows": [
|
68
|
+
{
|
69
|
+
"module": module,
|
70
|
+
"workflow_sandbox_id": workflow_sandbox_id,
|
71
|
+
"container_image_name": None,
|
72
|
+
"container_image_tag": None,
|
73
|
+
"ignore": None,
|
74
|
+
"deployments": [],
|
75
|
+
"workspace": "default",
|
76
|
+
}
|
77
|
+
],
|
78
|
+
"workspaces": [],
|
79
|
+
}
|
80
|
+
|
59
81
|
|
60
82
|
def test_pull__second_module(vellum_client, mock_module):
|
61
83
|
# GIVEN a module on the user's filesystem
|
@@ -95,7 +117,13 @@ def test_pull__sandbox_id_with_no_config(vellum_client):
|
|
95
117
|
workflow_sandbox_id = "87654321-0000-0000-0000-000000000000"
|
96
118
|
|
97
119
|
# AND the workflow pull API call returns a zip file
|
98
|
-
vellum_client.workflows.pull.return_value = iter(
|
120
|
+
vellum_client.workflows.pull.return_value = iter(
|
121
|
+
[
|
122
|
+
_zip_file_map(
|
123
|
+
{"workflow.py": "print('hello')", "metadata.json": json.dumps({"label": "Super Cool Workflow"})}
|
124
|
+
)
|
125
|
+
]
|
126
|
+
)
|
99
127
|
|
100
128
|
# AND we are currently in a new directory
|
101
129
|
current_dir = os.getcwd()
|
@@ -112,7 +140,7 @@ def test_pull__sandbox_id_with_no_config(vellum_client):
|
|
112
140
|
|
113
141
|
# AND the pull api is called with the workflow sandbox id
|
114
142
|
vellum_client.workflows.pull.assert_called_once()
|
115
|
-
workflow_py = os.path.join(temp_dir, "
|
143
|
+
workflow_py = os.path.join(temp_dir, "super_cool_workflow", "workflow.py")
|
116
144
|
assert os.path.exists(workflow_py)
|
117
145
|
with open(workflow_py) as f:
|
118
146
|
assert f.read() == "print('hello')"
|
@@ -127,7 +155,7 @@ def test_pull__sandbox_id_with_no_config(vellum_client):
|
|
127
155
|
"workspaces": [],
|
128
156
|
"workflows": [
|
129
157
|
{
|
130
|
-
"module": "
|
158
|
+
"module": "super_cool_workflow",
|
131
159
|
"workflow_sandbox_id": "87654321-0000-0000-0000-000000000000",
|
132
160
|
"ignore": None,
|
133
161
|
"deployments": [],
|
@@ -147,7 +175,13 @@ def test_pull__sandbox_id_with_other_workflow_configured(vellum_client, mock_mod
|
|
147
175
|
workflow_sandbox_id = "87654321-0000-0000-0000-000000000000"
|
148
176
|
|
149
177
|
# AND the workflow pull API call returns a zip file
|
150
|
-
vellum_client.workflows.pull.return_value = iter(
|
178
|
+
vellum_client.workflows.pull.return_value = iter(
|
179
|
+
[
|
180
|
+
_zip_file_map(
|
181
|
+
{"workflow.py": "print('hello')", "metadata.json": json.dumps({"label": "Super Cool Workflow"})}
|
182
|
+
)
|
183
|
+
]
|
184
|
+
)
|
151
185
|
|
152
186
|
# WHEN the user runs the pull command with the new workflow sandbox id
|
153
187
|
runner = CliRunner()
|
@@ -162,7 +196,7 @@ def test_pull__sandbox_id_with_other_workflow_configured(vellum_client, mock_mod
|
|
162
196
|
assert call_args[0] == workflow_sandbox_id
|
163
197
|
|
164
198
|
# AND the workflow.py file is written to the module directory
|
165
|
-
workflow_py = os.path.join(temp_dir, "
|
199
|
+
workflow_py = os.path.join(temp_dir, "super_cool_workflow", "workflow.py")
|
166
200
|
assert os.path.exists(workflow_py)
|
167
201
|
with open(workflow_py) as f:
|
168
202
|
assert f.read() == "print('hello')"
|
@@ -420,8 +454,12 @@ def test_pull__sandbox_id_with_other_workflow_deployment_in_lock(vellum_client,
|
|
420
454
|
_zip_file_map(
|
421
455
|
{
|
422
456
|
"workflow.py": "print('hello')",
|
423
|
-
"metadata.json":
|
424
|
-
|
457
|
+
"metadata.json": json.dumps(
|
458
|
+
{
|
459
|
+
"runner_config": {"container_image_name": "test", "container_image_tag": "1.0"},
|
460
|
+
"label": "Super Cool Workflow",
|
461
|
+
}
|
462
|
+
),
|
425
463
|
}
|
426
464
|
)
|
427
465
|
]
|
@@ -456,7 +494,7 @@ def test_pull__sandbox_id_with_other_workflow_deployment_in_lock(vellum_client,
|
|
456
494
|
"workspace": "default",
|
457
495
|
},
|
458
496
|
{
|
459
|
-
"module": "
|
497
|
+
"module": "super_cool_workflow",
|
460
498
|
"workflow_sandbox_id": new_workflow_sandbox_id,
|
461
499
|
"ignore": None,
|
462
500
|
"deployments": [],
|
@@ -539,3 +577,72 @@ def test_pull__include_sandbox(vellum_client, mock_module):
|
|
539
577
|
with open(lock_json) as f:
|
540
578
|
lock_data = json.load(f)
|
541
579
|
assert lock_data["workflows"][0]["ignore"] == "sandbox.py"
|
580
|
+
|
581
|
+
|
582
|
+
def test_pull__same_pull_twice__one_entry_in_lockfile(vellum_client, mock_module):
|
583
|
+
# GIVEN a module on the user's filesystem
|
584
|
+
module = mock_module.module
|
585
|
+
temp_dir = mock_module.temp_dir
|
586
|
+
workflow_sandbox_id = mock_module.workflow_sandbox_id
|
587
|
+
|
588
|
+
# AND the workflow pull API call returns a zip file both times
|
589
|
+
zip_contents = _zip_file_map({"workflow.py": "print('hello')"})
|
590
|
+
responses = iter([zip_contents, zip_contents])
|
591
|
+
|
592
|
+
def workflows_pull_side_effect(*args, **kwargs):
|
593
|
+
return iter([next(responses)])
|
594
|
+
|
595
|
+
vellum_client.workflows.pull.side_effect = workflows_pull_side_effect
|
596
|
+
|
597
|
+
# AND the user runs the pull command once
|
598
|
+
runner = CliRunner()
|
599
|
+
runner.invoke(cli_main, ["pull", module])
|
600
|
+
|
601
|
+
# WHEN the user runs the pull command again but with the workflow sandbox id
|
602
|
+
result = runner.invoke(cli_main, ["workflows", "pull", "--workflow-sandbox-id", workflow_sandbox_id])
|
603
|
+
|
604
|
+
# THEN the command returns successfully
|
605
|
+
assert result.exit_code == 0, (result.output, result.exception)
|
606
|
+
|
607
|
+
# AND the lockfile should only have one entry
|
608
|
+
lock_json = os.path.join(temp_dir, "vellum.lock.json")
|
609
|
+
with open(lock_json) as f:
|
610
|
+
lock_data = json.load(f)
|
611
|
+
assert len(lock_data["workflows"]) == 1
|
612
|
+
|
613
|
+
|
614
|
+
def test_pull__module_not_in_config(vellum_client, mock_module):
|
615
|
+
# GIVEN a module on the user's filesystem
|
616
|
+
module = mock_module.module
|
617
|
+
temp_dir = mock_module.temp_dir
|
618
|
+
workflow_sandbox_id = mock_module.workflow_sandbox_id
|
619
|
+
set_pyproject_toml = mock_module.set_pyproject_toml
|
620
|
+
|
621
|
+
# AND the pyproject.toml does not have the module configured
|
622
|
+
set_pyproject_toml({"workflows": []})
|
623
|
+
|
624
|
+
# AND the workflow pull API call returns a zip file
|
625
|
+
vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
|
626
|
+
|
627
|
+
# WHEN the user runs the pull command again with the workflow sandbox id and module
|
628
|
+
runner = CliRunner()
|
629
|
+
result = runner.invoke(cli_main, ["workflows", "pull", module, "--workflow-sandbox-id", workflow_sandbox_id])
|
630
|
+
|
631
|
+
# THEN the command returns successfully
|
632
|
+
assert result.exit_code == 0, (result.output, result.exception)
|
633
|
+
|
634
|
+
# AND the lockfile should have the new entry
|
635
|
+
lock_json = os.path.join(temp_dir, "vellum.lock.json")
|
636
|
+
with open(lock_json) as f:
|
637
|
+
lock_data = json.load(f)
|
638
|
+
assert lock_data["workflows"] == [
|
639
|
+
{
|
640
|
+
"module": module,
|
641
|
+
"workflow_sandbox_id": workflow_sandbox_id,
|
642
|
+
"ignore": None,
|
643
|
+
"deployments": [],
|
644
|
+
"container_image_name": None,
|
645
|
+
"container_image_tag": None,
|
646
|
+
"workspace": "default",
|
647
|
+
}
|
648
|
+
]
|
vellum_cli/tests/test_push.py
CHANGED
@@ -119,14 +119,12 @@ def test_push__happy_path(mock_module, vellum_client, base_command):
|
|
119
119
|
assert result.exit_code == 0
|
120
120
|
|
121
121
|
# Get the last part of the module path and format it
|
122
|
-
expected_label = mock_module.module.split(".")[-1].replace("_", " ").title()
|
123
122
|
expected_artifact_name = f"{mock_module.module.replace('.', '__')}.tar.gz"
|
124
123
|
|
125
124
|
# AND we should have called the push API with the correct args
|
126
125
|
vellum_client.workflows.push.assert_called_once()
|
127
126
|
call_args = vellum_client.workflows.push.call_args.kwargs
|
128
127
|
assert json.loads(call_args["exec_config"])["workflow_raw_data"]["definition"]["name"] == "ExampleWorkflow"
|
129
|
-
assert call_args["label"] == expected_label
|
130
128
|
assert is_valid_uuid(call_args["workflow_sandbox_id"])
|
131
129
|
assert call_args["artifact"].name == expected_artifact_name
|
132
130
|
assert "deplyment_config" not in call_args
|
@@ -165,14 +163,12 @@ def test_push__workflow_sandbox_option__existing_id(mock_module, vellum_client,
|
|
165
163
|
assert result.exit_code == 0
|
166
164
|
|
167
165
|
# Get the last part of the module path and format it
|
168
|
-
expected_label = mock_module.module.split(".")[-1].replace("_", " ").title()
|
169
166
|
expected_artifact_name = f"{mock_module.module.replace('.', '__')}.tar.gz"
|
170
167
|
|
171
168
|
# AND we should have called the push API with the correct args
|
172
169
|
vellum_client.workflows.push.assert_called_once()
|
173
170
|
call_args = vellum_client.workflows.push.call_args.kwargs
|
174
171
|
assert json.loads(call_args["exec_config"])["workflow_raw_data"]["definition"]["name"] == "ExampleWorkflow"
|
175
|
-
assert call_args["label"] == expected_label
|
176
172
|
assert call_args["workflow_sandbox_id"] == existing_workflow_sandbox_id
|
177
173
|
assert call_args["artifact"].name == expected_artifact_name
|
178
174
|
assert "deplyment_config" not in call_args
|
@@ -216,14 +212,12 @@ def test_push__workflow_sandbox_option__existing_no_module(mock_module, vellum_c
|
|
216
212
|
assert result.exit_code == 0
|
217
213
|
|
218
214
|
# Get the last part of the module path and format it
|
219
|
-
expected_label = second_module.split(".")[-1].replace("_", " ").title()
|
220
215
|
expected_artifact_name = f"{second_module.replace('.', '__')}.tar.gz"
|
221
216
|
|
222
217
|
# AND we should have called the push API with the correct args
|
223
218
|
vellum_client.workflows.push.assert_called_once()
|
224
219
|
call_args = vellum_client.workflows.push.call_args.kwargs
|
225
220
|
assert json.loads(call_args["exec_config"])["workflow_raw_data"]["definition"]["name"] == "ExampleWorkflow"
|
226
|
-
assert call_args["label"] == expected_label
|
227
221
|
assert call_args["workflow_sandbox_id"] == second_workflow_sandbox_id
|
228
222
|
assert call_args["artifact"].name == expected_artifact_name
|
229
223
|
assert "deplyment_config" not in call_args
|
@@ -297,14 +291,12 @@ def test_push__deployment(mock_module, vellum_client, base_command):
|
|
297
291
|
assert result.exit_code == 0
|
298
292
|
|
299
293
|
# Get the last part of the module path and format it
|
300
|
-
expected_label = mock_module.module.split(".")[-1].replace("_", " ").title()
|
301
294
|
expected_artifact_name = f"{mock_module.module.replace('.', '__')}.tar.gz"
|
302
295
|
|
303
296
|
# AND we should have called the push API with the correct args
|
304
297
|
vellum_client.workflows.push.assert_called_once()
|
305
298
|
call_args = vellum_client.workflows.push.call_args.kwargs
|
306
299
|
assert json.loads(call_args["exec_config"])["workflow_raw_data"]["definition"]["name"] == "ExampleWorkflow"
|
307
|
-
assert call_args["label"] == expected_label
|
308
300
|
assert is_valid_uuid(call_args["workflow_sandbox_id"])
|
309
301
|
assert call_args["artifact"].name == expected_artifact_name
|
310
302
|
assert call_args["deployment_config"] == "{}"
|