vellum-ai 0.10.9__py3-none-any.whl → 0.11.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. vellum/__init__.py +16 -0
  2. vellum/client/core/client_wrapper.py +1 -1
  3. vellum/client/types/__init__.py +28 -0
  4. vellum/client/types/test_suite_run_exec_config.py +7 -1
  5. vellum/client/types/test_suite_run_exec_config_request.py +8 -0
  6. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config.py +31 -0
  7. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_data.py +27 -0
  8. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_data_request.py +27 -0
  9. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_request.py +31 -0
  10. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config.py +31 -0
  11. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_data.py +27 -0
  12. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_data_request.py +27 -0
  13. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_request.py +31 -0
  14. vellum/evaluations/resources.py +7 -12
  15. vellum/evaluations/utils/env.py +1 -3
  16. vellum/evaluations/utils/paginator.py +0 -1
  17. vellum/evaluations/utils/typing.py +1 -1
  18. vellum/evaluations/utils/uuid.py +1 -1
  19. vellum/plugins/vellum_mypy.py +3 -1
  20. vellum/types/test_suite_run_prompt_sandbox_history_item_exec_config.py +3 -0
  21. vellum/types/test_suite_run_prompt_sandbox_history_item_exec_config_data.py +3 -0
  22. vellum/types/test_suite_run_prompt_sandbox_history_item_exec_config_data_request.py +3 -0
  23. vellum/types/test_suite_run_prompt_sandbox_history_item_exec_config_request.py +3 -0
  24. vellum/types/test_suite_run_workflow_sandbox_history_item_exec_config.py +3 -0
  25. vellum/types/test_suite_run_workflow_sandbox_history_item_exec_config_data.py +3 -0
  26. vellum/types/test_suite_run_workflow_sandbox_history_item_exec_config_data_request.py +3 -0
  27. vellum/types/test_suite_run_workflow_sandbox_history_item_exec_config_request.py +3 -0
  28. vellum/workflows/context.py +42 -0
  29. vellum/workflows/events/node.py +7 -6
  30. vellum/workflows/events/tests/test_event.py +0 -1
  31. vellum/workflows/events/types.py +0 -1
  32. vellum/workflows/events/workflow.py +19 -1
  33. vellum/workflows/nodes/bases/base.py +17 -56
  34. vellum/workflows/nodes/bases/tests/test_base_node.py +0 -1
  35. vellum/workflows/nodes/core/inline_subworkflow_node/node.py +13 -7
  36. vellum/workflows/nodes/core/templating_node/node.py +1 -0
  37. vellum/workflows/nodes/core/try_node/node.py +2 -2
  38. vellum/workflows/nodes/core/try_node/tests/test_node.py +1 -3
  39. vellum/workflows/nodes/displayable/api_node/node.py +3 -2
  40. vellum/workflows/nodes/displayable/bases/api_node/node.py +1 -1
  41. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +0 -1
  42. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +9 -1
  43. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +12 -2
  44. vellum/workflows/nodes/displayable/bases/search_node.py +0 -1
  45. vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +0 -1
  46. vellum/workflows/nodes/displayable/code_execution_node/utils.py +3 -2
  47. vellum/workflows/nodes/displayable/conditional_node/node.py +1 -1
  48. vellum/workflows/nodes/displayable/guardrail_node/node.py +0 -1
  49. vellum/workflows/nodes/displayable/inline_prompt_node/node.py +1 -0
  50. vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +3 -1
  51. vellum/workflows/nodes/displayable/search_node/node.py +1 -0
  52. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +13 -3
  53. vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +10 -7
  54. vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py +0 -1
  55. vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +1 -1
  56. vellum/workflows/outputs/base.py +2 -4
  57. vellum/workflows/ports/node_ports.py +1 -1
  58. vellum/workflows/runner/runner.py +167 -202
  59. vellum/workflows/state/base.py +0 -2
  60. vellum/workflows/types/core.py +1 -0
  61. vellum/workflows/types/tests/test_utils.py +1 -0
  62. vellum/workflows/types/utils.py +0 -1
  63. vellum/workflows/utils/functions.py +74 -0
  64. vellum/workflows/utils/tests/test_functions.py +171 -0
  65. vellum/workflows/utils/tests/test_vellum_variables.py +0 -1
  66. vellum/workflows/utils/vellum_variables.py +2 -2
  67. vellum/workflows/workflows/base.py +74 -34
  68. vellum/workflows/workflows/event_filters.py +7 -12
  69. {vellum_ai-0.10.9.dist-info → vellum_ai-0.11.1.dist-info}/METADATA +1 -1
  70. {vellum_ai-0.10.9.dist-info → vellum_ai-0.11.1.dist-info}/RECORD +122 -99
  71. vellum_cli/__init__.py +147 -13
  72. vellum_cli/config.py +0 -1
  73. vellum_cli/image_push.py +1 -1
  74. vellum_cli/pull.py +31 -19
  75. vellum_cli/push.py +9 -10
  76. vellum_cli/tests/__init__.py +0 -0
  77. vellum_cli/tests/conftest.py +40 -0
  78. vellum_cli/tests/test_main.py +11 -0
  79. vellum_cli/tests/test_pull.py +143 -71
  80. vellum_cli/tests/test_push.py +173 -0
  81. vellum_ee/workflows/display/base.py +1 -0
  82. vellum_ee/workflows/display/nodes/base_node_display.py +3 -2
  83. vellum_ee/workflows/display/nodes/base_node_vellum_display.py +2 -2
  84. vellum_ee/workflows/display/nodes/get_node_display_class.py +1 -1
  85. vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +1 -1
  86. vellum_ee/workflows/display/nodes/vellum/__init__.py +1 -1
  87. vellum_ee/workflows/display/nodes/vellum/api_node.py +54 -58
  88. vellum_ee/workflows/display/nodes/vellum/conditional_node.py +39 -22
  89. vellum_ee/workflows/display/nodes/vellum/error_node.py +3 -3
  90. vellum_ee/workflows/display/nodes/vellum/final_output_node.py +0 -2
  91. vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +1 -1
  92. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +1 -1
  93. vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +4 -2
  94. vellum_ee/workflows/display/nodes/vellum/map_node.py +11 -5
  95. vellum_ee/workflows/display/nodes/vellum/merge_node.py +2 -2
  96. vellum_ee/workflows/display/nodes/vellum/note_node.py +1 -3
  97. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +1 -1
  98. vellum_ee/workflows/display/nodes/vellum/search_node.py +1 -1
  99. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +1 -1
  100. vellum_ee/workflows/display/nodes/vellum/templating_node.py +1 -1
  101. vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +5 -5
  102. vellum_ee/workflows/display/nodes/vellum/utils.py +30 -10
  103. vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +45 -0
  104. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +42 -25
  105. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +13 -39
  106. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +2 -2
  107. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +62 -58
  108. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +25 -4
  109. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +2 -1
  110. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +2 -2
  111. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +2 -2
  112. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +1 -1
  113. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +2 -1
  114. vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +2 -2
  115. vellum_ee/workflows/display/types.py +4 -4
  116. vellum_ee/workflows/display/utils/vellum.py +2 -6
  117. vellum_ee/workflows/display/vellum.py +1 -1
  118. vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +4 -1
  119. vellum_ee/workflows/display/workflows/vellum_workflow_display.py +12 -5
  120. vellum/workflows/runner/types.py +0 -16
  121. {vellum_ai-0.10.9.dist-info → vellum_ai-0.11.1.dist-info}/LICENSE +0 -0
  122. {vellum_ai-0.10.9.dist-info → vellum_ai-0.11.1.dist-info}/WHEEL +0 -0
  123. {vellum_ai-0.10.9.dist-info → vellum_ai-0.11.1.dist-info}/entry_points.txt +0 -0
