vellum-ai 0.11.8__py3-none-any.whl → 0.11.9__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,7 +17,7 @@ class BaseClientWrapper:
17
17
  headers: typing.Dict[str, str] = {
18
18
  "X-Fern-Language": "Python",
19
19
  "X-Fern-SDK-Name": "vellum-ai",
20
- "X-Fern-SDK-Version": "0.11.8",
20
+ "X-Fern-SDK-Version": "0.11.9",
21
21
  }
22
22
  headers["X_API_KEY"] = self.api_key
23
23
  return headers
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.11.8
3
+ Version: 0.11.9
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -1,17 +1,17 @@
1
1
  vellum_cli/CONTRIBUTING.md,sha256=FtDC7BGxSeMnwCXAUssFsAIElXtmJE-O5Z7BpolcgvI,2935
2
2
  vellum_cli/README.md,sha256=2NudRoLzWxNKqnuVy1JuQ7DerIaxWGYkrH8kMd-asIE,90
3
- vellum_cli/__init__.py,sha256=pftUQ6FiyfebNEB8xcfwzLjpfFDCAiH15xHBU6xr_wY,6733
3
+ vellum_cli/__init__.py,sha256=XG6aC1NSPfBjNFzqiy9Lbk4DnELCKO8lpIZ3jeJR0r0,6990
4
4
  vellum_cli/aliased_group.py,sha256=ugW498j0yv4ALJ8vS9MsO7ctDW7Jlir9j6nE_uHAP8c,3363
5
5
  vellum_cli/config.py,sha256=wJQnv3tCgu1BOugg0AOP94yQ-x1yAg8juX_QoFN9Y7w,5223
6
6
  vellum_cli/image_push.py,sha256=SJwhwWJsLjwGNezNVd_oCVpFMfPsAB3dfLWmriZZUtw,4419
7
7
  vellum_cli/logger.py,sha256=PuRFa0WCh4sAGFS5aqWB0QIYpS6nBWwPJrIXpWxugV4,1022
8
- vellum_cli/pull.py,sha256=6wIiorqSx2rmR6atZJHHBuLSviocxK_n0DQxEDGmCzo,4008
8
+ vellum_cli/pull.py,sha256=EkQirsTe0KCpJ8oHTE3S9_M2XHSrb2wrXNq4hTkMZng,5770
9
9
  vellum_cli/push.py,sha256=kbvlzZ9KnkS5DxxKHQP5ZvHHk1-CbCDg9LqnIRAWyt4,5258
10
10
  vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  vellum_cli/tests/conftest.py,sha256=eFGwBxib3Nki830lIFintB0b6r4x8T_KMnmzhlTY5x0,1337
12
12
  vellum_cli/tests/test_config.py,sha256=uvKGDc8BoVyT9_H0Z-g8469zVxomn6Oi3Zj-vK7O_wU,2631
13
13
  vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
14
- vellum_cli/tests/test_pull.py,sha256=N6ZphvHYGokclbpbTpgOmpu_m2GtocDEesbdeHFjO5Y,13194
14
+ vellum_cli/tests/test_pull.py,sha256=pGqpBkahC360UITDE8BlcJ7LPd9DyRPn4NrCNdkQmAQ,15907
15
15
  vellum_cli/tests/test_push.py,sha256=V2iGcskh2X3OHj2uV5Vx_BhmtyfmUkyx0lrp8DDOExc,5824
16
16
  vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -79,7 +79,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
79
79
  vellum/client/__init__.py,sha256=o4m7iRZWEV8rP3GkdaztHAjNmjxjWERlarviFoHzuKI,110927
80
80
  vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
81
81
  vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
82
- vellum/client/core/client_wrapper.py,sha256=KtxhfH7jJZXfEPTJ_JeglwXX43TbY0JGd81hjEJN-Gw,1890
82
+ vellum/client/core/client_wrapper.py,sha256=7ETrjiHmBNoSjt9dOpoOQoV1KfdagFOllIIAwyOIi8U,1890
83
83
  vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
