vellum-ai 0.14.30__py3-none-any.whl → 0.14.31__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/workflows/nodes/displayable/code_execution_node/node.py +2 -1
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +16 -2
- vellum/workflows/state/context.py +6 -0
- {vellum_ai-0.14.30.dist-info → vellum_ai-0.14.31.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.30.dist-info → vellum_ai-0.14.31.dist-info}/RECORD +12 -12
- vellum_cli/pull.py +67 -62
- vellum_cli/tests/test_pull.py +18 -0
- vellum_ee/workflows/tests/test_server.py +13 -21
- {vellum_ai-0.14.30.dist-info → vellum_ai-0.14.31.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.30.dist-info → vellum_ai-0.14.31.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.30.dist-info → vellum_ai-0.14.31.dist-info}/entry_points.txt +0 -0
@@ -18,7 +18,7 @@ class BaseClientWrapper:
|
|
18
18
|
headers: typing.Dict[str, str] = {
|
19
19
|
"X-Fern-Language": "Python",
|
20
20
|
"X-Fern-SDK-Name": "vellum-ai",
|
21
|
-
"X-Fern-SDK-Version": "0.14.
|
21
|
+
"X-Fern-SDK-Version": "0.14.31",
|
22
22
|
}
|
23
23
|
headers["X_API_KEY"] = self.api_key
|
24
24
|
return headers
|
@@ -227,7 +227,8 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
|
|
227
227
|
)
|
228
228
|
|
229
229
|
root = inspect.getfile(self.__class__)
|
230
|
-
|
230
|
+
|
231
|
+
code = read_file_from_path(node_filepath=root, script_filepath=self.filepath, context=self._context)
|
231
232
|
if not code:
|
232
233
|
raise NodeException(
|
233
234
|
message=f"Filepath '{self.filepath}' does not exist",
|
@@ -1,19 +1,33 @@
|
|
1
1
|
import io
|
2
2
|
import os
|
3
|
-
from typing import Any, Tuple, Union
|
3
|
+
from typing import Any, Optional, Tuple, Union
|
4
4
|
|
5
5
|
from pydantic import BaseModel
|
6
6
|
|
7
7
|
from vellum.workflows.errors.types import WorkflowErrorCode
|
8
8
|
from vellum.workflows.exceptions import NodeException
|
9
9
|
from vellum.workflows.nodes.utils import cast_to_output_type
|
10
|
+
from vellum.workflows.state.context import WorkflowContext
|
10
11
|
from vellum.workflows.types.core import EntityInputsInterface
|
11
12
|
|
12
13
|
|
13
|
-
def read_file_from_path(
|
14
|
+
def read_file_from_path(
|
15
|
+
node_filepath: str, script_filepath: str, context: Optional[WorkflowContext] = None
|
16
|
+
) -> Union[str, None]:
|
14
17
|
node_filepath_dir = os.path.dirname(node_filepath)
|
15
18
|
full_filepath = os.path.join(node_filepath_dir, script_filepath)
|
16
19
|
|
20
|
+
# If dynamic file loader is present, try and read the code from there
|
21
|
+
if context and context.generated_files:
|
22
|
+
# Strip out namespace
|
23
|
+
normalized_path = os.path.normpath(full_filepath)
|
24
|
+
stripped_node_filepath = "/".join(normalized_path.split("/")[1:])
|
25
|
+
|
26
|
+
code = context.generated_files.get(stripped_node_filepath, None)
|
27
|
+
if code is not None:
|
28
|
+
return code
|
29
|
+
|
30
|
+
# Default logic for reading from filesystem
|
17
31
|
try:
|
18
32
|
with open(full_filepath) as file:
|
19
33
|
return file.read()
|
@@ -19,6 +19,7 @@ class WorkflowContext:
|
|
19
19
|
*,
|
20
20
|
vellum_client: Optional[Vellum] = None,
|
21
21
|
execution_context: Optional[ExecutionContext] = None,
|
22
|
+
generated_files: Optional[dict[str, str]] = None,
|
22
23
|
):
|
23
24
|
self._vellum_client = vellum_client
|
24
25
|
self._event_queue: Optional[Queue["WorkflowEvent"]] = None
|
@@ -26,6 +27,7 @@ class WorkflowContext:
|
|
26
27
|
self._execution_context = get_execution_context()
|
27
28
|
if not self._execution_context.parent_context and execution_context:
|
28
29
|
self._execution_context = execution_context
|
30
|
+
self._generated_files = generated_files
|
29
31
|
|
30
32
|
@cached_property
|
31
33
|
def vellum_client(self) -> Vellum:
|
@@ -38,6 +40,10 @@ class WorkflowContext:
|
|
38
40
|
def execution_context(self) -> ExecutionContext:
|
39
41
|
return self._execution_context
|
40
42
|
|
43
|
+
@cached_property
|
44
|
+
def generated_files(self) -> Optional[dict[str, str]]:
|
45
|
+
return self._generated_files
|
46
|
+
|
41
47
|
@cached_property
|
42
48
|
def node_output_mocks_map(self) -> Dict[Type[BaseOutputs], List[MockNodeExecution]]:
|
43
49
|
return self._node_output_mocks_map
|
@@ -7,7 +7,7 @@ vellum_cli/image_push.py,sha256=8DDvRDJEZ-FukUCqGW1827bg1ybF4xBbx9WyqWYQE-g,6816
|
|
7
7
|
vellum_cli/init.py,sha256=WpnMXPItPmh0f0bBGIer3p-e5gu8DUGwSArT_FuoMEw,5093
|
8
8
|
vellum_cli/logger.py,sha256=PuRFa0WCh4sAGFS5aqWB0QIYpS6nBWwPJrIXpWxugV4,1022
|
9
9
|
vellum_cli/ping.py,sha256=lWyJw6sziXjyTopTYRdFF5hV-sYPVDdX0yVbG5fzcY4,585
|
10
|
-
vellum_cli/pull.py,sha256=
|
10
|
+
vellum_cli/pull.py,sha256=Cz4_LWeaMNRGw4qvKpUBFnOpY6PXzJJ-9d7NU90S9Jc,9629
|
11
11
|
vellum_cli/push.py,sha256=xjTNbLwOVFNU3kpBrm56Bk5QkSRrJ9z86qceghCzfIA,9655
|
12
12
|
vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
13
|
vellum_cli/tests/conftest.py,sha256=AFYZryKA2qnUuCPBxBKmHLFoPiE0WhBFFej9tNwSHdc,1526
|
@@ -16,7 +16,7 @@ vellum_cli/tests/test_image_push.py,sha256=i3lJuW8nFRwL1M1OF6752IZYvGAFgKmkB2hd_
|
|
16
16
|
vellum_cli/tests/test_init.py,sha256=8UOc_ThfouR4ja5cCl_URuLk7ohr9JXfCnG4yka1OUQ,18754
|
17
17
|
vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
|
18
18
|
vellum_cli/tests/test_ping.py,sha256=QtbhYKMYn1DFnDyBij2mkQO32j9KOpZ5Pf0yek7k_Ao,1284
|
19
|
-
vellum_cli/tests/test_pull.py,sha256=
|
19
|
+
vellum_cli/tests/test_pull.py,sha256=asWPuOOeGY1Tj_JGu574A3-pnNKCDY0HqjaSWI0BXss,32824
|
20
20
|
vellum_cli/tests/test_push.py,sha256=zDv_Q1hbXtLwmTJDPRAvwDjbuHC09uNRYOy4FQujUow,23476
|
21
21
|
vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
22
|
vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -121,14 +121,14 @@ vellum_ee/workflows/tests/local_workflow/nodes/final_output.py,sha256=ZX7zBv87zi
|
|
121
121
|
vellum_ee/workflows/tests/local_workflow/nodes/templating_node.py,sha256=NQwFN61QkHfI3Vssz-B0NKGfupK8PU0FDSAIAhYBLi0,325
|
122
122
|
vellum_ee/workflows/tests/local_workflow/workflow.py,sha256=A4qOzOPNwePYxWbcAgIPLsmrVS_aVEZEc-wULSv787Q,393
|
123
123
|
vellum_ee/workflows/tests/test_display_meta.py,sha256=C25dErwghPNXio49pvSRxyOuc96srH6eYEwTAWdE2zY,2258
|
124
|
-
vellum_ee/workflows/tests/test_server.py,sha256=
|
124
|
+
vellum_ee/workflows/tests/test_server.py,sha256=Q9XD93jMwYjZOkcwMPNM2F4BWvcY71wxkYp8HgMgGFU,4435
|
125
125
|
vellum_ee/workflows/tests/test_virtual_files.py,sha256=TJEcMR0v2S8CkloXNmCHA0QW0K6pYNGaIjraJz7sFvY,2762
|
126
126
|
vellum/__init__.py,sha256=88-79I29hBTQvR1uH_BOCGMWuj2a4Nx82R_8KIESg28,40470
|
127
127
|
vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
|
128
128
|
vellum/client/__init__.py,sha256=Jv9sI5BNFo2OYA9px_aREFSIp655ryC3eaZSRI6yH1k,117826
|
129
129
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
130
130
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
131
|
-
vellum/client/core/client_wrapper.py,sha256=
|
131
|
+
vellum/client/core/client_wrapper.py,sha256=PGwx4aPEP3yRHu1laYbSTTdEDpTOYg6DZU5rt8u-QZo,1869
|
132
132
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
133
133
|
vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
|
134
134
|
vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
|
@@ -1543,12 +1543,12 @@ vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMD
|
|
1543
1543
|
vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
|
1544
1544
|
vellum/workflows/nodes/displayable/bases/utils.py,sha256=ckMUenSsNkiYmSw6FmjSMHYaCk8Y8_sUjL6lkFFEqts,5412
|
1545
1545
|
vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
|
1546
|
-
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=
|
1546
|
+
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=Ko_Dy17AjfSx2A4u5Xno5R0KH2p5akEHq8L0rQkySGs,9576
|
1547
1547
|
vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1548
1548
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1549
1549
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
|
1550
1550
|
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=xAaoOfQHQUlp0iKlig87t0aT2cJM-8PxiTb1QDg8VmY,24641
|
1551
|
-
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=
|
1551
|
+
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=G-sc7yOL5g6rLk99X8HAbXNcLxRaqpju9IXq1iUwnQI,4470
|
1552
1552
|
vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
|
1553
1553
|
vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
|
1554
1554
|
vellum/workflows/nodes/displayable/conftest.py,sha256=tD_WIiw5WjFqnzgnGLtEZDaMj2XhQ1DptnBTKYeBbI0,5705
|
@@ -1618,7 +1618,7 @@ vellum/workflows/runner/runner.py,sha256=ww4fjZJBENkB5HJxdj92kTz7k_EyifCeAreupy5
|
|
1618
1618
|
vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2235
|
1619
1619
|
vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
|
1620
1620
|
vellum/workflows/state/base.py,sha256=Vkhneko3VlQrPsMLU1PYSzXU_W1u7_AraJsghiv5O-4,15512
|
1621
|
-
vellum/workflows/state/context.py,sha256=
|
1621
|
+
vellum/workflows/state/context.py,sha256=B-sGK9GpZPh7bgCPb8PJCrl_evod3Ru7rHs_RofisrU,2926
|
1622
1622
|
vellum/workflows/state/encoder.py,sha256=TnOQojc5lTQ83g9QbpA4UCqShJvutmTMxbpKt-9gNe4,1911
|
1623
1623
|
vellum/workflows/state/store.py,sha256=uVe-oN73KwGV6M6YLhwZMMUQhzTQomsVfVnb8V91gVo,1147
|
1624
1624
|
vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1650,8 +1650,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1650
1650
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1651
1651
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=tCxrV3QBHL8wfdEO3bvKteDdw32xBlUl1_WxkAwaONw,8344
|
1652
1652
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1653
|
-
vellum_ai-0.14.
|
1654
|
-
vellum_ai-0.14.
|
1655
|
-
vellum_ai-0.14.
|
1656
|
-
vellum_ai-0.14.
|
1657
|
-
vellum_ai-0.14.
|
1653
|
+
vellum_ai-0.14.31.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1654
|
+
vellum_ai-0.14.31.dist-info/METADATA,sha256=BDTX1i0ZWziXvzVjwWKd3C6uEiD3QMQol9_a636y0-s,5484
|
1655
|
+
vellum_ai-0.14.31.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1656
|
+
vellum_ai-0.14.31.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1657
|
+
vellum_ai-0.14.31.dist-info/RECORD,,
|
vellum_cli/pull.py
CHANGED
@@ -151,68 +151,73 @@ def pull_command(
|
|
151
151
|
|
152
152
|
error_content = ""
|
153
153
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
workflow_config.
|
167
|
-
|
168
|
-
workflow_config.module
|
169
|
-
|
170
|
-
workflow_config.module
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
for
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
154
|
+
try:
|
155
|
+
with zipfile.ZipFile(zip_buffer) as zip_file:
|
156
|
+
if METADATA_FILE_NAME in zip_file.namelist():
|
157
|
+
metadata_json: Optional[dict] = None
|
158
|
+
with zip_file.open(METADATA_FILE_NAME) as source:
|
159
|
+
metadata_json = json.load(source)
|
160
|
+
|
161
|
+
pull_contents_metadata = PullContentsMetadata.model_validate(metadata_json)
|
162
|
+
|
163
|
+
if pull_contents_metadata.runner_config:
|
164
|
+
workflow_config.container_image_name = pull_contents_metadata.runner_config.container_image_name
|
165
|
+
workflow_config.container_image_tag = pull_contents_metadata.runner_config.container_image_tag
|
166
|
+
if workflow_config.container_image_name and not workflow_config.container_image_tag:
|
167
|
+
workflow_config.container_image_tag = "latest"
|
168
|
+
if not workflow_config.module and workflow_deployment and pull_contents_metadata.deployment_name:
|
169
|
+
workflow_config.module = snake_case(pull_contents_metadata.deployment_name)
|
170
|
+
if not workflow_config.module and pull_contents_metadata.label:
|
171
|
+
workflow_config.module = snake_case(pull_contents_metadata.label)
|
172
|
+
|
173
|
+
if not workflow_config.module:
|
174
|
+
raise ValueError(f"Failed to resolve a module name for Workflow {pk}")
|
175
|
+
|
176
|
+
# Use target_directory if provided, otherwise use current working directory
|
177
|
+
base_dir = os.path.join(os.getcwd(), target_directory) if target_directory else os.getcwd()
|
178
|
+
target_dir = os.path.join(base_dir, *workflow_config.module.split("."))
|
179
|
+
workflow_config.target_directory = target_dir if target_directory else None
|
180
|
+
|
181
|
+
# Delete files in target_dir that aren't in the zip file
|
182
|
+
if os.path.exists(target_dir):
|
183
|
+
ignore_patterns = (
|
184
|
+
workflow_config.ignore
|
185
|
+
if isinstance(workflow_config.ignore, list)
|
186
|
+
else [workflow_config.ignore] if isinstance(workflow_config.ignore, str) else []
|
187
|
+
)
|
188
|
+
existing_files = []
|
189
|
+
for root, _, files in os.walk(target_dir):
|
190
|
+
for file in files:
|
191
|
+
rel_path = os.path.relpath(os.path.join(root, file), target_dir)
|
192
|
+
existing_files.append(rel_path)
|
193
|
+
|
194
|
+
for file in existing_files:
|
195
|
+
if any(Path(file).match(ignore_pattern) for ignore_pattern in ignore_patterns):
|
196
|
+
continue
|
197
|
+
|
198
|
+
if file not in zip_file.namelist():
|
199
|
+
file_path = os.path.join(target_dir, file)
|
200
|
+
logger.info(f"Deleting {file_path}...")
|
201
|
+
os.remove(file_path)
|
202
|
+
|
203
|
+
for file_name in zip_file.namelist():
|
204
|
+
with zip_file.open(file_name) as source:
|
205
|
+
content = source.read().decode("utf-8")
|
206
|
+
if file_name == ERROR_LOG_FILE_NAME:
|
207
|
+
error_content = content
|
208
|
+
continue
|
209
|
+
if file_name == METADATA_FILE_NAME:
|
210
|
+
continue
|
211
|
+
|
212
|
+
target_file = os.path.join(target_dir, file_name)
|
213
|
+
os.makedirs(os.path.dirname(target_file), exist_ok=True)
|
214
|
+
with open(target_file, "w") as target:
|
215
|
+
logger.info(f"Writing to {target_file}...")
|
216
|
+
target.write(content)
|
217
|
+
except zipfile.BadZipFile:
|
218
|
+
raise Exception(
|
219
|
+
"The API we tried to pull from returned an invalid zip file. Please make sure your `VELLUM_API_URL` environment variable is set correctly." # noqa: E501
|
220
|
+
)
|
216
221
|
|
217
222
|
if include_json:
|
218
223
|
logger.warning(
|
vellum_cli/tests/test_pull.py
CHANGED
@@ -875,3 +875,21 @@ def test_pull__module_name_from_deployment_name(vellum_client):
|
|
875
875
|
assert os.path.exists(workflow_py)
|
876
876
|
with open(workflow_py) as f:
|
877
877
|
assert f.read() == "print('hello')"
|
878
|
+
|
879
|
+
|
880
|
+
def test_pull__invalid_zip_file(vellum_client):
|
881
|
+
workflow_deployment = "test-workflow-deployment-id"
|
882
|
+
|
883
|
+
# GIVEN a workflow pull API call returns an invalid zip file
|
884
|
+
vellum_client.workflows.pull.return_value = iter([b"invalid"]) # Return bytes instead of string
|
885
|
+
|
886
|
+
# WHEN the user runs the pull command
|
887
|
+
runner = CliRunner()
|
888
|
+
result = runner.invoke(cli_main, ["workflows", "pull", "--workflow-deployment", workflow_deployment])
|
889
|
+
|
890
|
+
# THEN the command returns an error
|
891
|
+
assert result.exit_code == 1
|
892
|
+
assert (
|
893
|
+
str(result.exception)
|
894
|
+
== "The API we tried to pull from returned an invalid zip file. Please make sure your `VELLUM_API_URL` environment variable is set correctly." # noqa: E501
|
895
|
+
)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import pytest
|
2
1
|
import sys
|
3
2
|
from uuid import uuid4
|
4
3
|
from typing import Type, cast
|
@@ -8,14 +7,10 @@ from vellum.client.types.code_executor_response import CodeExecutorResponse
|
|
8
7
|
from vellum.client.types.number_vellum_value import NumberVellumValue
|
9
8
|
from vellum.workflows import BaseWorkflow
|
10
9
|
from vellum.workflows.nodes import BaseNode
|
10
|
+
from vellum.workflows.state.context import WorkflowContext
|
11
11
|
from vellum_ee.workflows.server.virtual_file_loader import VirtualFileFinder
|
12
12
|
|
13
13
|
|
14
|
-
@pytest.fixture
|
15
|
-
def mock_open(mocker):
|
16
|
-
return mocker.patch("vellum.workflows.nodes.displayable.code_execution_node.utils.open")
|
17
|
-
|
18
|
-
|
19
14
|
def test_load_workflow_event_display_context():
|
20
15
|
# DEPRECATED: Use `vellum.workflows.events.workflow.WorkflowEventDisplayContext` instead. Will be removed in 0.15.0
|
21
16
|
from vellum_ee.workflows.display.types import WorkflowEventDisplayContext
|
@@ -80,7 +75,6 @@ class StartNode(BaseNode):
|
|
80
75
|
|
81
76
|
|
82
77
|
def test_load_from_module__ts_code_in_file_loader(
|
83
|
-
mock_open,
|
84
78
|
vellum_client,
|
85
79
|
):
|
86
80
|
# GIVEN typescript code
|
@@ -91,19 +85,22 @@ def test_load_from_module__ts_code_in_file_loader(
|
|
91
85
|
# AND a workflow module with only a code execution node
|
92
86
|
files = {
|
93
87
|
"__init__.py": "",
|
94
|
-
"workflow.py": """
|
88
|
+
"workflow.py": """
|
95
89
|
from vellum.workflows import BaseWorkflow
|
96
90
|
from .nodes.code_execution_node import CodeExecutionNode
|
97
91
|
|
98
92
|
class Workflow(BaseWorkflow):
|
99
93
|
graph = CodeExecutionNode
|
94
|
+
|
95
|
+
class Outputs(BaseWorkflow.Outputs):
|
96
|
+
final_output = CodeExecutionNode.Outputs.result
|
100
97
|
""",
|
101
|
-
"nodes/__init__.py": """
|
98
|
+
"nodes/__init__.py": """
|
102
99
|
from .code_execution_node import CodeExecutionNode
|
103
100
|
|
104
101
|
__all__ = ["CodeExecutionNode"]
|
105
102
|
""",
|
106
|
-
"nodes/code_execution_node.py": """
|
103
|
+
"nodes/code_execution_node/__init__.py": """
|
107
104
|
from typing import Any
|
108
105
|
|
109
106
|
from vellum.workflows.nodes.displayable import CodeExecutionNode as BaseCodeExecutionNode
|
@@ -121,10 +118,8 @@ class CodeExecutionNode(BaseCodeExecutionNode[BaseState, int]):
|
|
121
118
|
namespace = str(uuid4())
|
122
119
|
|
123
120
|
# AND the virtual file loader is registered
|
124
|
-
|
125
|
-
|
126
|
-
# AND the open function returns our file content
|
127
|
-
mock_open.return_value.__enter__.return_value.read.return_value = ts_code
|
121
|
+
finder = VirtualFileFinder(files, namespace)
|
122
|
+
sys.meta_path.append(finder)
|
128
123
|
|
129
124
|
# AND we know what the Code Execution Node will respond with
|
130
125
|
mock_code_execution = CodeExecutorResponse(
|
@@ -135,16 +130,13 @@ class CodeExecutionNode(BaseCodeExecutionNode[BaseState, int]):
|
|
135
130
|
|
136
131
|
# WHEN the workflow is loaded
|
137
132
|
Workflow = BaseWorkflow.load_from_module(namespace)
|
138
|
-
workflow = Workflow()
|
133
|
+
workflow = Workflow(context=WorkflowContext(generated_files=files))
|
139
134
|
|
140
135
|
# THEN the workflow is successfully initialized
|
141
136
|
assert workflow
|
142
137
|
|
143
138
|
event = workflow.run()
|
144
|
-
assert event.name == "workflow.execution.fulfilled"
|
145
|
-
|
146
|
-
# AND we pass in the correct file path to the open function
|
147
|
-
assert mock_open.call_args[0][0] == f"{namespace}/nodes/./script.ts"
|
139
|
+
assert event.name == "workflow.execution.fulfilled"
|
148
140
|
|
149
|
-
# AND we
|
150
|
-
assert
|
141
|
+
# AND we get the code execution result
|
142
|
+
assert event.body.outputs == {"final_output": 5.0}
|
File without changes
|
File without changes
|
File without changes
|