validio-sdk 9.0.6__tar.gz → 9.2.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.
Files changed (57) hide show
  1. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/PKG-INFO +1 -1
  2. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/pyproject.toml +1 -1
  3. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/_api/api.py +83 -1
  4. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/features.py +2 -0
  5. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/_server_resources.py +68 -0
  6. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/channels.py +15 -5
  7. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/credentials.py +272 -0
  8. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/sources.py +164 -0
  9. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/LICENSE +0 -0
  10. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/README_PUBLIC.md +0 -0
  11. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/__init__.py +0 -0
  12. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/_api/__init__.py +0 -0
  13. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/client/__init__.py +0 -0
  14. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/client/client.py +0 -0
  15. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/code/__init__.py +0 -0
  16. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/code/_import.py +0 -0
  17. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/code/_progress.py +0 -0
  18. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/code/apply.py +0 -0
  19. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/code/plan.py +0 -0
  20. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/code/scaffold.py +0 -0
  21. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/code/settings.py +0 -0
  22. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/config.py +0 -0
  23. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/dbt.py +0 -0
  24. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/exception.py +0 -0
  25. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/metadata.py +0 -0
  26. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/py.typed +0 -0
  27. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/__init__.py +0 -0
  28. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/_diff.py +0 -0
  29. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/_diff_util.py +0 -0
  30. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/_diffable.py +0 -0
  31. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/_errors.py +0 -0
  32. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/_resource.py +0 -0
  33. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/_resource_graph.py +0 -0
  34. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/_serde.py +0 -0
  35. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/_update_namespace.py +0 -0
  36. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/_util.py +0 -0
  37. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/enums.py +0 -0
  38. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/filters.py +0 -0
  39. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/notification_rules.py +0 -0
  40. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/replacement.py +0 -0
  41. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/segmentations.py +0 -0
  42. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tags.py +0 -0
  43. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tests/__init__.py +0 -0
  44. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tests/assets/example_manifest.json +0 -0
  45. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tests/assets/expected_trimmed_manifest.json +0 -0
  46. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tests/test__dbt.py +0 -0
  47. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tests/test__diff.py +0 -0
  48. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tests/test__features.py +0 -0
  49. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tests/test__plan.py +0 -0
  50. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tests/test__resource.py +0 -0
  51. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tests/test__sql_validation.py +0 -0
  52. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/tests/test_import.py +0 -0
  53. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/thresholds.py +0 -0
  54. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/validators.py +0 -0
  55. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/resource/windows.py +0 -0
  56. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/scalars.py +0 -0
  57. {validio_sdk-9.0.6 → validio_sdk-9.2.0}/validio_sdk/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: validio-sdk
3
- Version: 9.0.6
3
+ Version: 9.2.0
4
4
  Summary: SDK to interact with the Validio platform
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -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 = "9.0.6"
6
+ version = "9.2.0"
7
7
  description = "SDK to interact with the Validio platform"
8
8
  authors = ["Validio <support@validio.io>"]
9
9
  license = "Apache-2.0"
@@ -401,7 +401,33 @@ async def get_sources(
401
401
  source_id: str | None = None,
402
402
  namespace_id: str | None = None,
403
403
  ) -> list[dict[str, Any]] | dict[str, Any]:
404
- source_details = """
404
+ sap_iq_fragment = ""
405
+ if is_enabled(Feature.SAP_IQ):
406
+ sap_iq_fragment = """
407
+ ... on SapIqSource {
408
+ config {
409
+ database
410
+ schema
411
+ table
412
+ schedule
413
+ }
414
+ }
415
+ """
416
+
417
+ open_edge_fragment = ""
418
+ if is_enabled(Feature.OPEN_EDGE):
419
+ open_edge_fragment = """
420
+ ... on OpenEdgeSource {
421
+ config {
422
+ schema
423
+ table
424
+ schedule
425
+ }
426
+ }
427
+ """
428
+
429
+ source_details = (
430
+ """
405
431
  fragment SourceDetails on Source {
406
432
  __typename
407
433
  id
@@ -513,6 +539,9 @@ async def get_sources(
513
539
  schedule
514
540
  }
515
541
  }
