validio-sdk 5.3.0__tar.gz → 5.3.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.
Files changed (55) hide show
  1. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/PKG-INFO +1 -1
  2. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/pyproject.toml +1 -1
  3. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/_api/api.py +0 -4
  4. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/code/_import.py +1 -1
  5. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/code/plan.py +1 -5
  6. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/_diff.py +1 -36
  7. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/_server_resources.py +5 -8
  8. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/channels.py +17 -94
  9. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/filters.py +26 -103
  10. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/tests/test__diff.py +3 -2
  11. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/tests/test__plan.py +0 -54
  12. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/tests/test__resource.py +0 -2
  13. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/validators.py +28 -114
  14. validio_sdk-5.3.0/validio_sdk/resource/tests/test__channel.py +0 -137
  15. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/LICENSE +0 -0
  16. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/README_PUBLIC.md +0 -0
  17. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/__init__.py +0 -0
  18. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/_api/__init__.py +0 -0
  19. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/client/__init__.py +0 -0
  20. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/client/client.py +0 -0
  21. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/code/__init__.py +0 -0
  22. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/code/_progress.py +0 -0
  23. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/code/apply.py +0 -0
  24. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/code/scaffold.py +0 -0
  25. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/code/settings.py +0 -0
  26. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/config.py +0 -0
  27. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/dbt.py +0 -0
  28. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/exception.py +0 -0
  29. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/metadata.py +0 -0
  30. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/py.typed +0 -0
  31. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/__init__.py +0 -0
  32. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/_diff_util.py +0 -0
  33. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/_diffable.py +0 -0
  34. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/_errors.py +0 -0
  35. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/_resource.py +0 -0
  36. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/_resource_graph.py +0 -0
  37. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/_serde.py +0 -0
  38. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/_update_namespace.py +0 -0
  39. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/_util.py +0 -0
  40. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/credentials.py +0 -0
  41. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/notification_rules.py +0 -0
  42. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/replacement.py +0 -0
  43. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/segmentations.py +0 -0
  44. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/sources.py +0 -0
  45. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/tags.py +0 -0
  46. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/tests/__init__.py +0 -0
  47. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/tests/assets/example_manifest.json +0 -0
  48. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/tests/assets/expected_trimmed_manifest.json +0 -0
  49. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/tests/test__dbt.py +0 -0
  50. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/tests/test__sql_validation.py +0 -0
  51. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/tests/test_import.py +0 -0
  52. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/thresholds.py +0 -0
  53. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/resource/windows.py +0 -0
  54. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/scalars.py +0 -0
  55. {validio_sdk-5.3.0 → validio_sdk-5.3.1}/validio_sdk/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: validio-sdk
3
- Version: 5.3.0
3
+ Version: 5.3.1
4
4
  Summary: SDK to interact with the Validio platform
5
5
  Home-page: https://validio.io/
6
6
  License: Apache-2.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 = "5.3.0"
6
+ version = "5.3.1"
7
7
  description = "SDK to interact with the Validio platform"
8
8
  authors = ["Validio <support@validio.io>"]
9
9
  license = "Apache-2.0"
@@ -1194,7 +1194,6 @@ async def get_channels(
1194
1194
  }
