validio-cli 0.24.1__tar.gz → 0.25.1__tar.gz
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.
- {validio_cli-0.24.1 → validio_cli-0.25.1}/PKG-INFO +2 -2
- {validio_cli-0.24.1 → validio_cli-0.25.1}/pyproject.toml +2 -2
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/code.py +30 -18
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/sources.py +85 -55
- {validio_cli-0.24.1 → validio_cli-0.25.1}/LICENSE +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/README_PUBLIC.md +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/__init__.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/channels.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/config.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/credentials.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/dbt.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/filters.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/incidents.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/metrics.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/namespaces.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/notification_rules.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/recommendations.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/resources.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/segmentations.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/segments.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/users.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/validators.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/entities/windows.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/bin/main.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/components.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/metadata.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/namespace.py +0 -0
- {validio_cli-0.24.1 → validio_cli-0.25.1}/validio_cli/schema.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: validio-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.1
|
|
4
4
|
Summary: CLI tool to interact with the Validio platform
|
|
5
5
|
Home-page: https://validio.io/
|
|
6
6
|
License: Apache-2.0
|
|
@@ -16,7 +16,7 @@ Requires-Dist: classdiff (>=0.5.0,<0.6.0)
|
|
|
16
16
|
Requires-Dist: prompt-toolkit (>=3.0.38,<4.0.0)
|
|
17
17
|
Requires-Dist: pydantic (==2.4.2)
|
|
18
18
|
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
|
19
|
-
Requires-Dist: typer[all] (>=0.
|
|
19
|
+
Requires-Dist: typer[all] (>=0.8.0,<0.9.0)
|
|
20
20
|
Requires-Dist: types-tabulate (>=0.9.0.2,<0.10.0.0)
|
|
21
21
|
Requires-Dist: validio-sdk
|
|
22
22
|
Project-URL: Documentation, https://docs.validio.io/
|
|
@@ -3,7 +3,7 @@ name = "validio-cli"
|
|
|
3
3
|
# This version does not represent the released version or any tag. For each
|
|
4
4
|
# release we automatically bump this before building and publishing so this
|
|
5
5
|
# should be kept at 0.0.1dev1
|
|
6
|
-
version = "0.
|
|
6
|
+
version = "0.25.1"
|
|
7
7
|
description = "CLI tool to interact with the Validio platform"
|
|
8
8
|
authors = ["Validio <support@validio.io>"]
|
|
9
9
|
license = "Apache-2.0"
|
|
@@ -16,7 +16,7 @@ readme = "README_PUBLIC.md"
|
|
|
16
16
|
python = "^3.10"
|
|
17
17
|
camel-converter = "^3.0.0"
|
|
18
18
|
classdiff = "^0.5.0"
|
|
19
|
-
typer = { extras = ["all"], version = "^0.
|
|
19
|
+
typer = { extras = ["all"], version = "^0.8.0" }
|
|
20
20
|
prompt-toolkit = "^3.0.38"
|
|
21
21
|
tabulate = "^0.9.0"
|
|
22
22
|
types-tabulate = "^0.9.0.2"
|
|
@@ -7,7 +7,6 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
import classdiff # type: ignore
|
|
9
9
|
import typer
|
|
10
|
-
from validio_sdk import ValidioError
|
|
11
10
|
from validio_sdk._api.api import APIClient
|
|
12
11
|
from validio_sdk.code import _import as code_import
|
|
13
12
|
from validio_sdk.code import apply as code_apply
|
|
@@ -99,6 +98,15 @@ update_all_schemas_option = typer.Option(
|
|
|
99
98
|
),
|
|
100
99
|
)
|
|
101
100
|
|
|
101
|
+
show_progress_option = typer.Option(
|
|
102
|
+
True,
|
|
103
|
+
help=(
|
|
104
|
+
f"{BETA_BANNER} "
|
|
105
|
+
"If enabled, progress updates will be displayed during "
|
|
106
|
+
"execution of this command"
|
|
107
|
+
),
|
|
108
|
+
)
|
|
109
|
+
|
|
102
110
|
|
|
103
111
|
def target_option(resource_type: str) -> Any:
|
|
104
112
|
return typer.Option(
|
|
@@ -145,6 +153,7 @@ async def plan(
|
|
|
145
153
|
source: list[str] = target_option("source"),
|
|
146
154
|
validator: list[str] = target_option("validator"),
|
|
147
155
|
window: list[str] = target_option("window"),
|
|
156
|
+
progress: bool = show_progress_option,
|
|
148
157
|
) -> None:
|
|
149
158
|
dir_path = directory_or_default(directory)
|
|
150
159
|
client, _ = get_client(config_dir)
|
|
@@ -174,6 +183,7 @@ async def plan(
|
|
|
174
183
|
validators=set(validator),
|
|
175
184
|
windows=set(window),
|
|
176
185
|
),
|
|
186
|
+
show_progress=progress,
|
|
177
187
|
)
|
|
178
188
|
|
|
179
189
|
|
|
@@ -199,6 +209,7 @@ async def apply(
|
|
|
199
209
|
source: list[str] = target_option("source"),
|
|
200
210
|
validator: list[str] = target_option("validator"),
|
|
201
211
|
window: list[str] = target_option("window"),
|
|
212
|
+
progress: bool = show_progress_option,
|
|
202
213
|
) -> None:
|
|
203
214
|
dir_path = directory_or_default(directory)
|
|
204
215
|
client, _ = get_client(config_dir)
|
|
@@ -208,7 +219,7 @@ async def apply(
|
|
|
208
219
|
)
|
|
209
220
|
|
|
210
221
|
namespace = get_namespace(dir_path)
|
|
211
|
-
|
|
222
|
+
plan_result = await _plan(
|
|
212
223
|
namespace=namespace,
|
|
213
224
|
client=client,
|
|
214
225
|
directory=dir_path,
|
|
@@ -228,8 +239,10 @@ async def apply(
|
|
|
228
239
|
validators=set(validator),
|
|
229
240
|
windows=set(window),
|
|
230
241
|
),
|
|
242
|
+
show_progress=progress,
|
|
231
243
|
)
|
|
232
244
|
|
|
245
|
+
diff = plan_result.graph_diff
|
|
233
246
|
if diff.num_operations() == 0:
|
|
234
247
|
return
|
|
235
248
|
|
|
@@ -242,9 +255,10 @@ async def apply(
|
|
|
242
255
|
await code_apply.apply(
|
|
243
256
|
namespace=namespace,
|
|
244
257
|
client=client,
|
|
245
|
-
ctx=
|
|
258
|
+
ctx=plan_result.diff_context,
|
|
246
259
|
diff=diff,
|
|
247
260
|
show_secrets=show_secrets,
|
|
261
|
+
show_progress=progress,
|
|
248
262
|
)
|
|
249
263
|
|
|
250
264
|
print(
|
|
@@ -302,11 +316,6 @@ async def _import(
|
|
|
302
316
|
credentials=set(credential), channels=set(channel)
|
|
303
317
|
)
|
|
304
318
|
|
|
305
|
-
if resource_names.is_empty() and import_namespace is None:
|
|
306
|
-
raise ValidioError(
|
|
307
|
-
"--import-namespace is required when targeting resources to move"
|
|
308
|
-
)
|
|
309
|
-
|
|
310
319
|
dir_path = directory_or_default(directory)
|
|
311
320
|
client, _ = get_client(config_dir)
|
|
312
321
|
namespace = get_namespace(dir_path)
|
|
@@ -325,7 +334,7 @@ async def _import(
|
|
|
325
334
|
if num_moved_resources > 0:
|
|
326
335
|
print(f"Moved {num_moved_resources} resources")
|
|
327
336
|
|
|
328
|
-
|
|
337
|
+
plan_result = await _plan(
|
|
329
338
|
namespace=namespace,
|
|
330
339
|
client=client,
|
|
331
340
|
directory=dir_path,
|
|
@@ -339,11 +348,14 @@ async def _import(
|
|
|
339
348
|
import_mode=True,
|
|
340
349
|
)
|
|
341
350
|
|
|
342
|
-
if
|
|
351
|
+
if plan_result.graph_diff.num_deletes() == 0:
|
|
343
352
|
_print_no_changes()
|
|
344
353
|
return
|
|
345
354
|
|
|
346
|
-
s = await code_import._import(
|
|
355
|
+
s = await code_import._import(
|
|
356
|
+
ctx=plan_result.graph_diff.to_delete,
|
|
357
|
+
tags_ctx=plan_result.tags_context,
|
|
358
|
+
)
|
|
347
359
|
output.write_text(s)
|
|
348
360
|
print(f"Generated file {output.absolute()}")
|
|
349
361
|
|
|
@@ -371,7 +383,8 @@ async def _plan(
|
|
|
371
383
|
show_diff: bool = True,
|
|
372
384
|
targets: code_plan.ResourceNames = code_plan.ResourceNames(),
|
|
373
385
|
import_mode: bool = False,
|
|
374
|
-
|
|
386
|
+
show_progress: bool = True,
|
|
387
|
+
) -> code_plan.PlanResult:
|
|
375
388
|
plan_result = await code_plan.plan(
|
|
376
389
|
namespace=namespace,
|
|
377
390
|
client=client,
|
|
@@ -382,16 +395,15 @@ async def _plan(
|
|
|
382
395
|
show_secrets=show_secrets,
|
|
383
396
|
targets=targets,
|
|
384
397
|
import_mode=import_mode,
|
|
398
|
+
show_progress=show_progress,
|
|
385
399
|
)
|
|
386
400
|
|
|
387
|
-
diff, manifest_ctx = plan_result.graph_diff, plan_result.diff_context
|
|
388
|
-
|
|
389
401
|
if show_diff:
|
|
390
|
-
if
|
|
402
|
+
if plan_result.graph_diff.num_operations() == 0:
|
|
391
403
|
_print_no_changes()
|
|
392
404
|
else:
|
|
393
405
|
_show_resources_diff(
|
|
394
|
-
diff=
|
|
406
|
+
diff=plan_result.graph_diff,
|
|
395
407
|
show_schema=show_schema,
|
|
396
408
|
show_secrets=show_secrets,
|
|
397
409
|
escape=sys.stdout.isatty() and color,
|
|
@@ -400,7 +412,7 @@ async def _plan(
|
|
|
400
412
|
|
|
401
413
|
_show_deprecations(plan_result.deprecations)
|
|
402
414
|
|
|
403
|
-
return
|
|
415
|
+
return plan_result
|
|
404
416
|
|
|
405
417
|
|
|
406
418
|
def _show_resources_diff(
|
|
@@ -522,7 +534,7 @@ def _show_update_resource_diff(
|
|
|
522
534
|
if r.replacement_cascaded_update_parent:
|
|
523
535
|
(cls, parent_name) = r.replacement_cascaded_update_parent
|
|
524
536
|
cascade_update = (
|
|
525
|
-
f" (due to replacement of " f"{cls.__name__}({
|
|
537
|
+
f" (due to replacement of " f"{cls.__name__}({parent_name!r}))"
|
|
526
538
|
)
|
|
527
539
|
|
|
528
540
|
print(f"{class_key} '{r.manifest.name}' will be updated{cascade_update}")
|
|
@@ -14,6 +14,7 @@ from validio_sdk._api.api import (
|
|
|
14
14
|
SourceAction,
|
|
15
15
|
apply_source_action,
|
|
16
16
|
get_sources,
|
|
17
|
+
split_to_chunks,
|
|
17
18
|
)
|
|
18
19
|
from validio_sdk.client import Session
|
|
19
20
|
from validio_sdk.config import ValidioConfig
|
|
@@ -36,8 +37,6 @@ from validio_cli import (
|
|
|
36
37
|
from validio_cli.bin.entities import credentials
|
|
37
38
|
from validio_cli.namespace import get_namespace
|
|
38
39
|
|
|
39
|
-
NUM_CONCURRENT_CONNECTIONS = 5
|
|
40
|
-
|
|
41
40
|
app = AsyncTyper(help="Data sources to ingest data from")
|
|
42
41
|
|
|
43
42
|
infer_schema_app = AsyncTyper(help="Infer schema")
|
|
@@ -111,15 +110,16 @@ async def start(
|
|
|
111
110
|
namespace: str = Namespace(),
|
|
112
111
|
identifiers: list[str] = Identifiers,
|
|
113
112
|
) -> None:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
113
|
+
client, cfg = get_client(config_dir)
|
|
114
|
+
async with client.client as session:
|
|
115
|
+
await apply_source_action_on_chunks(
|
|
116
|
+
session,
|
|
117
|
+
cfg,
|
|
118
|
+
SourceAction.START,
|
|
119
|
+
split_to_chunks(identifiers),
|
|
120
|
+
namespace,
|
|
121
|
+
output_format,
|
|
122
|
+
)
|
|
123
123
|
|
|
124
124
|
|
|
125
125
|
@app.async_command(help="Stop source")
|
|
@@ -130,15 +130,16 @@ async def stop(
|
|
|
130
130
|
namespace: str = Namespace(),
|
|
131
131
|
identifiers: list[str] = Identifiers,
|
|
132
132
|
) -> None:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
client, cfg = get_client(config_dir)
|
|
134
|
+
async with client.client as session:
|
|
135
|
+
await apply_source_action_on_chunks(
|
|
136
|
+
session,
|
|
137
|
+
cfg,
|
|
138
|
+
SourceAction.STOP,
|
|
139
|
+
split_to_chunks(identifiers),
|
|
140
|
+
namespace,
|
|
141
|
+
output_format,
|
|
142
|
+
)
|
|
142
143
|
|
|
143
144
|
|
|
144
145
|
@app.async_command(help="Backfill source")
|
|
@@ -149,17 +150,16 @@ async def backfill(
|
|
|
149
150
|
namespace: str = Namespace(),
|
|
150
151
|
identifiers: list[str] = Identifiers,
|
|
151
152
|
) -> None:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return handle_source_action_response(results, SourceAction.BACKFILL, output_format)
|
|
153
|
+
client, cfg = get_client(config_dir)
|
|
154
|
+
async with client.client as session:
|
|
155
|
+
await apply_source_action_on_chunks(
|
|
156
|
+
session,
|
|
157
|
+
cfg,
|
|
158
|
+
SourceAction.BACKFILL,
|
|
159
|
+
split_to_chunks(identifiers),
|
|
160
|
+
namespace,
|
|
161
|
+
output_format,
|
|
162
|
+
)
|
|
163
163
|
|
|
164
164
|
|
|
165
165
|
@app.async_command(help="Reset source")
|
|
@@ -170,15 +170,16 @@ async def reset(
|
|
|
170
170
|
namespace: str = Namespace(),
|
|
171
171
|
identifiers: list[str] = Identifiers,
|
|
172
172
|
) -> None:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
173
|
+
client, cfg = get_client(config_dir)
|
|
174
|
+
async with client.client as session:
|
|
175
|
+
await apply_source_action_on_chunks(
|
|
176
|
+
session,
|
|
177
|
+
cfg,
|
|
178
|
+
SourceAction.RESET,
|
|
179
|
+
split_to_chunks(identifiers),
|
|
180
|
+
namespace,
|
|
181
|
+
output_format,
|
|
182
|
+
)
|
|
182
183
|
|
|
183
184
|
|
|
184
185
|
@infer_schema_app.callback(invoke_without_command=True)
|
|
@@ -1145,8 +1146,11 @@ async def _get_null_marker() -> str | None:
|
|
|
1145
1146
|
return null_marker
|
|
1146
1147
|
|
|
1147
1148
|
|
|
1148
|
-
async def
|
|
1149
|
-
|
|
1149
|
+
async def _get_source_id(
|
|
1150
|
+
session: Session,
|
|
1151
|
+
cfg: ValidioConfig,
|
|
1152
|
+
identifier: str,
|
|
1153
|
+
namespace: str,
|
|
1150
1154
|
) -> str | None:
|
|
1151
1155
|
"""
|
|
1152
1156
|
Ensure the identifier is a resource id.
|
|
@@ -1164,7 +1168,7 @@ async def get_source_id(
|
|
|
1164
1168
|
return identifier
|
|
1165
1169
|
|
|
1166
1170
|
resource = await get_sources(
|
|
1167
|
-
|
|
1171
|
+
session,
|
|
1168
1172
|
source_id=identifier,
|
|
1169
1173
|
namespace_id=get_namespace(namespace, cfg),
|
|
1170
1174
|
)
|
|
@@ -1179,6 +1183,16 @@ async def get_source_id(
|
|
|
1179
1183
|
return resource["id"]
|
|
1180
1184
|
|
|
1181
1185
|
|
|
1186
|
+
async def get_source_id(
|
|
1187
|
+
client: APIClient,
|
|
1188
|
+
cfg: ValidioConfig,
|
|
1189
|
+
identifier: str,
|
|
1190
|
+
namespace: str,
|
|
1191
|
+
) -> str | None:
|
|
1192
|
+
async with client.client as session:
|
|
1193
|
+
return await _get_source_id(session, cfg, identifier, namespace)
|
|
1194
|
+
|
|
1195
|
+
|
|
1182
1196
|
def _resource_filter(
|
|
1183
1197
|
source: Any, credential_id: str | None, credential_name: str | None
|
|
1184
1198
|
) -> bool:
|
|
@@ -1234,15 +1248,35 @@ def _interactive_message_format_input() -> tuple[str, list[str], str]:
|
|
|
1234
1248
|
)
|
|
1235
1249
|
|
|
1236
1250
|
|
|
1251
|
+
async def apply_source_action_on_chunks(
|
|
1252
|
+
session: Session,
|
|
1253
|
+
cfg: ValidioConfig,
|
|
1254
|
+
action: SourceAction,
|
|
1255
|
+
chunks: list[list[str]],
|
|
1256
|
+
namespace: str,
|
|
1257
|
+
output_format: OutputFormat = OutputFormatOption,
|
|
1258
|
+
) -> None:
|
|
1259
|
+
results = await asyncio.gather(
|
|
1260
|
+
*[
|
|
1261
|
+
apply_batch_source_action(session, cfg, action, chunk, namespace)
|
|
1262
|
+
for chunk in chunks
|
|
1263
|
+
]
|
|
1264
|
+
)
|
|
1265
|
+
|
|
1266
|
+
return handle_source_action_response(results, action, output_format)
|
|
1267
|
+
|
|
1268
|
+
|
|
1237
1269
|
async def apply_batch_source_action(
|
|
1238
|
-
|
|
1270
|
+
session: Session,
|
|
1271
|
+
cfg: ValidioConfig,
|
|
1272
|
+
action: SourceAction,
|
|
1273
|
+
identifiers: list[str],
|
|
1274
|
+
namespace: str,
|
|
1239
1275
|
) -> list[dict[str, Any]]:
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
for id in identifiers
|
|
1245
|
-
]
|
|
1276
|
+
return [
|
|
1277
|
+
await apply_single_source_action(session, action, cfg, id, namespace)
|
|
1278
|
+
for id in identifiers
|
|
1279
|
+
]
|
|
1246
1280
|
|
|
1247
1281
|
|
|
1248
1282
|
async def apply_single_source_action(
|
|
@@ -1252,7 +1286,7 @@ async def apply_single_source_action(
|
|
|
1252
1286
|
identifier: str,
|
|
1253
1287
|
namespace: str,
|
|
1254
1288
|
) -> dict[str, Any]:
|
|
1255
|
-
source_id = await
|
|
1289
|
+
source_id = await _get_source_id(session, cfg, identifier, namespace)
|
|
1256
1290
|
if source_id is None:
|
|
1257
1291
|
return {
|
|
1258
1292
|
f"source{action.value}": {
|
|
@@ -1301,9 +1335,5 @@ def handle_source_action_response(
|
|
|
1301
1335
|
)
|
|
1302
1336
|
|
|
1303
1337
|
|
|
1304
|
-
def split_to_chunks(data: list[Any], num_of_chunks: int) -> list[list[Any]]:
|
|
1305
|
-
return [data[i::num_of_chunks] for i in range(min(num_of_chunks, len(data)))]
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
1338
|
if __name__ == "__main__":
|
|
1309
1339
|
typer.run(app())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|