validio-sdk 7.2.0__tar.gz → 7.4.0__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_sdk-7.2.0 → validio_sdk-7.4.0}/PKG-INFO +1 -1
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/pyproject.toml +1 -1
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/_api/api.py +31 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/_diffable.py +2 -2
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/_serde.py +2 -2
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/_server_resources.py +47 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/channels.py +3 -3
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/credentials.py +237 -12
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/sources.py +72 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tests/test__diff.py +48 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/validators.py +1 -1
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/LICENSE +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/README_PUBLIC.md +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/__init__.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/_api/__init__.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/client/__init__.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/client/client.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/code/__init__.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/code/_import.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/code/_progress.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/code/apply.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/code/plan.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/code/scaffold.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/code/settings.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/config.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/dbt.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/exception.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/metadata.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/py.typed +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/__init__.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/_diff.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/_diff_util.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/_errors.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/_resource.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/_resource_graph.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/_update_namespace.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/_util.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/enums.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/filters.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/notification_rules.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/replacement.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/segmentations.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tags.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tests/__init__.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tests/assets/example_manifest.json +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tests/assets/expected_trimmed_manifest.json +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tests/test__dbt.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tests/test__plan.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tests/test__resource.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tests/test__sql_validation.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tests/test_import.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/thresholds.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/windows.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/scalars.py +0 -0
- {validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/util.py +0 -0
|
@@ -3,7 +3,7 @@ name = "validio-sdk"
|
|
|
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 = "7.
|
|
6
|
+
version = "7.4.0"
|
|
7
7
|
description = "SDK to interact with the Validio platform"
|
|
8
8
|
authors = ["Validio <support@validio.io>"]
|
|
9
9
|
license = "Apache-2.0"
|
|
@@ -553,6 +553,13 @@ async def get_sources(
|
|
|
553
553
|
schedule
|
|
554
554
|
}
|
|
555
555
|
}
|
|
556
|
+
... on TeradataSource {
|
|
557
|
+
config {
|
|
558
|
+
database
|
|
559
|
+
table
|
|
560
|
+
schedule
|
|
561
|
+
}
|
|
562
|
+
}
|
|
556
563
|
}
|
|
557
564
|
"""
|
|
558
565
|
|
|
@@ -962,6 +969,12 @@ async def get_credentials(
|
|
|
962
969
|
baseUrl
|
|
963
970
|
}
|
|
964
971
|
}
|
|
972
|
+
... on AnthropicCredential {
|
|
973
|
+
config {
|
|
974
|
+
model
|
|
975
|
+
optBaseUrl: baseUrl
|
|
976
|
+
}
|
|
977
|
+
}
|
|
965
978
|
... on AwsCredential {
|
|
966
979
|
config {
|
|
967
980
|
accessKey
|
|
@@ -1080,6 +1093,8 @@ async def get_credentials(
|
|
|
1080
1093
|
user
|
|
1081
1094
|
}
|
|
1082
1095
|
}
|
|
1096
|
+
tlsEnabled
|
|
1097
|
+
tlsCaCertificates
|
|
1083
1098
|
}
|
|
1084
1099
|
enableCatalog
|
|
1085
1100
|
}
|
|
@@ -1166,6 +1181,21 @@ async def get_credentials(
|
|
|
1166
1181
|
}
|
|
1167
1182
|
enableCatalog
|
|
1168
1183
|
}
|
|
1184
|
+
... on TeradataCredential {
|
|
1185
|
+
config {
|
|
1186
|
+
host
|
|
1187
|
+
sslMode
|
|
1188
|
+
httpsPort
|
|
1189
|
+
tdmstPort
|
|
1190
|
+
auth {
|
|
1191
|
+
__typename
|
|
1192
|
+
... on TeradataCredentialUserPassword {
|
|
1193
|
+
user
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
enableCatalog
|
|
1198
|
+
}
|
|
1169
1199
|
}
|
|
1170
1200
|
"""
|
|
1171
1201
|
|
|
@@ -1214,6 +1244,7 @@ async def get_credentials(
|
|
|
1214
1244
|
("powerBiAuth", "auth"),
|
|
1215
1245
|
("databaseRequired", "database"),
|
|
1216
1246
|
("optUser", "user"),
|
|
1247
|
+
("optBaseUrl", "baseUrl"),
|
|
1217
1248
|
],
|
|
1218
1249
|
)
|
|
1219
1250
|
result[i] = credential
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
3
|
from collections.abc import Iterator
|
|
4
|
-
from typing import TYPE_CHECKING, Any
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
5
|
|
|
6
6
|
from camel_converter import to_camel
|
|
7
7
|
|
|
@@ -53,7 +53,7 @@ class Diffable(ABC):
|
|
|
53
53
|
@abstractmethod
|
|
54
54
|
def _nested_objects(
|
|
55
55
|
self,
|
|
56
|
-
) -> dict[str,
|
|
56
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
57
57
|
"""Returns any nested objects contained within this object.
|
|
58
58
|
|
|
59
59
|
Nested objects will be diff-ed recursively.
|
|
@@ -389,9 +389,9 @@ def _import_value_repr(
|
|
|
389
389
|
# single long line.
|
|
390
390
|
if "\n" not in value:
|
|
391
391
|
value_repr = repr(value)
|
|
392
|
-
elif "'''"
|
|
392
|
+
elif not any(["'''" in value, value.startswith("'"), value.endswith("'")]):
|
|
393
393
|
value_repr = f"'''{value}'''"
|
|
394
|
-
elif '"""'
|
|
394
|
+
elif not any(['"""' in value, value.startswith('"'), value.endswith('"')]):
|
|
395
395
|
value_repr = f'"""{value}"""'
|
|
396
396
|
else:
|
|
397
397
|
value_repr = repr(value)
|
|
@@ -38,6 +38,9 @@ from validio_sdk.resource.channels import (
|
|
|
38
38
|
WebhookChannel,
|
|
39
39
|
)
|
|
40
40
|
from validio_sdk.resource.credentials import (
|
|
41
|
+
AnthropicCredential,
|
|
42
|
+
AnthropicCredentialApiKey,
|
|
43
|
+
AnthropicCredentialAuth,
|
|
41
44
|
AtlanCredential,
|
|
42
45
|
AwsAthenaCredential,
|
|
43
46
|
AwsCredential,
|
|
@@ -74,6 +77,9 @@ from validio_sdk.resource.credentials import (
|
|
|
74
77
|
SnowflakeCredentialUserPassword,
|
|
75
78
|
TableauConnectedAppCredential,
|
|
76
79
|
TableauPersonalAccessTokenCredential,
|
|
80
|
+
TeradataCredential,
|
|
81
|
+
TeradataCredentialAuth,
|
|
82
|
+
TeradataCredentialUserPassword,
|
|
77
83
|
)
|
|
78
84
|
from validio_sdk.resource.filters import Filter, SqlFilter
|
|
79
85
|
from validio_sdk.resource.notification_rules import Conditions
|
|
@@ -205,6 +211,19 @@ async def load_credentials(
|
|
|
205
211
|
display_name=display_name,
|
|
206
212
|
__internal__=g,
|
|
207
213
|
)
|
|
214
|
+
case "AnthropicCredential":
|
|
215
|
+
anthropic_auth: AnthropicCredentialAuth = AnthropicCredentialApiKey(
|
|
216
|
+
api_key="UNSET",
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
credential = AnthropicCredential(
|
|
220
|
+
name=name,
|
|
221
|
+
model=c["config"]["model"],
|
|
222
|
+
base_url=c["config"]["baseUrl"],
|
|
223
|
+
auth=anthropic_auth,
|
|
224
|
+
display_name=display_name,
|
|
225
|
+
__internal__=g,
|
|
226
|
+
)
|
|
208
227
|
case "AtlanCredential":
|
|
209
228
|
credential = AtlanCredential(
|
|
210
229
|
name=name,
|
|
@@ -408,6 +427,8 @@ async def load_credentials(
|
|
|
408
427
|
port=c["config"]["port"],
|
|
409
428
|
database=c["config"]["database"],
|
|
410
429
|
auth=oracle_auth,
|
|
430
|
+
tls_enabled=c["config"]["tlsEnabled"],
|
|
431
|
+
tls_ca_certificates=c["config"]["tlsCaCertificates"],
|
|
411
432
|
display_name=display_name,
|
|
412
433
|
enable_catalog=c["enableCatalog"],
|
|
413
434
|
__internal__=g,
|
|
@@ -491,6 +512,32 @@ async def load_credentials(
|
|
|
491
512
|
enable_catalog=c["enableCatalog"],
|
|
492
513
|
__internal__=g,
|
|
493
514
|
)
|
|
515
|
+
case "TeradataCredential":
|
|
516
|
+
auth_type = c["config"]["auth"]["__typename"]
|
|
517
|
+
|
|
518
|
+
if auth_type == "TeradataCredentialUserPassword":
|
|
519
|
+
teradata_auth: TeradataCredentialAuth = (
|
|
520
|
+
TeradataCredentialUserPassword(
|
|
521
|
+
user=c["config"]["auth"]["user"],
|
|
522
|
+
password="UNSET",
|
|
523
|
+
)
|
|
524
|
+
)
|
|
525
|
+
else:
|
|
526
|
+
raise ValidioBugError(
|
|
527
|
+
f"Unknown Teradata auth type on {name}: '{auth_type}'"
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
credential = TeradataCredential(
|
|
531
|
+
name=name,
|
|
532
|
+
host=c["config"]["host"],
|
|
533
|
+
auth=teradata_auth,
|
|
534
|
+
ssl_mode=c["config"]["sslMode"],
|
|
535
|
+
https_port=c["config"]["httpsPort"],
|
|
536
|
+
tdmst_port=c["config"]["tdmstPort"],
|
|
537
|
+
display_name=display_name,
|
|
538
|
+
enable_catalog=c["enableCatalog"],
|
|
539
|
+
__internal__=g,
|
|
540
|
+
)
|
|
494
541
|
case _:
|
|
495
542
|
raise ValidioError(
|
|
496
543
|
f"unsupported credential '{name}' of type '{type(c)}'"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Notification Channels."""
|
|
2
2
|
|
|
3
3
|
from enum import Enum
|
|
4
|
-
from typing import TYPE_CHECKING, Any,
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Union, cast
|
|
5
5
|
|
|
6
6
|
from camel_converter import to_camel
|
|
7
7
|
|
|
@@ -387,7 +387,7 @@ class EmailChannelAuthSmtpUserPassword(ApiSecretChangeNestedResource):
|
|
|
387
387
|
|
|
388
388
|
def _nested_objects(
|
|
389
389
|
self,
|
|
390
|
-
) -> dict[str,
|
|
390
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
391
391
|
return {}
|
|
392
392
|
|
|
393
393
|
|
|
@@ -456,5 +456,5 @@ class EmailChannel(Channel):
|
|
|
456
456
|
|
|
457
457
|
def _nested_objects(
|
|
458
458
|
self,
|
|
459
|
-
) -> dict[str,
|
|
459
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
460
460
|
return {"auth": self.auth}
|
|
@@ -21,6 +21,7 @@ from validio_sdk.resource._serde import (
|
|
|
21
21
|
_api_update_input_params,
|
|
22
22
|
_encode_resource,
|
|
23
23
|
_import_resource_params,
|
|
24
|
+
_maybe_cast,
|
|
24
25
|
decode_nested_objects,
|
|
25
26
|
get_children_node,
|
|
26
27
|
get_config_node,
|
|
@@ -48,6 +49,15 @@ class ClickHouseProtocol(str, Enum):
|
|
|
48
49
|
NATIVE_TLS = "NATIVE_TLS"
|
|
49
50
|
|
|
50
51
|
|
|
52
|
+
class TeradataSSLMode(str, Enum):
|
|
53
|
+
"""SSL encryption mode when connecting to Teradata."""
|
|
54
|
+
|
|
55
|
+
PREFER = "PREFER"
|
|
56
|
+
ALLOW = "ALLOW"
|
|
57
|
+
DISABLE = "DISABLE"
|
|
58
|
+
REQUIRE = "REQUIRE"
|
|
59
|
+
|
|
60
|
+
|
|
51
61
|
class Credential(Resource):
|
|
52
62
|
"""
|
|
53
63
|
Base class for a credential resource.
|
|
@@ -236,6 +246,100 @@ class Credential(Resource):
|
|
|
236
246
|
return test_input
|
|
237
247
|
|
|
238
248
|
|
|
249
|
+
class AnthropicCredentialApiKey(ApiSecretChangeNestedResource):
|
|
250
|
+
"""Anthropic credential using API key for authentication."""
|
|
251
|
+
|
|
252
|
+
def __init__(
|
|
253
|
+
self,
|
|
254
|
+
*,
|
|
255
|
+
api_key: str,
|
|
256
|
+
):
|
|
257
|
+
"""
|
|
258
|
+
Constructor.
|
|
259
|
+
|
|
260
|
+
:param api_key: API key to use for connecting to Anthropic.
|
|
261
|
+
"""
|
|
262
|
+
self.api_key = api_key
|
|
263
|
+
|
|
264
|
+
def _api_variant_name(self) -> str:
|
|
265
|
+
return "apiKey"
|
|
266
|
+
|
|
267
|
+
def _immutable_fields(self) -> set[str]:
|
|
268
|
+
return set({})
|
|
269
|
+
|
|
270
|
+
def _mutable_fields(self) -> set[str]:
|
|
271
|
+
return set({})
|
|
272
|
+
|
|
273
|
+
def _secret_fields(self) -> set[str]:
|
|
274
|
+
return {"api_key"}
|
|
275
|
+
|
|
276
|
+
def _nested_objects(
|
|
277
|
+
self,
|
|
278
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
279
|
+
return {}
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
AnthropicCredentialAuth = Union[AnthropicCredentialApiKey]
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
class AnthropicCredential(Credential):
|
|
286
|
+
"""Credential to connect to Anthropic."""
|
|
287
|
+
|
|
288
|
+
def __init__(
|
|
289
|
+
self,
|
|
290
|
+
*,
|
|
291
|
+
name: str,
|
|
292
|
+
model: str,
|
|
293
|
+
auth: AnthropicCredentialAuth,
|
|
294
|
+
base_url: str | None = None,
|
|
295
|
+
display_name: str | None = None,
|
|
296
|
+
ignore_changes: bool = False,
|
|
297
|
+
__internal__: ResourceGraph | None = None,
|
|
298
|
+
):
|
|
299
|
+
"""
|
|
300
|
+
Constructor.
|
|
301
|
+
|
|
302
|
+
:param name: Unique resource name assigned to the credential
|
|
303
|
+
:param model: Name of the model to use. E.g. claude-sonnet-4-5
|
|
304
|
+
:param auth: Auth method to use for connecting to Anthropic.
|
|
305
|
+
:param base_url: Base URL of Anthropic API. E.g. https://api.anthropic.com/v1.
|
|
306
|
+
If not provided, defaults to the standard Anthropic API endpoint.
|
|
307
|
+
:param display_name: Human-readable name for the credential. This name is
|
|
308
|
+
visible in the UI and does not need to be unique.
|
|
309
|
+
:param ignore_changes: If set to true, changes to the resource will be ignored.
|
|
310
|
+
"""
|
|
311
|
+
super().__init__(
|
|
312
|
+
name=name,
|
|
313
|
+
display_name=display_name,
|
|
314
|
+
ignore_changes=ignore_changes,
|
|
315
|
+
__internal__=__internal__,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
self.model = model
|
|
319
|
+
self.auth = auth
|
|
320
|
+
self.base_url = base_url
|
|
321
|
+
|
|
322
|
+
def _immutable_fields(self) -> set[str]:
|
|
323
|
+
return set({})
|
|
324
|
+
|
|
325
|
+
def _mutable_fields(self) -> set[str]:
|
|
326
|
+
return {
|
|
327
|
+
*super()._mutable_fields(),
|
|
328
|
+
*{
|
|
329
|
+
"model",
|
|
330
|
+
"base_url",
|
|
331
|
+
},
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
def _secret_fields(self) -> set[str]:
|
|
335
|
+
return set()
|
|
336
|
+
|
|
337
|
+
def _nested_objects(
|
|
338
|
+
self,
|
|
339
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
340
|
+
return {"auth": self.auth}
|
|
341
|
+
|
|
342
|
+
|
|
239
343
|
class AtlanCredential(Credential):
|
|
240
344
|
"""(BETA) An Atlan credential resource."""
|
|
241
345
|
|
|
@@ -647,7 +751,7 @@ class SnowflakeCredentialKeyPair(ApiSecretChangeNestedResource):
|
|
|
647
751
|
|
|
648
752
|
def _nested_objects(
|
|
649
753
|
self,
|
|
650
|
-
) -> dict[str,
|
|
754
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
651
755
|
return {}
|
|
652
756
|
|
|
653
757
|
|
|
@@ -683,7 +787,7 @@ class SnowflakeCredentialUserPassword(ApiSecretChangeNestedResource):
|
|
|
683
787
|
|
|
684
788
|
def _nested_objects(
|
|
685
789
|
self,
|
|
686
|
-
) -> dict[str,
|
|
790
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
687
791
|
return {}
|
|
688
792
|
|
|
689
793
|
|
|
@@ -748,7 +852,7 @@ class SnowflakeCredential(Credential):
|
|
|
748
852
|
|
|
749
853
|
def _nested_objects(
|
|
750
854
|
self,
|
|
751
|
-
) -> dict[str,
|
|
855
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
752
856
|
return {"auth": self.auth}
|
|
753
857
|
|
|
754
858
|
|
|
@@ -1337,7 +1441,7 @@ class MsSqlServerCredentialUserPassword(ApiSecretChangeNestedResource):
|
|
|
1337
1441
|
|
|
1338
1442
|
def _nested_objects(
|
|
1339
1443
|
self,
|
|
1340
|
-
) -> dict[str,
|
|
1444
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
1341
1445
|
return {}
|
|
1342
1446
|
|
|
1343
1447
|
|
|
@@ -1372,7 +1476,7 @@ class MsSqlServerCredentialEntraId(ApiSecretChangeNestedResource):
|
|
|
1372
1476
|
|
|
1373
1477
|
def _nested_objects(
|
|
1374
1478
|
self,
|
|
1375
|
-
) -> dict[str,
|
|
1479
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
1376
1480
|
return {}
|
|
1377
1481
|
|
|
1378
1482
|
|
|
@@ -1442,7 +1546,7 @@ class MsSqlServerCredential(Credential):
|
|
|
1442
1546
|
|
|
1443
1547
|
def _nested_objects(
|
|
1444
1548
|
self,
|
|
1445
|
-
) -> dict[str,
|
|
1549
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
1446
1550
|
return {"auth": self.auth}
|
|
1447
1551
|
|
|
1448
1552
|
|
|
@@ -1475,7 +1579,7 @@ class OmniCredentialApiKey(ApiSecretChangeNestedResource):
|
|
|
1475
1579
|
|
|
1476
1580
|
def _nested_objects(
|
|
1477
1581
|
self,
|
|
1478
|
-
) -> dict[str,
|
|
1582
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
1479
1583
|
return {}
|
|
1480
1584
|
|
|
1481
1585
|
|
|
@@ -1536,7 +1640,7 @@ class OmniCredential(Credential):
|
|
|
1536
1640
|
|
|
1537
1641
|
def _nested_objects(
|
|
1538
1642
|
self,
|
|
1539
|
-
) -> dict[str,
|
|
1643
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
1540
1644
|
return {"auth": self.auth}
|
|
1541
1645
|
|
|
1542
1646
|
|
|
@@ -1571,7 +1675,7 @@ class OracleCredentialUserPassword(ApiSecretChangeNestedResource):
|
|
|
1571
1675
|
|
|
1572
1676
|
def _nested_objects(
|
|
1573
1677
|
self,
|
|
1574
|
-
) -> dict[str,
|
|
1678
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
1575
1679
|
return {}
|
|
1576
1680
|
|
|
1577
1681
|
|
|
@@ -1588,6 +1692,8 @@ class OracleCredential(Credential):
|
|
|
1588
1692
|
port: int,
|
|
1589
1693
|
database: str,
|
|
1590
1694
|
auth: OracleCredentialAuth,
|
|
1695
|
+
tls_enabled: bool | None = None,
|
|
1696
|
+
tls_ca_certificates: str | None = None,
|
|
1591
1697
|
enable_catalog: bool = False,
|
|
1592
1698
|
display_name: str | None = None,
|
|
1593
1699
|
ignore_changes: bool = False,
|
|
@@ -1601,6 +1707,10 @@ class OracleCredential(Credential):
|
|
|
1601
1707
|
:param port: Port number of the server.
|
|
1602
1708
|
:param auth: Credentials to use for authentication.
|
|
1603
1709
|
:param database: Name of the database to connect to
|
|
1710
|
+
:param tls_enabled: If set to true, connections will be
|
|
1711
|
+
established using the TLS protocol.
|
|
1712
|
+
:param tls_ca_certificates: PEM certificate bundle used to
|
|
1713
|
+
verify the server TLS certificate.
|
|
1604
1714
|
:param enable_catalog: If set to true, this credential will
|
|
1605
1715
|
be used to fetch catalog information.
|
|
1606
1716
|
:param display_name: Human-readable name for the credential. This name is
|
|
@@ -1618,6 +1728,8 @@ class OracleCredential(Credential):
|
|
|
1618
1728
|
self.port = port
|
|
1619
1729
|
self.database = database
|
|
1620
1730
|
self.auth = auth
|
|
1731
|
+
self.tls_enabled = tls_enabled
|
|
1732
|
+
self.tls_ca_certificates = tls_ca_certificates
|
|
1621
1733
|
self.enable_catalog = enable_catalog
|
|
1622
1734
|
|
|
1623
1735
|
def _immutable_fields(self) -> set[str]:
|
|
@@ -1630,6 +1742,8 @@ class OracleCredential(Credential):
|
|
|
1630
1742
|
"host",
|
|
1631
1743
|
"port",
|
|
1632
1744
|
"database",
|
|
1745
|
+
"tls_enabled",
|
|
1746
|
+
"tls_ca_certificates",
|
|
1633
1747
|
"enable_catalog",
|
|
1634
1748
|
},
|
|
1635
1749
|
}
|
|
@@ -1639,7 +1753,7 @@ class OracleCredential(Credential):
|
|
|
1639
1753
|
|
|
1640
1754
|
def _nested_objects(
|
|
1641
1755
|
self,
|
|
1642
|
-
) -> dict[str,
|
|
1756
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
1643
1757
|
return {"auth": self.auth}
|
|
1644
1758
|
|
|
1645
1759
|
|
|
@@ -1871,7 +1985,7 @@ class MsPowerBiCredentialAuthEntraId(ApiSecretChangeNestedResource):
|
|
|
1871
1985
|
|
|
1872
1986
|
def _nested_objects(
|
|
1873
1987
|
self,
|
|
1874
|
-
) -> dict[str,
|
|
1988
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
1875
1989
|
return {}
|
|
1876
1990
|
|
|
1877
1991
|
|
|
@@ -1922,7 +2036,7 @@ class MsPowerBiCredential(Credential):
|
|
|
1922
2036
|
|
|
1923
2037
|
def _nested_objects(
|
|
1924
2038
|
self,
|
|
1925
|
-
) -> dict[str,
|
|
2039
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
1926
2040
|
return {"auth": self.auth}
|
|
1927
2041
|
|
|
1928
2042
|
|
|
@@ -1978,6 +2092,115 @@ class SigmaCredential(Credential):
|
|
|
1978
2092
|
return {"client_secret"}
|
|
1979
2093
|
|
|
1980
2094
|
|
|
2095
|
+
class TeradataCredentialUserPassword(ApiSecretChangeNestedResource):
|
|
2096
|
+
"""Teradata credential via user-password auth."""
|
|
2097
|
+
|
|
2098
|
+
def __init__(
|
|
2099
|
+
self,
|
|
2100
|
+
user: str,
|
|
2101
|
+
password: str,
|
|
2102
|
+
):
|
|
2103
|
+
"""
|
|
2104
|
+
Constructor.
|
|
2105
|
+
|
|
2106
|
+
:param user: Username.
|
|
2107
|
+
:param password: Password.
|
|
2108
|
+
"""
|
|
2109
|
+
self.user = user
|
|
2110
|
+
self.password = password
|
|
2111
|
+
|
|
2112
|
+
def _api_variant_name(self) -> str:
|
|
2113
|
+
return "userPassword"
|
|
2114
|
+
|
|
2115
|
+
def _immutable_fields(self) -> set[str]:
|
|
2116
|
+
return set({})
|
|
2117
|
+
|
|
2118
|
+
def _mutable_fields(self) -> set[str]:
|
|
2119
|
+
return {"user"}
|
|
2120
|
+
|
|
2121
|
+
def _secret_fields(self) -> set[str]:
|
|
2122
|
+
return {"password"}
|
|
2123
|
+
|
|
2124
|
+
def _nested_objects(
|
|
2125
|
+
self,
|
|
2126
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
2127
|
+
return {}
|
|
2128
|
+
|
|
2129
|
+
|
|
2130
|
+
TeradataCredentialAuth = Union[TeradataCredentialUserPassword]
|
|
2131
|
+
|
|
2132
|
+
|
|
2133
|
+
class TeradataCredential(Credential):
|
|
2134
|
+
"""Credential to connect to a Teradata warehouse."""
|
|
2135
|
+
|
|
2136
|
+
def __init__(
|
|
2137
|
+
self,
|
|
2138
|
+
name: str,
|
|
2139
|
+
host: str,
|
|
2140
|
+
auth: TeradataCredentialAuth,
|
|
2141
|
+
ssl_mode: TeradataSSLMode,
|
|
2142
|
+
https_port: int | None = None,
|
|
2143
|
+
tdmst_port: int | None = None,
|
|
2144
|
+
enable_catalog: bool = False,
|
|
2145
|
+
display_name: str | None = None,
|
|
2146
|
+
ignore_changes: bool = False,
|
|
2147
|
+
__internal__: ResourceGraph | None = None,
|
|
2148
|
+
):
|
|
2149
|
+
"""
|
|
2150
|
+
Constructor.
|
|
2151
|
+
|
|
2152
|
+
:param name: Unique resource name assigned to the credential
|
|
2153
|
+
:param host: Host address of the server.
|
|
2154
|
+
:param auth: Credentials to use for authentication.
|
|
2155
|
+
:param ssl_mode: SSL encryption mode when connecting to Teradata.
|
|
2156
|
+
:param https_port: Port number to use to access the Teradata server
|
|
2157
|
+
via SSL connection (default 443).
|
|
2158
|
+
:param tdmst_port: Port number to use to access the Teradata server
|
|
2159
|
+
via non-SSL connection (default 1025).
|
|
2160
|
+
:param enable_catalog: If set to true, this credential will
|
|
2161
|
+
be used to fetch catalog information.
|
|
2162
|
+
:param display_name: Human-readable name for the credential. This name is
|
|
2163
|
+
visible in the UI and does not need to be unique.
|
|
2164
|
+
:param ignore_changes: If set to true, changes to the resource will be ignored.
|
|
2165
|
+
"""
|
|
2166
|
+
super().__init__(
|
|
2167
|
+
name=name,
|
|
2168
|
+
display_name=display_name,
|
|
2169
|
+
ignore_changes=ignore_changes,
|
|
2170
|
+
__internal__=__internal__,
|
|
2171
|
+
)
|
|
2172
|
+
|
|
2173
|
+
self.host = host
|
|
2174
|
+
self.auth = auth
|
|
2175
|
+
self.ssl_mode = _maybe_cast(ssl_mode, TeradataSSLMode)
|
|
2176
|
+
self.https_port = https_port
|
|
2177
|
+
self.tdmst_port = tdmst_port
|
|
2178
|
+
self.enable_catalog = enable_catalog
|
|
2179
|
+
|
|
2180
|
+
def _immutable_fields(self) -> set[str]:
|
|
2181
|
+
return set({})
|
|
2182
|
+
|
|
2183
|
+
def _mutable_fields(self) -> set[str]:
|
|
2184
|
+
return {
|
|
2185
|
+
*super()._mutable_fields(),
|
|
2186
|
+
*{
|
|
2187
|
+
"host",
|
|
2188
|
+
"enable_catalog",
|
|
2189
|
+
"ssl_mode",
|
|
2190
|
+
"https_port",
|
|
2191
|
+
"tdmst_port",
|
|
2192
|
+
},
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
def _secret_fields(self) -> set[str]:
|
|
2196
|
+
return set()
|
|
2197
|
+
|
|
2198
|
+
def _nested_objects(
|
|
2199
|
+
self,
|
|
2200
|
+
) -> dict[str, "Diffable | list[Diffable] | None"]:
|
|
2201
|
+
return {"auth": self.auth}
|
|
2202
|
+
|
|
2203
|
+
|
|
1981
2204
|
WarehouseCredential = Union[
|
|
1982
2205
|
AzureSynapseCredential,
|
|
1983
2206
|
AwsAthenaCredential,
|
|
@@ -1986,5 +2209,7 @@ WarehouseCredential = Union[
|
|
|
1986
2209
|
DatabricksCredential,
|
|
1987
2210
|
GcpCredential,
|
|
1988
2211
|
PostgreSqlCredential,
|
|
2212
|
+
OracleCredential,
|
|
1989
2213
|
SnowflakeCredential,
|
|
2214
|
+
TeradataCredential,
|
|
1990
2215
|
]
|
|
@@ -39,6 +39,7 @@ from validio_sdk.resource.credentials import (
|
|
|
39
39
|
OracleCredential,
|
|
40
40
|
PostgreSqlCredential,
|
|
41
41
|
SnowflakeCredential,
|
|
42
|
+
TeradataCredential,
|
|
42
43
|
WarehouseCredential,
|
|
43
44
|
)
|
|
44
45
|
from validio_sdk.resource.enums import IncidentGroupPriority
|
|
@@ -1444,6 +1445,77 @@ class OracleSource(Source):
|
|
|
1444
1445
|
}
|
|
1445
1446
|
|
|
1446
1447
|
|
|
1448
|
+
class TeradataSource(Source):
|
|
1449
|
+
"""A Teradata source configuration."""
|
|
1450
|
+
|
|
1451
|
+
def __init__(
|
|
1452
|
+
self,
|
|
1453
|
+
name: str,
|
|
1454
|
+
credential: TeradataCredential,
|
|
1455
|
+
database: str,
|
|
1456
|
+
table: str,
|
|
1457
|
+
schedule: str | None,
|
|
1458
|
+
display_name: str | None = None,
|
|
1459
|
+
owner: str | None = None,
|
|
1460
|
+
ignore_changes: bool = False,
|
|
1461
|
+
jtd_schema: JsonTypeDefinition | None = None,
|
|
1462
|
+
description: str | None = None,
|
|
1463
|
+
tags: list[Tag] | None = None,
|
|
1464
|
+
priority: IncidentGroupPriority | None = None,
|
|
1465
|
+
):
|
|
1466
|
+
"""
|
|
1467
|
+
Constructor.
|
|
1468
|
+
|
|
1469
|
+
:param database: Name of the database to connect to.
|
|
1470
|
+
:param table: Name of table to monitor.
|
|
1471
|
+
:param schedule: A 5-digit cron expression specifying how when the source
|
|
1472
|
+
polls for new data. Example: '0 0 * * *' to poll daily at midnight.
|
|
1473
|
+
:param display_name: Human-readable name for the source. This name is
|
|
1474
|
+
visible in the UI and does not need to be unique.
|
|
1475
|
+
:param owner: User email address of the source owner.
|
|
1476
|
+
:param ignore_changes: If set to true, changes to the resource will be ignored.
|
|
1477
|
+
:param description: Description of the resource.
|
|
1478
|
+
:param tags: Tags to add to the resource
|
|
1479
|
+
:param priority: Priority to assign to incidents created by this source.
|
|
1480
|
+
"""
|
|
1481
|
+
super().__init__(
|
|
1482
|
+
name=name,
|
|
1483
|
+
credential=credential,
|
|
1484
|
+
display_name=display_name,
|
|
1485
|
+
owner=owner,
|
|
1486
|
+
ignore_changes=ignore_changes,
|
|
1487
|
+
jtd_schema=jtd_schema,
|
|
1488
|
+
description=description,
|
|
1489
|
+
tags=tags,
|
|
1490
|
+
priority=priority,
|
|
1491
|
+
)
|
|
1492
|
+
|
|
1493
|
+
self.database = database
|
|
1494
|
+
self.table = table
|
|
1495
|
+
self.schedule = schedule
|
|
1496
|
+
|
|
1497
|
+
def _immutable_fields(self) -> set[str]:
|
|
1498
|
+
return {
|
|
1499
|
+
*super()._immutable_fields(),
|
|
1500
|
+
*{
|
|
1501
|
+
"database",
|
|
1502
|
+
"table",
|
|
1503
|
+
},
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
def _mutable_fields(self) -> set[str]:
|
|
1507
|
+
return {
|
|
1508
|
+
*super()._mutable_fields(),
|
|
1509
|
+
*{"schedule"},
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
def _api_infer_schema_input(self) -> dict[str, object] | None:
|
|
1513
|
+
return {
|
|
1514
|
+
"database": self.database,
|
|
1515
|
+
"table": self.table,
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
|
|
1447
1519
|
# Streaming
|
|
1448
1520
|
|
|
1449
1521
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
|
|
3
|
+
from validio_sdk.code._import import ImportContext
|
|
3
4
|
from validio_sdk.resource._diff import (
|
|
4
5
|
CascadeReplacementReason,
|
|
5
6
|
DiffContext,
|
|
@@ -11,6 +12,7 @@ from validio_sdk.resource._diff import (
|
|
|
11
12
|
_diff_resource_graph,
|
|
12
13
|
)
|
|
13
14
|
from validio_sdk.resource._resource import ResourceGraph
|
|
15
|
+
from validio_sdk.resource._serde import _import_value_repr
|
|
14
16
|
from validio_sdk.resource.channels import Channel, SlackChannel, WebhookChannel
|
|
15
17
|
from validio_sdk.resource.credentials import AwsCredential, Credential, DemoCredential
|
|
16
18
|
from validio_sdk.resource.filters import (
|
|
@@ -1774,3 +1776,49 @@ def test_enum_filter_values_should_ignore_order() -> None:
|
|
|
1774
1776
|
|
|
1775
1777
|
_add_namespace(namespace, server_ctx)
|
|
1776
1778
|
assert expected == _diff_resource_graph(namespace, manifest_ctx, server_ctx)
|
|
1779
|
+
|
|
1780
|
+
|
|
1781
|
+
@pytest.mark.parametrize(
|
|
1782
|
+
("input", "expected"),
|
|
1783
|
+
[
|
|
1784
|
+
(
|
|
1785
|
+
"this string has no special characters",
|
|
1786
|
+
"'this string has no special characters'",
|
|
1787
|
+
),
|
|
1788
|
+
(
|
|
1789
|
+
"this string contains '",
|
|
1790
|
+
'"this string contains \'"',
|
|
1791
|
+
),
|
|
1792
|
+
(
|
|
1793
|
+
"this\nmultiline\nshould be\ntripple quoted",
|
|
1794
|
+
"'''this\nmultiline\nshould be\ntripple quoted'''",
|
|
1795
|
+
),
|
|
1796
|
+
(
|
|
1797
|
+
"multiline with '''\nshould be\ndouble quotes",
|
|
1798
|
+
'"""multiline with \'\'\'\nshould be\ndouble quotes"""',
|
|
1799
|
+
),
|
|
1800
|
+
(
|
|
1801
|
+
"multiline trailing\nshould be\ndouble quotes'",
|
|
1802
|
+
'"""multiline trailing\nshould be\ndouble quotes\'"""',
|
|
1803
|
+
),
|
|
1804
|
+
(
|
|
1805
|
+
"'multiline leading\nshould be\ndouble quotes",
|
|
1806
|
+
'"""\'multiline leading\nshould be\ndouble quotes"""',
|
|
1807
|
+
),
|
|
1808
|
+
(
|
|
1809
|
+
'multiline with """\nshould be\nsingle quotes',
|
|
1810
|
+
"'''multiline with \"\"\"\nshould be\nsingle quotes'''",
|
|
1811
|
+
),
|
|
1812
|
+
(
|
|
1813
|
+
'multiline trailing\nshould be\nsingle quotes"',
|
|
1814
|
+
"'''multiline trailing\nshould be\nsingle quotes\"'''",
|
|
1815
|
+
),
|
|
1816
|
+
(
|
|
1817
|
+
'"multiline leading\nshould be\nsingle quotes',
|
|
1818
|
+
"'''\"multiline leading\nshould be\nsingle quotes'''",
|
|
1819
|
+
),
|
|
1820
|
+
],
|
|
1821
|
+
)
|
|
1822
|
+
def test_import_value_repr(input: str, expected: str) -> None:
|
|
1823
|
+
got = _import_value_repr(input, 0, ImportContext())
|
|
1824
|
+
assert got == expected
|
|
@@ -416,7 +416,7 @@ class Validator(Resource, ABC):
|
|
|
416
416
|
def _mutable_fields(self) -> set[str]:
|
|
417
417
|
return {
|
|
418
418
|
*super()._mutable_fields(),
|
|
419
|
-
*{"description", "filter_name", "owner", "priority"},
|
|
419
|
+
*{"description", "filter_name", "owner", "priority", "tag_names"},
|
|
420
420
|
}
|
|
421
421
|
|
|
422
422
|
def _ignored_fields(self) -> set[str]:
|
|
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
|
|
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
|
{validio_sdk-7.2.0 → validio_sdk-7.4.0}/validio_sdk/resource/tests/assets/example_manifest.json
RENAMED
|
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
|