542
+ """
543
+ + sap_iq_fragment
544
+ + """
516
545
  ... on MsSqlServerSource {
517
546
  config {
518
547
  database
@@ -576,8 +605,12 @@ async def get_sources(
576
605
  schedule
577
606
  }
578
607
  }
608
+ """
609
+ + open_edge_fragment
610
+ + """
579
611
  }
580
612
  """
613
+ )
581
614
 
582
615
  if source_id and source_id.startswith("SRC_"):
583
616
  query = f"""
@@ -984,6 +1017,50 @@ async def get_credentials(
984
1017
  }
985
1018
  """
986
1019
 
1020
+ sap_iq_fragment = ""
1021
+ if is_enabled(Feature.SAP_IQ):
1022
+ sap_iq_fragment = """
1023
+ ... on SapIqCredential {
1024
+ config {
1025
+ host
1026
+ port
1027
+ server
1028
+ sapIqSslMode: sslMode
1029
+ tlsCaCertificate
1030
+ certificateName
1031
+ auth {
1032
+ __typename
1033
+ ... on SapIqCredentialUserPassword {
1034
+ user
1035
+ }
1036
+ }
1037
+ }
1038
+ enableCatalog
1039
+ }
1040
+ """
1041
+
1042
+ open_edge_fragment = ""
1043
+ if is_enabled(Feature.OPEN_EDGE):
1044
+ open_edge_fragment = """
1045
+ ... on OpenEdgeCredential {
1046
+ config {
1047
+ host
1048
+ port
1049
+ databaseRequired: database
1050
+ openEdgeSslMode: sslMode
1051
+ tlsCaCertificate
1052
+ certificateName
1053
+ auth {
1054
+ __typename
1055
+ ... on OpenEdgeCredentialUserPassword {
1056
+ user
1057
+ }
1058
+ }
1059
+ }
1060
+ enableCatalog
1061
+ }
1062
+ """
1063
+
987
1064
  credential_details = (
988
1065
  """
989
1066
  fragment CredentialBase on Credential {
@@ -1035,6 +1112,8 @@ async def get_credentials(
1035
1112
  }
1036
1113
  """
1037
1114
  + gcp_gemini_enterprise_fragment
1115
+ + sap_iq_fragment
1116
+ + open_edge_fragment
1038
1117
  + """
1039
1118
  ... on AwsCredential {
1040
1119
  config {
@@ -1133,6 +1212,7 @@ async def get_credentials(
1133
1212
  }
1134
1213
  tlsEnabledRequired: tlsEnabled
1135
1214
  tlsCaCertificates
1215
+ packageCollection
1136
1216
  }
1137
1217
  enableCatalog
1138
1218
  }
@@ -1336,6 +1416,8 @@ async def get_credentials(
1336
1416
  ("optUser", "user"),
1337
1417
  ("optBaseUrl", "baseUrl"),
1338
1418
  ("tlsEnabledRequired", "tlsEnabled"),
1419
+ ("sapIqSslMode", "sslMode"),
1420
+ ("openEdgeSslMode", "sslMode"),
1339
1421
  ],
1340
1422
  )
1341
1423
  result[i] = credential
@@ -31,6 +31,8 @@ class Feature(str, Enum):
31
31
 
32
32
  GCP_GEMINI_ENTERPRISE_CREDENTIAL = "gemini"
33
33
  JIRA = "jira"
34
+ OPEN_EDGE = "open-edge"
35
+ SAP_IQ = "sap-iq"
34
36
 
35
37
 
36
38
  def is_enabled(feature: Feature) -> bool:
@@ -94,10 +94,16 @@ from validio_sdk.resource.credentials import (
94
94
  OpenAiCredential,
95
95
  OpenAiCredentialApiKey,
96
96
  OpenAiCredentialAuth,
97
+ OpenEdgeCredential,
98
+ OpenEdgeCredentialAuth,
99
+ OpenEdgeCredentialUserPassword,
97
100
  OracleCredential,
98
101
  OracleCredentialAuth,
99
102
  OracleCredentialUserPassword,
100
103
  PostgreSqlCredential,
104
+ SapIqCredential,
105
+ SapIqCredentialAuth,
106
+ SapIqCredentialUserPassword,
101
107
  SigmaCredential,
102
108
  SnowflakeCredential,
103
109
  SnowflakeCredentialAuth,
@@ -366,6 +372,35 @@ async def load_credentials(
366
372
  auth=db2_auth,
367
373
  tls_enabled=c["config"]["tlsEnabled"],
368
374
  tls_ca_certificates=c["config"]["tlsCaCertificates"],
375
+ package_collection=c["config"]["packageCollection"],
376
+ display_name=display_name,
377
+ enable_catalog=c["enableCatalog"],
378
+ __internal__=g,
379
+ )
380
+ case "OpenEdgeCredential" if is_enabled(Feature.OPEN_EDGE):
381
+ auth_type = c["config"]["auth"]["__typename"]
382
+
383
+ if auth_type == "OpenEdgeCredentialUserPassword":
384
+ open_edge_auth: OpenEdgeCredentialAuth = (
385
+ OpenEdgeCredentialUserPassword(
386
+ user=c["config"]["auth"]["user"],
387
+ password="UNSET",
388
+ )
389
+ )
390
+ else:
391
+ raise ValidioBugError(
392
+ f"Unknown OpenEdge auth type on {name}: '{auth_type}'"
393
+ )
394
+
395
+ credential = OpenEdgeCredential(
396
+ name=name,
397
+ host=c["config"]["host"],
398
+ port=c["config"]["port"],
399
+ database=c["config"]["database"],
400
+ auth=open_edge_auth,
401
+ ssl_mode=c["config"]["sslMode"],
402
+ tls_ca_certificate=c["config"]["tlsCaCertificate"],
403
+ certificate_name=c["config"]["certificateName"],
369
404
  display_name=display_name,
370
405
  enable_catalog=c["enableCatalog"],
371
406
  __internal__=g,
@@ -659,6 +694,32 @@ async def load_credentials(
659
694
  enable_catalog=c["enableCatalog"],
660
695
  __internal__=g,
661
696
  )
697
+ case "SapIqCredential" if is_enabled(Feature.SAP_IQ):
698
+ auth_type = c["config"]["auth"]["__typename"]
699
+
700
+ if auth_type == "SapIqCredentialUserPassword":
701
+ sap_iq_auth: SapIqCredentialAuth = SapIqCredentialUserPassword(
702
+ user=c["config"]["auth"]["user"],
703
+ password="UNSET",
704
+ )
705
+ else:
706
+ raise ValidioBugError(
707
+ f"Unknown SAP IQ auth type on {name}: '{auth_type}'"
708
+ )
709
+
710
+ credential = SapIqCredential(
711
+ name=name,
712
+ host=c["config"]["host"],
713
+ port=c["config"]["port"],
714
+ server=c["config"]["server"],
715
+ auth=sap_iq_auth,
716
+ ssl_mode=c["config"]["sslMode"],
717
+ tls_ca_certificate=c["config"]["tlsCaCertificate"],
718
+ certificate_name=c["config"]["certificateName"],
719
+ display_name=display_name,
720
+ enable_catalog=c["enableCatalog"],
721
+ __internal__=g,
722
+ )
662
723
  case "TeradataCredential":
663
724
  auth_type = c["config"]["auth"]["__typename"]
664
725
 
@@ -858,6 +919,13 @@ async def load_sources(
858
919
  owner = s.get("owner") or {}
859
920
 
860
921
  cls = eval(f"validio_sdk.resource.sources.{s['__typename']}")
922
+ if cls._feature is not None and not is_enabled(cls._feature):
923
+ raise ValidioError(
924
+ f"unsupported source '{name}' of type '{s['__typename']}'. "
925
+ "If this source type requires a feature flag, "
926
+ "ensure it is enabled."
927
+ )
928
+
861
929
  source = cls(
862
930
  **{
863
931
  **{to_snake(k): v for k, v in source_config.items()},
@@ -78,7 +78,13 @@ class Channel(Resource):
78
78
  self._resource_graph._add_root(self)
79
79
 
80
80
  def _immutable_fields(self) -> set[str]:
81
- return {"integration_id"}
81
+ return set()
82
+
83
+ def _mutable_fields(self) -> set[str]:
84
+ return {
85
+ *super()._mutable_fields(),
86
+ *{"integration_id"},
87
+ }
82
88
 
83
89
  @abstractmethod
84
90
  def _deprecated_fields(self) -> set[str]:
@@ -109,15 +115,19 @@ class Channel(Resource):
109
115
  def _encode(self) -> dict[str, object]:
110
116
  return _encode_resource(self)
111
117
 
118
+ def _api_top_level_fields(
119
+ self,
120
+ namespace: str, # noqa: ARG002
121
+ ctx: "DiffContext", # noqa: ARG002
122
+ ) -> dict[str, Any]:
123
+ return {"integrationId": self.integration_id}
124
+
112
125
  def _api_top_level_create_fields(
113
126
  self,
114
127
  namespace: str,
115
128
  ctx: "DiffContext", # noqa: ARG002
116
129
  ) -> dict[str, Any]:
117
- return {"namespaceId": namespace, "integrationId": self.integration_id}
118
-
119
- def _api_config_excludes(self) -> set[str]:
120
- return {"integration_id"}
130
+ return {"namespaceId": namespace}
121
131
 
122
132
  @staticmethod
123
133
  def _decode(
@@ -53,6 +53,20 @@ class IbmDb2BackendType(str, Enum):
53
53
  ZOS = "ZOS"
54
54
 
55
55
 
56
+ class OpenEdgeSSLMode(str, Enum):
57
+ """SSL encryption mode when connecting to OpenEdge."""
58
+
59
+ DISABLE = "DISABLE"
60
+ REQUIRE = "REQUIRE"
61
+
62
+
63
+ class SapIqSslMode(str, Enum):
64
+ """SSL mode when connecting to SAP IQ."""
65
+
66
+ DISABLE = "DISABLE"
67
+ REQUIRE = "REQUIRE"
68
+
69
+
56
70
  class TeradataSSLMode(str, Enum):
57
71
  """SSL encryption mode when connecting to Teradata."""
58
72
 
@@ -1162,6 +1176,7 @@ class IbmDb2Credential(Credential):
1162
1176
  auth: IbmDb2CredentialAuth,
1163
1177
  tls_enabled: bool,
1164
1178
  tls_ca_certificates: str | None = None,
1179
+ package_collection: str | None = None,
1165
1180
  enable_catalog: bool = False,
1166
1181
  display_name: str | None = None,
1167
1182
  ignore_changes: bool = False,
@@ -1181,6 +1196,8 @@ class IbmDb2Credential(Credential):
1181
1196
  established using the TLS protocol.
1182
1197
  :param tls_ca_certificates: PEM certificate bundle used to
1183
1198
  verify the server TLS certificate.
1199
+ :param package_collection: The DB2 package collection to
1200
+ run queries under.
1184
1201
  :param enable_catalog: If set to true, this credential will
1185
1202
  be used to fetch catalog information.
1186
1203
  :param display_name: Human-readable name for the credential. This name is
@@ -1205,6 +1222,7 @@ class IbmDb2Credential(Credential):
1205
1222
  self.enable_catalog = enable_catalog
1206
1223
  self.tls_enabled = tls_enabled
1207
1224
  self.tls_ca_certificates = tls_ca_certificates
1225
+ self.package_collection = package_collection
1208
1226
 
1209
1227
  def _immutable_fields(self) -> set[str]:
1210
1228
  return {"database", "backend_type"}
@@ -1217,6 +1235,7 @@ class IbmDb2Credential(Credential):
1217
1235
  "port",
1218
1236
  "tls_enabled",
1219
1237
  "tls_ca_certificates",
1238
+ "package_collection",
1220
1239
  "enable_catalog",
1221
1240
  },
1222
1241
  }
@@ -2791,6 +2810,257 @@ class SigmaCredential(Credential):
2791
2810
  return {"client_secret"}
2792
2811
 
2793
2812
 
2813
+ class OpenEdgeCredentialUserPassword(ApiSecretChangeNestedResource):
2814
+ """OpenEdge credential via user-password auth."""
2815
+
2816
+ def __init__(
2817
+ self,
2818
+ user: str,
2819
+ password: str,
2820
+ ):
2821
+ """
2822
+ Constructor.
2823
+
2824
+ :param user: Username.
2825
+ :param password: Password.
2826
+ """
2827
+ self.user = user
2828
+ self.password = password
2829
+
2830
+ def _api_variant_name(self) -> str:
2831
+ return "userPassword"
2832
+
2833
+ def _immutable_fields(self) -> set[str]:
2834
+ return set()
2835
+
2836
+ def _mutable_fields(self) -> set[str]:
2837
+ return {"user"}
2838
+
2839
+ def _secret_fields(self) -> set[str]:
2840
+ return {"password"}
2841
+
2842
+ def _mutable_nested_objects(
2843
+ self,
2844
+ ) -> dict[str, "Diffable | list[Diffable] | None"]:
2845
+ return {}
2846
+
2847
+
2848
+ OpenEdgeCredentialAuth = Union[OpenEdgeCredentialUserPassword]
2849
+
2850
+
2851
+ class OpenEdgeCredential(Credential):
2852
+ """Credential to connect to Progress OpenEdge."""
2853
+
2854
+ _feature = Feature.OPEN_EDGE
2855
+
2856
+ def __init__(
2857
+ self,
2858
+ *,
2859
+ name: str,
2860
+ host: str,
2861
+ port: int,
2862
+ database: str,
2863
+ auth: OpenEdgeCredentialAuth,
2864
+ ssl_mode: OpenEdgeSSLMode,
2865
+ tls_ca_certificate: str | None = None,
2866
+ certificate_name: str | None = None,
2867
+ enable_catalog: bool = False,
2868
+ display_name: str | None = None,
2869
+ ignore_changes: bool = False,
2870
+ recreate_on_change: bool = False,
2871
+ __internal__: ResourceGraph | None = None,
2872
+ ):
2873
+ """
2874
+ Constructor.
2875
+
2876
+ :param name: Unique resource name assigned to the credential
2877
+ :param host: Host address of the database server.
2878
+ :param port: Port number to use to access the OpenEdge SQL Engine.
2879
+ :param database: Name of the OpenEdge database to connect to.
2880
+ This field is immutable; changing it requires recreating the
2881
+ credential.
2882
+ :param auth: Credentials to use for authentication.
2883
+ :param ssl_mode: Specifies which SSL mode the client operates in.
2884
+ :param tls_ca_certificate: Optional CA certificate (PEM format)
2885
+ used to verify the server certificate.
2886
+ :param certificate_name: Optional certificate name (CN/SAN) to
2887
+ expect in the server certificate. Set when it doesn't match
2888
+ the dialed host.
2889
+ :param enable_catalog: If set to true, this credential will
2890
+ be used to fetch catalog information.
2891
+ :param display_name: Human-readable name for the credential. This name is
2892
+ visible in the UI and does not need to be unique.
2893
+ :param ignore_changes: If set to true, changes to the resource will be ignored.
2894
+ :param recreate_on_change: If set to true, any change to the resource will
2895
+ cause it to be deleted and recreated instead of updated.
2896
+ """
2897
+ super().__init__(
2898
+ name=name,
2899
+ display_name=display_name,
2900
+ ignore_changes=ignore_changes,
2901
+ recreate_on_change=recreate_on_change,
2902
+ __internal__=__internal__,
2903
+ )
2904
+
2905
+ self.host = host
2906
+ self.port = port
2907
+ self.database = database
2908
+ self.auth = auth
2909
+ self.ssl_mode = _maybe_cast(ssl_mode, OpenEdgeSSLMode)
2910
+ self.tls_ca_certificate = tls_ca_certificate
2911
+ self.certificate_name = certificate_name
2912
+ self.enable_catalog = enable_catalog
2913
+
2914
+ def _immutable_fields(self) -> set[str]:
2915
+ return {"database"}
2916
+
2917
+ def _mutable_fields(self) -> set[str]:
2918
+ return {
2919
+ *super()._mutable_fields(),
2920
+ *{
2921
+ "host",
2922
+ "port",
2923
+ "ssl_mode",
2924
+ "tls_ca_certificate",
2925
+ "certificate_name",
2926
+ "enable_catalog",
2927
+ },
2928
+ }
2929
+
2930
+ def _secret_fields(self) -> set[str]:
2931
+ return set()
2932
+
2933
+ def _mutable_nested_objects(
2934
+ self,
2935
+ ) -> dict[str, "Diffable | list[Diffable] | None"]:
2936
+ return {"auth": self.auth}
2937
+
2938
+
2939
+ class SapIqCredentialUserPassword(ApiSecretChangeNestedResource):
2940
+ """SAP IQ credential via user-password auth."""
2941
+
2942
+ def __init__(
2943
+ self,
2944
+ user: str,
2945
+ password: str,
2946
+ ):
2947
+ """
2948
+ Constructor.
2949
+
2950
+ :param user: Username.
2951
+ :param password: Password.
2952
+ """
2953
+ self.user = user
2954
+ self.password = password
2955
+
2956
+ def _api_variant_name(self) -> str:
2957
+ return "userPassword"
2958
+
2959
+ def _immutable_fields(self) -> set[str]:
2960
+ return set({})
2961
+
2962
+ def _mutable_fields(self) -> set[str]:
2963
+ return {"user"}
2964
+
2965
+ def _secret_fields(self) -> set[str]:
2966
+ return {"password"}
2967
+
2968
+ def _mutable_nested_objects(
2969
+ self,
2970
+ ) -> dict[str, "Diffable | list[Diffable] | None"]:
2971
+ return {}
2972
+
2973
+
2974
+ SapIqCredentialAuth = Union[SapIqCredentialUserPassword]
2975
+
2976
+
2977
+ class SapIqCredential(Credential):
2978
+ """Credential to connect to SAP IQ."""
2979
+
2980
+ _feature = Feature.SAP_IQ
2981
+
2982
+ def __init__(
2983
+ self,
2984
+ *,
2985
+ name: str,
2986
+ host: str,
2987
+ port: int,
2988
+ server: str,
2989
+ auth: SapIqCredentialAuth,
2990
+ ssl_mode: SapIqSslMode,
2991
+ tls_ca_certificate: str | None = None,
2992
+ certificate_name: str | None = None,
2993
+ enable_catalog: bool = False,
2994
+ display_name: str | None = None,
2995
+ ignore_changes: bool = False,
2996
+ recreate_on_change: bool = False,
2997
+ __internal__: ResourceGraph | None = None,
2998
+ ):
2999
+ """
3000
+ Constructor.
3001
+
3002
+ :param name: Unique resource name assigned to the credential
3003
+ :param host: Host address of the server.
3004
+ :param port: Port number of the server.
3005
+ :param server: Server (engine) name to connect to.
3006
+ :param auth: Credentials to use for authentication.
3007
+ :param ssl_mode: Specifies which SSL mode the client operates in.
3008
+ :param tls_ca_certificate: Optional CA certificate (PEM format)
3009
+ used to verify the server certificate.
3010
+ :param certificate_name: Optional certificate name (CN/SAN) to
3011
+ expect in the server certificate. Set when it doesn't match
3012
+ the dialed host.
3013
+ :param enable_catalog: If set to true, this credential will
3014
+ be used to fetch catalog information.
3015
+ :param display_name: Human-readable name for the credential. This name is
3016
+ visible in the UI and does not need to be unique.
3017
+ :param ignore_changes: If set to true, changes to the resource will be ignored.
3018
+ :param recreate_on_change: If set to true, any change to the resource will
3019
+ cause it to be deleted and recreated instead of updated.
3020
+ """
3021
+ super().__init__(
3022
+ name=name,
3023
+ display_name=display_name,
3024
+ ignore_changes=ignore_changes,
3025
+ recreate_on_change=recreate_on_change,
3026
+ __internal__=__internal__,
3027
+ )
3028
+
3029
+ self.host = host
3030
+ self.port = port
3031
+ self.server = server
3032
+ self.auth = auth
3033
+ self.ssl_mode = _maybe_cast(ssl_mode, SapIqSslMode)
3034
+ self.tls_ca_certificate = tls_ca_certificate
3035
+ self.certificate_name = certificate_name
3036
+ self.enable_catalog = enable_catalog
3037
+
3038
+ def _immutable_fields(self) -> set[str]:
3039
+ return set({})
3040
+
3041
+ def _mutable_fields(self) -> set[str]:
3042
+ return {
3043
+ *super()._mutable_fields(),
3044
+ *{
3045
+ "host",
3046
+ "port",
3047
+ "server",
3048
+ "ssl_mode",
3049
+ "tls_ca_certificate",
3050
+ "certificate_name",
3051
+ "enable_catalog",
3052
+ },
3053
+ }
3054
+
3055
+ def _secret_fields(self) -> set[str]:
3056
+ return set()
3057
+
3058
+ def _mutable_nested_objects(
3059
+ self,
3060
+ ) -> dict[str, "Diffable | list[Diffable] | None"]:
3061
+ return {"auth": self.auth}
3062
+
3063
+
2794
3064
  class TeradataCredentialUserPassword(ApiSecretChangeNestedResource):
2795
3065
  """Teradata credential via user-password auth."""
2796
3066
 
@@ -2915,6 +3185,8 @@ WarehouseCredential = Union[
2915
3185
  IbmDb2Credential,
2916
3186
  PostgreSqlCredential,
2917
3187
  OracleCredential,
3188
+ OpenEdgeCredential,
3189
+ SapIqCredential,
2918
3190
  SnowflakeCredential,
2919
3191
  TeradataCredential,
2920
3192
  ]
@@ -11,6 +11,7 @@ import validio_sdk
11
11
  from validio_sdk._api.api import infer_schema, sql_source_preview
12
12
  from validio_sdk.client import Session
13
13
  from validio_sdk.exception import ValidioResourceError
14
+ from validio_sdk.features import Feature
14
15
  from validio_sdk.resource._diffable import Diffable
15
16
  from validio_sdk.resource._errors import ManifestConfigurationError
16
17
  from validio_sdk.resource._resource import Resource
@@ -36,8 +37,10 @@ from validio_sdk.resource.credentials import (
36
37
  IbmDb2Credential,
37
38
  KafkaCredential,
38
39
  MsSqlServerCredential,
40
+ OpenEdgeCredential,
39
41
  OracleCredential,
40
42
  PostgreSqlCredential,
43
+ SapIqCredential,
41
44
  SnowflakeCredential,
42
45
  TeradataCredential,
43
46
  WarehouseCredential,
@@ -1513,6 +1516,167 @@ class OracleSource(Source):
1513
1516
  }
1514
1517
 
1515
1518
 
1519
+ class OpenEdgeSource(Source):
1520
+ """A Progress OpenEdge source configuration."""
1521
+
1522
+ _feature = Feature.OPEN_EDGE
1523
+
1524
+ def __init__(
1525
+ self,
1526
+ *,
1527
+ name: str,
1528
+ credential: OpenEdgeCredential,
1529
+ schema: str,
1530
+ table: str,
1531
+ schedule: str | None,
1532
+ display_name: str | None = None,
1533
+ owner: str | None = None,
1534
+ ignore_changes: bool = False,
1535
+ recreate_on_change: bool = False,
1536
+ jtd_schema: JsonTypeDefinition | None = None,
1537
+ description: str | None = None,
1538
+ tags: list[Tag] | None = None,
1539
+ priority: IncidentGroupPriority | None = None,
1540
+ ):
1541
+ """
1542
+ Constructor.
1543
+
1544
+ :param schema: Name of the schema in the database.
1545
+ :param table: Name of table to monitor.
1546
+ :param schedule: A 5-digit cron expression specifying how when the source
1547
+ polls for new data. Example: '0 0 * * *' to poll daily at midnight.
1548
+ :param display_name: Human-readable name for the source. This name is
1549
+ visible in the UI and does not need to be unique.
1550
+ :param owner: User email address of the source owner.
1551
+ :param ignore_changes: If set to true, changes to the resource will be ignored.
1552
+ :param recreate_on_change: If set to true, any change to the resource will
1553
+ cause it to be deleted and recreated instead of updated.
1554
+ :param description: Description of the resource.
1555
+ :param tags: Tags to add to the resource
1556
+ :param priority: Priority to assign to incidents created by this source.
1557
+ """
1558
+ super().__init__(
1559
+ name=name,
1560
+ credential=credential,
1561
+ display_name=display_name,
1562
+ owner=owner,
1563
+ ignore_changes=ignore_changes,
1564
+ recreate_on_change=recreate_on_change,
1565
+ jtd_schema=jtd_schema,
1566
+ description=description,
1567
+ tags=tags,
1568
+ priority=priority,
1569
+ )
1570
+
1571
+ self.schema = schema
1572
+ self.table = table
1573
+ self.schedule = schedule
1574
+
1575
+ def _immutable_fields(self) -> set[str]:
1576
+ return {
1577
+ *super()._immutable_fields(),
1578
+ *{
1579
+ "schema",
1580
+ "table",
1581
+ },
1582
+ }
1583
+
1584
+ def _mutable_fields(self) -> set[str]:
1585
+ return {
1586
+ *super()._mutable_fields(),
1587
+ *{"schedule"},
1588
+ }
1589
+
1590
+ def _api_infer_schema_input(self) -> dict[str, object] | None:
1591
+ return {
1592
+ "schema": self.schema,
1593
+ "table": self.table,
1594
+ }
1595
+
1596
+
1597
+ class SapIqSource(Source):
1598
+ """A SAP IQ source configuration."""
1599
+
1600
+ _feature = Feature.SAP_IQ
1601
+
1602
+ def __init__(
1603
+ self,
1604
+ *,
1605
+ name: str,
1606
+ credential: SapIqCredential,
1607
+ database: str,
1608
+ schema: str,
1609
+ table: str,
1610
+ schedule: str | None,
1611
+ display_name: str | None = None,
1612
+ owner: str | None = None,
1613
+ ignore_changes: bool = False,
1614
+ recreate_on_change: bool = False,
1615
+ jtd_schema: JsonTypeDefinition | None = None,
1616
+ description: str | None = None,
1617
+ tags: list[Tag] | None = None,
1618
+ priority: IncidentGroupPriority | None = None,
1619
+ ):
1620
+ """
1621
+ Constructor.
1622
+
1623
+ :param database: Name of the database to connect to.
1624
+ :param schema: Name of the schema in the database.
1625
+ :param table: Name of table to monitor.
1626
+ :param schedule: A 5-digit cron expression specifying how when the source
1627
+ polls for new data. Example: '0 0 * * *' to poll daily at midnight.
1628
+ :param display_name: Human-readable name for the source. This name is
1629
+ visible in the UI and does not need to be unique.
1630
+ :param owner: User email address of the source owner.
1631
+ :param ignore_changes: If set to true, changes to the resource will be ignored.
1632
+ :param recreate_on_change: If set to true, any change to the resource will
1633
+ cause it to be deleted and recreated instead of updated.
1634
+ :param description: Description of the resource.
1635
+ :param tags: Tags to add to the resource
1636
+ :param priority: Priority to assign to incidents created by this source.
1637
+ """
1638
+ super().__init__(
1639
+ name=name,
1640
+ credential=credential,
1641
+ display_name=display_name,
1642
+ owner=owner,
1643
+ ignore_changes=ignore_changes,
1644
+ recreate_on_change=recreate_on_change,
1645
+ jtd_schema=jtd_schema,
1646
+ description=description,
1647
+ tags=tags,
1648
+ priority=priority,
1649
+ )
1650
+
1651
+ self.database = database
1652
+ self.schema = schema
1653
+ self.table = table
1654
+ self.schedule = schedule
1655
+
1656
+ def _immutable_fields(self) -> set[str]:
1657
+ return {
1658
+ *super()._immutable_fields(),
1659
+ *{
1660
+ "database",
1661
+ "schema",
1662
+ "table",
1663
+ },
1664
+ }
1665
+
1666
+ def _mutable_fields(self) -> set[str]:
1667
+ return {
1668
+ *super()._mutable_fields(),
1669
+ *{"schedule"},
1670
+ }
1671
+
1672
+ def _api_infer_schema_input(self) -> dict[str, object] | None:
1673
+ return {
1674
+ "database": self.database,
1675
+ "schema": self.schema,
1676
+ "table": self.table,
1677
+ }
1678
+
1679
+
1516
1680
  class TeradataSource(Source):
1517
1681
  """A Teradata source configuration."""
1518
1682
 
File without changes