1195
1195
  ... on SlackChannel {
1196
1196
  config {
1197
- slackWebhookUrl: webhookUrl
1198
1197
  applicationLinkUrl
1199
1198
  slackChannelId
1200
1199
  interactiveMessageEnabled
@@ -1207,7 +1206,6 @@ async def get_channels(
1207
1206
  }
1208
1207
  ... on MsTeamsChannel {
1209
1208
  config {
1210
- msTeamsWebhookUrl: webhookUrl
1211
1209
  applicationLinkUrl
1212
1210
  msTeamsChannelId
1213
1211
  msTeamsInteractiveMessageEnabled: interactiveMessageEnabled
@@ -1276,8 +1274,6 @@ async def get_channels(
1276
1274
  _replace_aliases(
1277
1275
  ftr["config"],
1278
1276
  [
1279
- ("slackWebhookUrl", "webhookUrl"),
1280
- ("msTeamsWebhookUrl", "webhookUrl"),
1281
1277
  ("msTeamsInteractiveMessageEnabled", "interactiveMessageEnabled"),
1282
1278
  ("emailInteractiveMessageEnabled", "interactiveMessageEnabled"),
1283
1279
  ],
@@ -277,7 +277,7 @@ async def _import(
277
277
  ("tags", resource_tags(r), None),
278
278
  ]
279
279
 
280
- if v._filter_resource_mode() and v.filter_name:
280
+ if v.filter_name:
281
281
  filter_ = import_ctx.get_variable(Filter, v.filter_name)
282
282
  inits.append(("filter", filter_, None))
283
283
 
@@ -24,7 +24,7 @@ from validio_sdk.resource._resource import (
24
24
  )
25
25
  from validio_sdk.resource._server_resources import load_resources
26
26
  from validio_sdk.resource._util import SourceSchemaReinference
27
- from validio_sdk.resource.channels import Channel, WebhookChannel
27
+ from validio_sdk.resource.channels import WebhookChannel
28
28
  from validio_sdk.resource.tags import Tag
29
29
 
30
30
 
@@ -286,10 +286,6 @@ def _create_resource_diff_object(
286
286
  if not show_secrets and hasattr(r, "_secret_fields"):
287
287
  secret_fields = r._secret_fields()
288
288
 
289
- # Workaround for Channel having a special secret field
290
- if isinstance(r, Channel):
291
- secret_fields.update(r._deprecated_secret_fields())
292
-
293
289
  if secret_fields:
294
290
  for field in secret_fields:
295
291
  # We want to avoid overriding webhook_url if it is None already
@@ -26,7 +26,6 @@ from validio_sdk.resource._errors import (
26
26
  )
27
27
  from validio_sdk.resource._resource import CREATE_ONLY_RESOURCES, DiffContext, Resource
28
28
  from validio_sdk.resource._util import SourceSchemaReinference, _sanitize_error
29
- from validio_sdk.resource.channels import Channel
30
29
  from validio_sdk.resource.replacement import (
31
30
  CascadeReplacementReason,
32
31
  ImmutableFieldReplacementReason,
@@ -36,7 +35,6 @@ from validio_sdk.resource.replacement import (
36
35
  from validio_sdk.resource.segmentations import Segmentation
37
36
  from validio_sdk.resource.sources import Source
38
37
  from validio_sdk.resource.tags import Tag
39
- from validio_sdk.resource.validators import Reference, Validator
40
38
  from validio_sdk.resource.windows import TumblingWindow
41
39
 
42
40
  if TYPE_CHECKING:
@@ -254,8 +252,7 @@ def _visit_resource_to_replace(
254
252
  to_delete: dict[str, Resource] = getattr(graph_diff.to_delete, resource_type)
255
253
 
256
254
  # Remove the resource from the update list.
257
- if resource_name in to_update:
258
- del to_update[resource_name]
255
+ to_update.pop(resource_name, None)
259
256
 
260
257
  # Flag the resource to be created.
261
258
  manifest_resources: dict[str, Resource] = getattr(manifest_ctx, resource_type)
@@ -566,23 +563,6 @@ def diff(
566
563
  if isinstance(manifest_object, Resource) and manifest_object.ignore_changes:
567
564
  return None
568
565
 
569
- # NOTE: Backwards compatibility while we transition to Filter resources.
570
- # If we're about to diff a validator where the manifest validator still uses
571
- # the JSONFilterExpression mode, then force the server object to work
572
- # in the JSONFilterExpression mode so that we can compare the same fields.
573
- # Same for validator reference.
574
- if (
575
- isinstance(manifest_object, (Reference, Validator))
576
- and
577
- # NOTE: the server resource is always the Validator. Even if
578
- # the server object is potentially the nested 'Reference'.
579
- # This is mostly for type-checking.
580
- isinstance(server_resource, Validator)
581
- and isinstance(manifest_resource, Validator)
582
- ) and not manifest_object._filter_resource_mode():
583
- manifest_resource._force_filter_expression_mode()
584
- server_resource._force_filter_expression_mode()
585
-
586
566
  if isinstance(server_resource, Segmentation) and isinstance(
587
567
  manifest_resource, Segmentation
588
568
  ):
@@ -642,20 +622,6 @@ def diff(
642
622
  server = getattr(server_object, field)
643
623
 
644
624
  if manifest != server:
645
- # This is a temporary fix to support marking deprecated secret fields as
646
- # changed on a `Channel`. If the field is both in `_mutable_fields`
647
- # and also in `_deprecated_secret_fields` we will flag the field in
648
- # `secret_fields_changed` if there has been an update. This ensures
649
- # that the value is redacted by default when displaying the config.
650
- secret_fields_changed = None
651
- if (
652
- isinstance(manifest_object, Channel)
653
- and field in manifest_object._deprecated_secret_fields()
654
- ):
655
- secret_fields_changed = {
656
- field: True,
657
- }
658
-
659
625
  # Whenever we find there's a change to make, grab all fields on both
660
626
  # resource versions so that we can present them as a diff.
661
627
  # Regardless of at what depth we find a change, the diff we present
@@ -664,7 +630,6 @@ def diff(
664
630
  return ResourceUpdate(
665
631
  manifest_resource,
666
632
  server_resource,
667
- secret_fields_changed=secret_fields_changed,
668
633
  )
669
634
 
670
635
  # Some fields require the resource to be re-created if the type changes
@@ -498,7 +498,6 @@ async def load_channels(
498
498
 
499
499
  cfg = ch["config"]
500
500
  application_link_url = cfg["applicationLinkUrl"]
501
- unset_or_none = None if cfg.get("webhookUrl") else "UNSET"
502
501
  interactive_message_enabled = cfg.get("interactiveMessageEnabled", None)
503
502
  display_name = ch["name"]
504
503
  # The 'secret' parts of a channel are left unset since they are not
@@ -509,10 +508,9 @@ async def load_channels(
509
508
  name=name,
510
509
  application_link_url=application_link_url,
511
510
  ms_teams_channel_id=cfg["msTeamsChannelId"],
512
- client_id=unset_or_none,
513
- client_secret=unset_or_none,
511
+ client_id="UNSET",
512
+ client_secret="UNSET",
514
513
  interactive_message_enabled=interactive_message_enabled,
515
- webhook_url=cfg["webhookUrl"],
516
514
  display_name=display_name,
517
515
  __internal__=g,
518
516
  )
@@ -521,11 +519,10 @@ async def load_channels(
521
519
  name=name,
522
520
  application_link_url=application_link_url,
523
521
  slack_channel_id=cfg["slackChannelId"],
524
- token=unset_or_none,
525
- signing_secret=unset_or_none,
526
- app_token=unset_or_none,
522
+ token="UNSET",
523
+ signing_secret="UNSET",
524
+ app_token="UNSET",
527
525
  interactive_message_enabled=interactive_message_enabled,
528
- webhook_url=cfg["webhookUrl"],
529
526
  display_name=display_name,
530
527
  __internal__=g,
531
528
  )
@@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Any, Optional, Union, cast
5
5
 
6
6
  from camel_converter import to_camel
7
7
 
8
- from validio_sdk.resource._errors import ManifestConfigurationError
9
8
  from validio_sdk.resource._resource import (
10
9
  ApiSecretChangeNestedResource,
11
10
  Resource,
@@ -69,13 +68,6 @@ class Channel(Resource):
69
68
  self._resource_graph: ResourceGraph = g
70
69
  self._resource_graph._add_root(self)
71
70
 
72
- def _deprecated_secret_fields(self) -> set[str]:
73
- """Fields that are not supported when calling the secrets changed endpoint.
74
-
75
- :return: Set of secret fields that are deprecated
76
- """
77
- return set({})
78
-
79
71
  def _immutable_fields(self) -> set[str]:
80
72
  return set({})
81
73
 
@@ -107,7 +99,8 @@ class Channel(Resource):
107
99
  },
108
100
  }
109
101
  return _api_create_input_params(
110
- resource=self, overrides=overrides, skip_fields=self._api_skip_fields()
102
+ resource=self,
103
+ overrides=overrides,
111
104
  )
112
105
 
113
106
  def _api_update_input(self, _namespace: str, _ctx: "DiffContext") -> Any:
@@ -118,16 +111,10 @@ class Channel(Resource):
118
111
  }
119
112
  }
120
113
  return _api_update_input_params(
121
- resource=self, overrides=overrides, skip_fields=self._api_skip_fields()
114
+ resource=self,
115
+ overrides=overrides,
122
116
  )
123
117
 
124
- def _api_skip_fields(self) -> set[str]:
125
- return {
126
- to_camel(f)
127
- for f in self._deprecated_secret_fields()
128
- if not getattr(self, f, None)
129
- }
130
-
131
118
  @staticmethod
132
119
  def _decode(
133
120
  ctx: "DiffContext",
@@ -166,15 +153,6 @@ class Channel(Resource):
166
153
 
167
154
  return channel
168
155
 
169
- def _api_secret_change_response(
170
- self,
171
- ) -> dict[str, None | ApiSecretChangeNestedResource]:
172
- fields = super()._api_secret_change_response()
173
- for secret_field in self._deprecated_secret_fields():
174
- if secret_field in fields:
175
- del fields[secret_field]
176
- return fields
177
-
178
156
 
179
157
  class SlackChannel(Channel):
180
158
  """
@@ -188,12 +166,11 @@ class SlackChannel(Channel):
188
166
  *,
189
167
  name: str,
190
168
  application_link_url: str,
191
- slack_channel_id: str | None = None,
192
- token: str | None = None,
169
+ slack_channel_id: str,
170
+ token: str,
193
171
  signing_secret: str | None = None,
194
172
  app_token: str | None = None,
195
- interactive_message_enabled: bool | None = None,
196
- webhook_url: str | None = None,
173
+ interactive_message_enabled: bool = True,
197
174
  display_name: str | None = None,
198
175
  ignore_changes: bool = False,
199
176
  __internal__: ResourceGraph | None = None,
@@ -209,8 +186,6 @@ class SlackChannel(Channel):
209
186
  :param app_token: App level token used to retrieve user events from Slack.
210
187
  :param interactive_message_enabled: If interactive notification messages should
211
188
  be used.
212
- :param webhook_url: Webhook URL provided by Slack to the
213
- specified Slack channel. (deprecated)
214
189
  :param display_name: Human-readable name for the channel. This name is
215
190
  visible in the UI and does not need to be unique.
216
191
  :param ignore_changes: If set to true, changes to the resource will be ignored.
@@ -222,7 +197,6 @@ class SlackChannel(Channel):
222
197
  __internal__=__internal__,
223
198
  )
224
199
  self.application_link_url = application_link_url
225
- self.webhook_url = webhook_url
226
200
  self.slack_channel_id = slack_channel_id
227
201
  self.token = token
228
202
  self.signing_secret = signing_secret
@@ -232,34 +206,12 @@ class SlackChannel(Channel):
232
206
  if self.signing_secret:
233
207
  self.add_field_deprecation("signing_secret", "app_token")
234
208
 
235
- if webhook_url and (
236
- slack_channel_id
237
- or token
238
- or signing_secret
239
- or interactive_message_enabled
240
- or app_token
241
- ):
242
- raise ManifestConfigurationError(
243
- f"invalid configuration for Slack channel {self.name}: either"
244
- " webhook_url or slack_channel_id, token, app_token and"
245
- " interactive_message_enabled can be used."
246
- )
247
-
248
- if webhook_url:
249
- self.add_field_deprecation("webhook_url")
250
-
251
209
  def _secret_fields(self) -> set[str]:
252
- # If the webhook URL is set, we return an empty set so that the caller can
253
- # avoid calling the secrets changed endpoint as it's not supported
254
- return (
255
- set({})
256
- if self.webhook_url
257
- else {
258
- "app_token",
259
- "signing_secret",
260
- "token",
261
- }
262
- )
210
+ return {
211
+ "app_token",
212
+ "signing_secret",
213
+ "token",
214
+ }
263
215
 
264
216
  def _immutable_fields(self) -> set[str]:
265
217
  return set({})
@@ -271,13 +223,9 @@ class SlackChannel(Channel):
271
223
  "application_link_url",
272
224
  "slack_channel_id",
273
225
  "interactive_message_enabled",
274
- *self._deprecated_secret_fields(),
275
226
  },
276
227
  }
277
228
 
278
- def _deprecated_secret_fields(self) -> set[str]:
279
- return {"webhook_url"}
280
-
281
229
 
282
230
  class MsTeamsChannel(Channel):
283
231
  """
@@ -291,11 +239,10 @@ class MsTeamsChannel(Channel):
291
239
  *,
292
240
  name: str,
293
241
  application_link_url: str,
294
- ms_teams_channel_id: str | None = None,
295
- client_id: str | None = None,
296
- client_secret: str | None = None,
297
- interactive_message_enabled: bool | None = None,
298
- webhook_url: str | None = None,
242
+ ms_teams_channel_id: str,
243
+ client_id: str,
244
+ client_secret: str,
245
+ interactive_message_enabled: bool = True,
299
246
  display_name: str | None = None,
300
247
  ignore_changes: bool = False,
301
248
  __internal__: ResourceGraph | None = None,
@@ -310,8 +257,6 @@ class MsTeamsChannel(Channel):
310
257
  :param client_secret: Client secret for authentication.
311
258
  :param interactive_message_enabled: If interactive notification messages should
312
259
  be used.
313
- :param webhook_url: Webhook URL provided by Microsoft Teams to the
314
- specified channel. (deprecated)
315
260
  :param display_name: Human-readable name for the channel. This name is
316
261
  visible in the UI and does not need to be unique.
317
262
  :param ignore_changes: If set to true, changes to the resource will be ignored.
@@ -323,31 +268,13 @@ class MsTeamsChannel(Channel):
323
268
  __internal__=__internal__,
324
269
  )
325
270
  self.application_link_url = application_link_url
326
- self.webhook_url = webhook_url
327
271
  self.ms_teams_channel_id = ms_teams_channel_id
328
272
  self.client_id = client_id
329
273
  self.client_secret = client_secret
330
274
  self.interactive_message_enabled = interactive_message_enabled
331
275
 
332
- if webhook_url and (
333
- ms_teams_channel_id
334
- or client_id
335
- or client_secret
336
- or interactive_message_enabled
337
- ):
338
- raise ManifestConfigurationError(
339
- f"invalid configuration for MS Teams channel {self.name}: either"
340
- " webhook_url or ms_teams_channel_id, client_id, client_secret,"
341
- " and interactive_message_enabled can be used."
342
- )
343
-
344
- if webhook_url:
345
- self.add_field_deprecation("webhook_url")
346
-
347
276
  def _secret_fields(self) -> set[str]:
348
- # If the webhook URL is set, we return an empty set so that the caller can
349
- # avoid calling the secrets changed endpoint as it's not supported
350
- return set({}) if self.webhook_url else {"client_id", "client_secret"}
277
+ return {"client_id", "client_secret"}
351
278
 
352
279
  def _immutable_fields(self) -> set[str]:
353
280
  return set({})
@@ -359,13 +286,9 @@ class MsTeamsChannel(Channel):
359
286
  "application_link_url",
360
287
  "ms_teams_channel_id",
361
288
  "interactive_message_enabled",
362
- *self._deprecated_secret_fields(),
363
289
  },
364
290
  }
365
291
 
366
- def _deprecated_secret_fields(self) -> set[str]:
367
- return {"webhook_url"}
368
-
369
292
 
370
293
  class WebhookChannel(Channel):
371
294
  """
@@ -1,15 +1,12 @@
1
1
  """Filters configuration."""
2
2
 
3
- from abc import abstractmethod
4
3
  from enum import Enum
5
4
  from typing import TYPE_CHECKING, Any, Optional
6
5
 
7
6
  from validio_sdk.exception import ValidioBugError
8
7
  from validio_sdk.resource._diffable import Diffable
9
- from validio_sdk.resource._errors import ManifestConfigurationError
10
- from validio_sdk.resource._resource import Resource, ResourceGraph
8
+ from validio_sdk.resource._resource import Resource
11
9
  from validio_sdk.resource._serde import (
12
- CONFIG_FIELD_NAME,
13
10
  NODE_TYPE_FIELD_NAME,
14
11
  _api_create_input_params,
15
12
  _encode_resource,
@@ -21,10 +18,6 @@ if TYPE_CHECKING:
21
18
  from validio_sdk.resource.sources import Source
22
19
 
23
20
 
24
- # used to detect when we're in resource vs filter expression mode.
25
- DUMMY_NAME_PLACEHOLDER = "_validio_dummy_filter"
26
-
27
-
28
21
  class Filter(Resource):
29
22
  """
30
23
  Base class for a filter configuration.
@@ -34,8 +27,8 @@ class Filter(Resource):
34
27
 
35
28
  def __init__(
36
29
  self,
37
- name: str | None = None,
38
- source: Optional["Source"] = None,
30
+ name: str,
31
+ source: "Source",
39
32
  display_name: str | None = None,
40
33
  ignore_changes: bool = False,
41
34
  ):
@@ -48,28 +41,11 @@ class Filter(Resource):
48
41
  visible in the UI and does not need to be unique.
49
42
  :param ignore_changes: If set to true, changes to the resource will be ignored
50
43
  """
51
- # For backwards compatibility while we transition from
52
- # JSONFilterExpression to Filter resources, the Filter class
53
- # is able to optionally act as a resource.
54
- if (source is None) and (name is not None and name != DUMMY_NAME_PLACEHOLDER):
55
- raise ManifestConfigurationError(
56
- f"invalid {self.__class__.__name__}: "
57
- "name and source arguments must be provided together."
58
- )
59
-
60
- # If in JSONFilterExpression mode, we initialize the base
61
- # resource with an empty resource graph and a random name.
62
- # Both values are simply placeholders and are ignored in this
63
- # mode.
64
- resource_graph = (
65
- source._resource_graph if source is not None else ResourceGraph()
66
- )
67
-
68
44
  super().__init__(
69
- name=name or DUMMY_NAME_PLACEHOLDER,
45
+ name=name,
70
46
  display_name=display_name,
71
47
  ignore_changes=ignore_changes,
72
- __internal__=resource_graph,
48
+ __internal__=source._resource_graph,
73
49
  )
74
50
 
75
51
  # If in Resource mode, then we add it as usual to the graph
@@ -78,21 +54,11 @@ class Filter(Resource):
78
54
  self.source_name: str = source.name
79
55
  source.add(self.name, self)
80
56
 
81
- def _in_resource_mode(self) -> bool:
82
- """Returns true if the filter is in resource mode."""
83
- return self.name != DUMMY_NAME_PLACEHOLDER
84
-
85
57
  def _immutable_fields(self) -> set[str]:
86
- if self._in_resource_mode():
87
- return {"source_name"}
88
-
89
- return set({})
58
+ return {"source_name"}
90
59
 
91
60
  def _mutable_fields(self) -> set[str]:
92
- if self._in_resource_mode():
93
- return super()._mutable_fields()
94
-
95
- return set({})
61
+ return super()._mutable_fields()
96
62
 
97
63
  def _nested_objects(self) -> dict[str, Diffable | list[Diffable] | None]:
98
64
  return {}
@@ -101,24 +67,10 @@ class Filter(Resource):
101
67
  """Returns the base class name."""
102
68
  return "Filter"
103
69
 
104
- @abstractmethod
105
- def _scalar(self) -> dict[str, object]:
106
- """
107
- Returns the JsonFilterExpression representation of this filter.
108
- For backwards compatibility while we transition to filter resources.
109
- """
110
-
111
70
  def _encode(self) -> dict[str, object]:
112
- if self._in_resource_mode():
113
- # Drop fields here that are not part of the constructor for when
114
- # we deserialize back. They will be reinitialized by the constructor.
115
- return _encode_resource(self, skip_fields={"source_name"})
116
-
117
- data = self._scalar()
118
- data[NODE_TYPE_FIELD_NAME] = self.__class__.__name__
119
- data["name"] = self.name
120
-
121
- return data
71
+ # Drop fields here that are not part of the constructor for when we
72
+ # deserialize back. They will be reinitialized by the constructor.
73
+ return _encode_resource(self, skip_fields={"source_name"})
122
74
 
123
75
  @staticmethod
124
76
  def _decode(
@@ -127,17 +79,11 @@ class Filter(Resource):
127
79
  ) -> "Filter":
128
80
  cls = eval(obj[NODE_TYPE_FIELD_NAME])
129
81
 
130
- in_resource_mode = CONFIG_FIELD_NAME in obj
82
+ if source is None:
83
+ raise ValidioBugError("Missing source when decoding filter")
131
84
 
132
- if in_resource_mode:
133
- if source is None:
134
- raise ValidioBugError(
135
- "Missing source when decoding filter in resource mode"
136
- )
137
- args = get_config_node(obj)
138
- return cls(**{**args, "source": source})
139
-
140
- return cls(**{k: v for k, v in obj.items() if k != NODE_TYPE_FIELD_NAME})
85
+ args = get_config_node(obj)
86
+ return cls(**{**args, "source": source})
141
87
 
142
88
  def _api_create_input(self, _namespace: str, ctx: "DiffContext") -> dict[str, Any]:
143
89
  return _api_create_input_params(
@@ -145,9 +91,6 @@ class Filter(Resource):
145
91
  overrides={"sourceId": ctx.sources[self.source_name]._must_id()},
146
92
  )
147
93
 
148
- def _api_json_filter_expression_create_input(self) -> dict[str, Any]:
149
- return {"__typename": f"{self.__class__.__name__}Expression", **self._scalar()}
150
-
151
94
 
152
95
  class BooleanFilterOperator(str, Enum):
153
96
  """
@@ -172,8 +115,8 @@ class BooleanFilter(Filter):
172
115
  *,
173
116
  field: str,
174
117
  operator: BooleanFilterOperator,
175
- name: str | None = None,
176
- source: Optional["Source"] = None,
118
+ name: str,
119
+ source: "Source",
177
120
  display_name: str | None = None,
178
121
  ignore_changes: bool = False,
179
122
  ):
@@ -231,9 +174,9 @@ class NullFilter(Filter):
231
174
  self,
232
175
  *,
233
176
  field: str,
177
+ name: str,
178
+ source: "Source",
234
179
  operator: NullFilterOperator = NullFilterOperator.IS,
235
- name: str | None = None,
236
- source: Optional["Source"] = None,
237
180
  display_name: str | None = None,
238
181
  ignore_changes: bool = False,
239
182
  ):
@@ -265,9 +208,6 @@ class NullFilter(Filter):
265
208
  def _mutable_fields(self) -> set[str]:
266
209
  return {"field", "operator", *super()._mutable_fields()}
267
210
 
268
- def _scalar(self) -> dict[str, object]:
269
- return {"field": self.field, "operator": self.operator.value}
270
-
271
211
 
272
212
  class EnumFilterOperator(str, Enum):
273
213
  """
@@ -292,9 +232,9 @@ class EnumFilter(Filter):
292
232
  *,
293
233
  field: str,
294
234
  values: list[str],
235
+ name: str,
236
+ source: "Source",
295
237
  operator: EnumFilterOperator = EnumFilterOperator.ALLOW,
296
- name: str | None = None,
297
- source: Optional["Source"] = None,
298
238
  display_name: str | None = None,
299
239
  ignore_changes: bool = False,
300
240
  ):
@@ -375,9 +315,9 @@ class StringFilter(Filter):
375
315
  *,
376
316
  field: str,
377
317
  operator: StringFilterOperator,
318
+ name: str,
319
+ source: "Source",
378
320
  value: str | None = None,
379
- name: str | None = None,
380
- source: Optional["Source"] = None,
381
321
  display_name: str | None = None,
382
322
  ignore_changes: bool = False,
383
323
  ):
@@ -413,13 +353,6 @@ class StringFilter(Filter):
413
353
  def _mutable_fields(self) -> set[str]:
414
354
  return {"field", "operator", "value", *super()._mutable_fields()}
415
355
 
416
- def _scalar(self) -> dict[str, object]:
417
- return {
418
- "field": self.field,
419
- "value": self.value,
420
- "operator": self.operator.value,
421
- }
422
-
423
356
 
424
357
  class ThresholdFilterOperator(str, Enum):
425
358
  """
@@ -452,9 +385,9 @@ class ThresholdFilter(Filter):
452
385
  *,
453
386
  field: str,
454
387
  value: float,
388
+ name: str,
389
+ source: "Source",
455
390
  operator: ThresholdFilterOperator,
456
- name: str | None = None,
457
- source: Optional["Source"] = None,
458
391
  display_name: str | None = None,
459
392
  ignore_changes: bool = False,
460
393
  ):
@@ -489,13 +422,6 @@ class ThresholdFilter(Filter):
489
422
  def _mutable_fields(self) -> set[str]:
490
423
  return {"field", "operator", "value", *super()._mutable_fields()}
491
424
 
492
- def _scalar(self) -> dict[str, object]:
493
- return {
494
- "field": self.field,
495
- "value": self.value,
496
- "operator": self.operator.value,
497
- }
498
-
499
425
 
500
426
  class SqlFilter(Filter):
501
427
  """A SQL filter configuration.
@@ -507,8 +433,8 @@ class SqlFilter(Filter):
507
433
  self,
508
434
  *,
509
435
  query: str,
510
- name: str | None = None,
511
- source: Optional["Source"] = None,
436
+ name: str,
437
+ source: "Source",
512
438
  display_name: str | None = None,
513
439
  ignore_changes: bool = False,
514
440
  ):
@@ -535,6 +461,3 @@ class SqlFilter(Filter):
535
461
 
536
462
  def _mutable_fields(self) -> set[str]:
537
463
  return {"query", *super()._mutable_fields()}
538
-
539
- def _scalar(self) -> dict[str, object]:
540
- return {"query": self.query}