84
84
  vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
85
85
  vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
@@ -1378,8 +1378,8 @@ vellum/workflows/vellum_client.py,sha256=ODrq_TSl-drX2aezXegf7pizpWDVJuTXH-j6528
1378
1378
  vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
1379
1379
  vellum/workflows/workflows/base.py,sha256=mnI-kZ78yt7u6NFSTUo-tYjDnarP-RJ7uZjwjCn6PCQ,16795
1380
1380
  vellum/workflows/workflows/event_filters.py,sha256=-uQcMB7IpPd-idMku8f2QNVhPXPFWo6FZLlGjRf8rCo,1996
1381
- vellum_ai-0.11.8.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1382
- vellum_ai-0.11.8.dist-info/METADATA,sha256=7H-xm-0FDR9QYaVdqlM8w4rVbWfsK9-0osBbv0npgWk,5128
1383
- vellum_ai-0.11.8.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
1384
- vellum_ai-0.11.8.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1385
- vellum_ai-0.11.8.dist-info/RECORD,,
1381
+ vellum_ai-0.11.9.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1382
+ vellum_ai-0.11.9.dist-info/METADATA,sha256=mbIOikcPuEIU344kVitGc9qdEQCbVQn5_-GrKT7XgdI,5128
1383
+ vellum_ai-0.11.9.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
1384
+ vellum_ai-0.11.9.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1385
+ vellum_ai-0.11.9.dist-info/RECORD,,
vellum_cli/__init__.py CHANGED
@@ -148,6 +148,11 @@ def pull(
148
148
  Should only be used for debugging purposes.""",
149
149
  )
150
150
  @click.option("--workflow-sandbox-id", type=str, help="Pull the Workflow from a specific Sandbox ID")
151
+ @click.option(
152
+ "--workflow-deployment",
153
+ type=str,
154
+ help="""Pull the Workflow from a specific Deployment. Can use the name or the ID of the Deployment.""",
155
+ )
151
156
  @click.option(
152
157
  "--exclude-code",
153
158
  is_flag=True,
@@ -158,6 +163,7 @@ def workflows_pull(
158
163
  module: Optional[str],
159
164
  include_json: Optional[bool],
160
165
  workflow_sandbox_id: Optional[str],
166
+ workflow_deployment: Optional[str],
161
167
  exclude_code: Optional[bool],
162
168
  ) -> None:
163
169
  """
@@ -169,6 +175,7 @@ def workflows_pull(
169
175
  module=module,
170
176
  include_json=include_json,
171
177
  workflow_sandbox_id=workflow_sandbox_id,
178
+ workflow_deployment=workflow_deployment,
172
179
  exclude_code=exclude_code,
173
180
  )
174
181
 
vellum_cli/pull.py CHANGED
@@ -1,39 +1,84 @@
1
1
  import io
2
2
  import os
3
3
  from pathlib import Path
4
+ from uuid import UUID
4
5
  import zipfile
5
- from typing import Optional
6
+ from typing import Optional, Union
6
7
 
7
8
  from dotenv import load_dotenv
9
+ from pydash import snake_case
8
10
 
11
+ from vellum.client.core.pydantic_utilities import UniversalBaseModel
9
12
  from vellum.workflows.vellum_client import create_vellum_client
10
13
  from vellum_cli.config import VellumCliConfig, WorkflowConfig, load_vellum_cli_config
11
14
  from vellum_cli.logger import load_cli_logger
12
15
 
13
16
 
14
- def resolve_workflow_config(
17
+ def _is_valid_uuid(val: Union[str, UUID, None]) -> bool:
18
+ try:
19
+ UUID(str(val))
20
+ return True
21
+ except (ValueError, TypeError):
22
+ return False
23
+
24
+
25
+ class WorkflowConfigResolutionResult(UniversalBaseModel):
26
+ workflow_config: Optional[WorkflowConfig] = None
27
+ pk: Optional[str] = None
28
+
29
+
30
+ def _resolve_workflow_config(
15
31
  config: VellumCliConfig,
16
32
  module: Optional[str] = None,
17
33
  workflow_sandbox_id: Optional[str] = None,
18
- ) -> Optional[WorkflowConfig]:
34
+ workflow_deployment: Optional[str] = None,
35
+ ) -> WorkflowConfigResolutionResult:
36
+ if workflow_sandbox_id and workflow_deployment:
37
+ raise ValueError("Cannot specify both workflow_sandbox_id and workflow_deployment")
38
+
19
39
  if module:
20
- return next((w for w in config.workflows if w.module == module), None)
40
+ workflow_config = next((w for w in config.workflows if w.module == module), None)
41
+ return WorkflowConfigResolutionResult(
42
+ workflow_config=workflow_config,
43
+ pk=workflow_config.workflow_sandbox_id if workflow_config else None,
44
+ )
21
45
  elif workflow_sandbox_id:
22
46
  workflow_config = WorkflowConfig(
23
47
  workflow_sandbox_id=workflow_sandbox_id,
24
48
  module=f"workflow_{workflow_sandbox_id.split('-')[0]}",
25
49
  )
26
50
  config.workflows.append(workflow_config)
27
- return workflow_config
51
+ return WorkflowConfigResolutionResult(
52
+ workflow_config=workflow_config,
53
+ pk=workflow_config.workflow_sandbox_id,
54
+ )
55
+ elif workflow_deployment:
56
+ module = (
57
+ f"workflow_{workflow_deployment.split('-')[0]}"
58
+ if _is_valid_uuid(workflow_deployment)
59
+ else snake_case(workflow_deployment)
60
+ )
61
+ workflow_config = WorkflowConfig(
62
+ module=module,
63
+ )
64
+ config.workflows.append(workflow_config)
65
+ return WorkflowConfigResolutionResult(
66
+ workflow_config=workflow_config,
67
+ pk=workflow_deployment,
68
+ )
28
69
  elif config.workflows:
29
- return config.workflows[0]
70
+ return WorkflowConfigResolutionResult(
71
+ workflow_config=config.workflows[0],
72
+ pk=config.workflows[0].workflow_sandbox_id,
73
+ )
30
74
 
31
- return None
75
+ return WorkflowConfigResolutionResult()
32
76
 
33
77
 
34
78
  def pull_command(
35
79
  module: Optional[str] = None,
36
80
  workflow_sandbox_id: Optional[str] = None,
81
+ workflow_deployment: Optional[str] = None,
37
82
  include_json: Optional[bool] = None,
38
83
  exclude_code: Optional[bool] = None,
39
84
  ) -> None:
@@ -41,17 +86,20 @@ def pull_command(
41
86
  logger = load_cli_logger()
42
87
  config = load_vellum_cli_config()
43
88
 
44
- workflow_config = resolve_workflow_config(
45
- config,
46
- module,
47
- workflow_sandbox_id,
89
+ workflow_config_result = _resolve_workflow_config(
90
+ config=config,
91
+ module=module,
92
+ workflow_sandbox_id=workflow_sandbox_id,
93
+ workflow_deployment=workflow_deployment,
48
94
  )
49
95
  save_lock_file = not module
50
96
 
97
+ workflow_config = workflow_config_result.workflow_config
51
98
  if not workflow_config:
52
99
  raise ValueError("No workflow config found in project to pull from.")
53
100
 
54
- if not workflow_config.workflow_sandbox_id:
101
+ pk = workflow_config_result.pk
102
+ if not pk:
55
103
  raise ValueError("No workflow sandbox ID found in project to pull from.")
56
104
 
57
105
  logger.info(f"Pulling workflow into {workflow_config.module}")
@@ -63,7 +111,7 @@ def pull_command(
63
111
  query_parameters["exclude_code"] = exclude_code
64
112
 
65
113
  response = client.workflows.pull(
66
- workflow_config.workflow_sandbox_id,
114
+ pk,
67
115
  request_options={"additional_query_parameters": query_parameters},
68
116
  )
69
117
 
@@ -164,6 +164,86 @@ def test_pull__sandbox_id_with_other_workflow_configured(vellum_client, mock_mod
164
164
  assert f.read() == "print('hello')"
165
165
 
166
166
 
167
+ def test_pull__workflow_deployment_with_no_config(vellum_client):
168
+ # GIVEN a workflow deployment
169
+ workflow_deployment = "my-deployment"
170
+
171
+ # AND the workflow pull API call returns a zip file
172
+ vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
173
+
174
+ # AND we are currently in a new directory
175
+ current_dir = os.getcwd()
176
+ temp_dir = tempfile.mkdtemp()
177
+ os.chdir(temp_dir)
178
+
179
+ # WHEN the user runs the pull command with the workflow deployment
180
+ runner = CliRunner()
181
+ result = runner.invoke(cli_main, ["workflows", "pull", "--workflow-deployment", workflow_deployment])
182
+ os.chdir(current_dir)
183
+
184
+ # THEN the command returns successfully
185
+ assert result.exit_code == 0
186
+
187
+ # AND the pull api is called with the workflow deployment
188
+ vellum_client.workflows.pull.assert_called_once()
189
+ workflow_py = os.path.join(temp_dir, "my_deployment", "workflow.py")
190
+ assert os.path.exists(workflow_py)
191
+ with open(workflow_py) as f:
192
+ assert f.read() == "print('hello')"
193
+
194
+ # AND the vellum.lock.json file is created
195
+ vellum_lock_json = os.path.join(temp_dir, "vellum.lock.json")
196
+ assert os.path.exists(vellum_lock_json)
197
+ with open(vellum_lock_json) as f:
198
+ lock_data = json.loads(f.read())
199
+ assert lock_data == {
200
+ "version": "1.0",
201
+ "workflows": [
202
+ {
203
+ "module": "my_deployment",
204
+ "workflow_sandbox_id": None,
205
+ "ignore": None,
206
+ "deployments": [],
207
+ }
208
+ ],
209
+ }
210
+
211
+
212
+ def test_pull__both_workflow_sandbox_id_and_deployment(vellum_client):
213
+ # GIVEN a workflow sandbox id
214
+ workflow_sandbox_id = "87654321-0000-0000-0000-000000000000"
215
+
216
+ # AND a workflow deployment
217
+ workflow_deployment = "my-deployment"
218
+
219
+ # AND the workflow pull API call returns a zip file
220
+ vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
221
+
222
+ # AND we are currently in a new directory
223
+ current_dir = os.getcwd()
224
+ temp_dir = tempfile.mkdtemp()
225
+ os.chdir(temp_dir)
226
+
227
+ # WHEN the user runs the pull command with the workflow deployment
228
+ runner = CliRunner()
229
+ result = runner.invoke(
230
+ cli_main,
231
+ [
232
+ "workflows",
233
+ "pull",
234
+ "--workflow-sandbox-id",
235
+ workflow_sandbox_id,
236
+ "--workflow-deployment",
237
+ workflow_deployment,
238
+ ],
239
+ )
240
+ os.chdir(current_dir)
241
+
242
+ # THEN the command returns successfully
243
+ assert result.exit_code == 1
244
+ assert "Cannot specify both workflow_sandbox_id and workflow_deployment" == str(result.exception)
245
+
246
+
167
247
  def test_pull__remove_missing_files(vellum_client, mock_module):
168
248
  # GIVEN a module on the user's filesystem
169
249
  temp_dir = mock_module.temp_dir