vellum_cli/__init__.py CHANGED
@@ -14,14 +14,42 @@ def main() -> None:
14
14
  pass
15
15
 
16
16
 
17
- @main.command()
18
- @click.argument("module", required=False)
19
- @click.option("--deploy", is_flag=True, help="Deploy the workflow after pushing it to Vellum")
20
- @click.option("--deployment-label", type=str, help="Label to use for the deployment")
21
- @click.option("--deployment-name", type=str, help="Unique name for the deployment")
22
- @click.option("--deployment-description", type=str, help="Description for the deployment")
23
- @click.option("--release-tag", type=list, help="Release tag for the deployment", multiple=True)
17
+ class PushGroup(ClickAliasedGroup):
18
+ def get_command(self, ctx, cmd_name):
19
+ # First try to get the command normally
20
+ cmd = super().get_command(ctx, cmd_name)
21
+ if cmd is not None:
22
+ return cmd
23
+
24
+ # If no command found, call our catch-all
25
+ return push_module
26
+
27
+
28
+ @main.group(invoke_without_command=True, cls=PushGroup)
29
+ @click.pass_context
24
30
  def push(
31
+ ctx: click.Context,
32
+ ) -> None:
33
+ """Push Resources to Vellum"""
34
+
35
+ if ctx.invoked_subcommand is None:
36
+ push_command()
37
+
38
+
39
+ @main.group()
40
+ def workflows():
41
+ """Operations related to Vellum Workflows"""
42
+ pass
43
+
44
+
45
+ @workflows.command(name="push")
46
+ @click.argument("module", required=False)
47
+ @click.option("--deploy", is_flag=True, help="Deploy the Workflow after pushing it to Vellum")
48
+ @click.option("--deployment-label", type=str, help="Label to use for the Deployment")
49
+ @click.option("--deployment-name", type=str, help="Unique name for the Deployment")
50
+ @click.option("--deployment-description", type=str, help="Description for the Deployment")
51
+ @click.option("--release-tag", type=list, help="Release Tag for the Deployment", multiple=True)
52
+ def workflows_push(
25
53
  module: Optional[str],
26
54
  deploy: Optional[bool],
27
55
  deployment_label: Optional[str],
@@ -29,7 +57,11 @@ def push(
29
57
  deployment_description: Optional[str],
30
58
  release_tag: Optional[List[str]],
31
59
  ) -> None:
32
- """Push Workflow to Vellum"""
60
+ """
61
+ Push Workflows to Vellum. If a module is provided, only the Workflow for that module will be pushed.
62
+ If no module is provided, the first configured Workflow will be pushed.
63
+ """
64
+
33
65
  push_command(
34
66
  module=module,
35
67
  deploy=deploy,
@@ -40,26 +72,99 @@ def push(
40
72
  )
41
73
 
42
74
 
43
- @main.command()
75
+ @push.command(name="*", hidden=True)
76
+ @click.pass_context
77
+ @click.option("--deploy", is_flag=True, help="Deploy the Resource after pushing it to Vellum")
78
+ @click.option("--deployment-label", type=str, help="Label to use for the Deployment")
79
+ @click.option("--deployment-name", type=str, help="Unique name for the Deployment")
80
+ @click.option("--deployment-description", type=str, help="Description for the Deployment")
81
+ @click.option("--release-tag", type=list, help="Release Tag for the Deployment", multiple=True)
82
+ def push_module(
83
+ ctx: click.Context,
84
+ deploy: Optional[bool],
85
+ deployment_label: Optional[str],
86
+ deployment_name: Optional[str],
87
+ deployment_description: Optional[str],
88
+ release_tag: Optional[List[str]],
89
+ ) -> None:
90
+ """Push a specific module to Vellum"""
91
+
92
+ if ctx.parent:
93
+ push_command(
94
+ module=ctx.parent.invoked_subcommand,
95
+ deploy=deploy,
96
+ deployment_label=deployment_label,
97
+ deployment_name=deployment_name,
98
+ deployment_description=deployment_description,
99
+ release_tags=release_tag,
100
+ )
101
+
102
+
103
+ class PullGroup(ClickAliasedGroup):
104
+ def get_command(self, ctx, cmd_name):
105
+ # First try to get the command normally
106
+ cmd = super().get_command(ctx, cmd_name)
107
+ if cmd is not None:
108
+ return cmd
109
+
110
+ # If no command found, call our catch-all
111
+ return pull_module
112
+
113
+
114
+ @main.group(invoke_without_command=True, cls=PullGroup)
115
+ @click.pass_context
116
+ @click.option(
117
+ "--include-json",
118
+ is_flag=True,
119
+ help="""Include the JSON representation of each Resource in the pull response. \
120
+ Should only be used for debugging purposes.""",
121
+ )
122
+ @click.option(
123
+ "--exclude-code",
124
+ is_flag=True,
125
+ help="""Exclude the code definition of each Resource from the pull response. \
126
+ Should only be used for debugging purposes.""",
127
+ )
128
+ def pull(
129
+ ctx: click.Context,
130
+ include_json: Optional[bool],
131
+ exclude_code: Optional[bool],
132
+ ) -> None:
133
+ """Pull Resources from Vellum"""
134
+
135
+ if ctx.invoked_subcommand is None:
136
+ pull_command(
137
+ include_json=include_json,
138
+ exclude_code=exclude_code,
139
+ )
140
+
141
+
142
+ @workflows.command(name="pull")
44
143
  @click.argument("module", required=False)
45
144
  @click.option(
46
145
  "--include-json",
47
146
  is_flag=True,
48
- help="Include the JSON representation of the Workflow in the pull response. Should only be used for debugging purposes.",
147
+ help="""Include the JSON representation of the Workflow in the pull response. \
148
+ Should only be used for debugging purposes.""",
49
149
  )
50
150
  @click.option("--workflow-sandbox-id", type=str, help="Pull the Workflow from a specific Sandbox ID")
51
151
  @click.option(
52
152
  "--exclude-code",
53
153
  is_flag=True,
54
- help="Exclude the code definition of the Workflow from the pull response. Should only be used for debugging purposes.",
154
+ help="""Exclude the code definition of the Workflow from the pull response. \
155
+ Should only be used for debugging purposes.""",
55
156
  )
56
- def pull(
157
+ def workflows_pull(
57
158
  module: Optional[str],
58
159
  include_json: Optional[bool],
59
160
  workflow_sandbox_id: Optional[str],
60
161
  exclude_code: Optional[bool],
61
162
  ) -> None:
62
- """Pull Workflow from Vellum"""
163
+ """
164
+ Pull Workflows from Vellum. If a module is provided, only the Workflow for that module will be pulled.
165
+ If no module is provided, the first configured Workflow will be pulled.
166
+ """
167
+
63
168
  pull_command(
64
169
  module=module,
65
170
  include_json=include_json,
@@ -68,6 +173,35 @@ def pull(
68
173
  )
69
174
 
70
175
 
176
+ @pull.command(name="*")
177
+ @click.pass_context
178
+ @click.option(
179
+ "--include-json",
180
+ is_flag=True,
181
+ help="""Include the JSON representation of the Resource in the pull response. \
182
+ Should only be used for debugging purposes.""",
183
+ )
184
+ @click.option(
185
+ "--exclude-code",
186
+ is_flag=True,
187
+ help="""Exclude the code definition of the Resource from the pull response. \
188
+ Should only be used for debugging purposes.""",
189
+ )
190
+ def pull_module(
191
+ ctx: click.Context,
192
+ include_json: Optional[bool],
193
+ exclude_code: Optional[bool],
194
+ ) -> None:
195
+ """Pull a specific module from Vellum"""
196
+
197
+ if ctx.parent:
198
+ pull_command(
199
+ module=ctx.parent.invoked_subcommand,
200
+ include_json=include_json,
201
+ exclude_code=exclude_code,
202
+ )
203
+
204
+
71
205
  @main.group(aliases=["images", "image"])
72
206
  def images() -> None:
73
207
  """Vellum Docker Images"""
vellum_cli/config.py CHANGED
@@ -7,7 +7,6 @@ from typing import Dict, List, Literal, Optional, Union
7
7
  import tomli
8
8
 
9
9
  from vellum.core.pydantic_utilities import UniversalBaseModel
10
-
11
10
  from vellum.workflows.state.encoder import DefaultStateEncoder
12
11
 
13
12
  LOCKFILE_PATH = "vellum.lock.json"
vellum_cli/image_push.py CHANGED
@@ -7,8 +7,8 @@ import docker
7
7
  from docker import DockerClient
8
8
  from dotenv import load_dotenv
9
9
 
10
- from vellum_cli.logger import load_cli_logger
11
10
  from vellum.workflows.vellum_client import create_vellum_client
11
+ from vellum_cli.logger import load_cli_logger
12
12
 
13
13
  _SUPPORTED_ARCHITECTURE = "amd64"
14
14
 
vellum_cli/pull.py CHANGED
@@ -7,10 +7,30 @@ from typing import Optional
7
7
  from dotenv import load_dotenv
8
8
 
9
9
  from vellum.workflows.vellum_client import create_vellum_client
10
- from vellum_cli.config import WorkflowConfig, load_vellum_cli_config
10
+ from vellum_cli.config import VellumCliConfig, WorkflowConfig, load_vellum_cli_config
11
11
  from vellum_cli.logger import load_cli_logger
12
12
 
13
13
 
14
+ def resolve_workflow_config(
15
+ config: VellumCliConfig,
16
+ module: Optional[str] = None,
17
+ workflow_sandbox_id: Optional[str] = None,
18
+ ) -> Optional[WorkflowConfig]:
19
+ if module:
20
+ return next((w for w in config.workflows if w.module == module), None)
21
+ elif workflow_sandbox_id:
22
+ workflow_config = WorkflowConfig(
23
+ workflow_sandbox_id=workflow_sandbox_id,
24
+ module=f"workflow_{workflow_sandbox_id.split('-')[0]}",
25
+ )
26
+ config.workflows.append(workflow_config)
27
+ return workflow_config
28
+ elif config.workflows:
29
+ return config.workflows[0]
30
+
31
+ return None
32
+
33
+
14
34
  def pull_command(
15
35
  module: Optional[str] = None,
16
36
  workflow_sandbox_id: Optional[str] = None,
@@ -21,24 +41,15 @@ def pull_command(
21
41
  logger = load_cli_logger()
22
42
  config = load_vellum_cli_config()
23
43
 
24
- workflow_config = (
25
- next((w for w in config.workflows if w.module == module), None)
26
- if module
27
- else (config.workflows[0] if config.workflows else None)
44
+ workflow_config = resolve_workflow_config(
45
+ config,
46
+ module,
47
+ workflow_sandbox_id,
28
48
  )
29
- save_lock_file = False
30
- if workflow_config is None:
31
- if module:
32
- raise ValueError(f"No workflow config for '{module}' found in project to pull.")
33
- elif workflow_sandbox_id:
34
- workflow_config = WorkflowConfig(
35
- workflow_sandbox_id=workflow_sandbox_id,
36
- module=f"workflow_{workflow_sandbox_id.split('-')[0]}",
37
- )
38
- config.workflows.append(workflow_config)
39
- save_lock_file = True
40
- else:
41
- raise ValueError("No workflow config found in project to pull from.")
49
+ save_lock_file = not module
50
+
51
+ if not workflow_config:
52
+ raise ValueError("No workflow config found in project to pull from.")
42
53
 
43
54
  if not workflow_config.workflow_sandbox_id:
44
55
  raise ValueError("No workflow sandbox ID found in project to pull from.")
@@ -92,7 +103,8 @@ def pull_command(
92
103
 
93
104
  if include_json:
94
105
  logger.warning(
95
- "The pulled JSON representation of the Workflow should be used for debugging purposely only. Its schema should be considered unstable and subject to change at any time."
106
+ """The pulled JSON representation of the Workflow should be used for debugging purposely only. \
107
+ Its schema should be considered unstable and subject to change at any time."""
96
108
  )
97
109
 
98
110
  if save_lock_file:
vellum_cli/push.py CHANGED
@@ -10,23 +10,22 @@ from dotenv import load_dotenv
10
10
 
11
11
  from vellum.resources.workflows.client import OMIT
12
12
  from vellum.types import WorkflowPushDeploymentConfigRequest
13
-
13
+ from vellum.workflows.utils.names import snake_to_title_case
14
+ from vellum.workflows.vellum_client import create_vellum_client
15
+ from vellum.workflows.workflows.base import BaseWorkflow
14
16
  from vellum_cli.config import WorkflowDeploymentConfig, load_vellum_cli_config
15
17
  from vellum_cli.logger import load_cli_logger
16
18
  from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
17
19
  from vellum_ee.workflows.display.workflows.vellum_workflow_display import VellumWorkflowDisplay
18
- from vellum.workflows.utils.names import snake_to_title_case
19
- from vellum.workflows.vellum_client import create_vellum_client
20
- from vellum.workflows.workflows.base import BaseWorkflow
21
20
 
22
21
 
23
22
  def push_command(
24
- module: Optional[str],
25
- deploy: Optional[bool],
26
- deployment_label: Optional[str],
27
- deployment_name: Optional[str],
28
- deployment_description: Optional[str],
29
- release_tags: Optional[List[str]],
23
+ module: Optional[str] = None,
24
+ deploy: Optional[bool] = None,
25
+ deployment_label: Optional[str] = None,
26
+ deployment_name: Optional[str] = None,
27
+ deployment_description: Optional[str] = None,
28
+ release_tags: Optional[List[str]] = None,
30
29
  ) -> None:
31
30
  load_dotenv()
32
31
  logger = load_cli_logger()
File without changes
@@ -0,0 +1,40 @@
1
+ import pytest
2
+ import os
3
+ import shutil
4
+ import tempfile
5
+ from uuid import uuid4
6
+ from typing import Any, Callable, Dict, Generator, Tuple
7
+
8
+ import tomli_w
9
+
10
+
11
+ @pytest.fixture
12
+ def mock_module() -> Generator[Tuple[str, str, Callable[[Dict[str, Any]], None]], None, None]:
13
+ current_dir = os.getcwd()
14
+ temp_dir = tempfile.mkdtemp()
15
+ os.chdir(temp_dir)
16
+ module = "examples.mock"
17
+
18
+ def set_pyproject_toml(vellum_config: Dict[str, Any]) -> None:
19
+ pyproject_toml_path = os.path.join(temp_dir, "pyproject.toml")
20
+ with open(pyproject_toml_path, "wb") as f:
21
+ tomli_w.dump(
22
+ {"tool": {"vellum": vellum_config}},
23
+ f,
24
+ )
25
+
26
+ set_pyproject_toml(
27
+ {
28
+ "workflows": [
29
+ {
30
+ "module": module,
31
+ "workflow_sandbox_id": str(uuid4()),
32
+ }
33
+ ]
34
+ }
35
+ )
36
+
37
+ yield temp_dir, module, set_pyproject_toml
38
+
39
+ os.chdir(current_dir)
40
+ shutil.rmtree(temp_dir)
@@ -0,0 +1,11 @@
1
+ import subprocess
2
+
3
+
4
+ def test_cli__root():
5
+ """
6
+ A test sanity ensuring that the CLI is accessible
7
+ """
8
+
9
+ result = subprocess.run(["vellum", "--help"], capture_output=True)
10
+ assert result.returncode == 0
11
+ assert result.stdout.startswith(b"Usage: vellum")