validio-sdk 7.4.0__tar.gz → 7.4.2__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-7.4.0 → validio_sdk-7.4.2}/PKG-INFO +1 -1
  2. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/pyproject.toml +1 -1
  3. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/_api/api.py +7 -0
  4. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/code/_import.py +10 -4
  5. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/_diffable.py +53 -1
  6. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/_resource.py +1 -1
  7. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/_server_resources.py +23 -1
  8. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/credentials.py +112 -12
  9. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/tests/test_import.py +24 -3
  10. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/LICENSE +0 -0
  11. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/README_PUBLIC.md +0 -0
  12. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/__init__.py +0 -0
  13. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/_api/__init__.py +0 -0
  14. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/client/__init__.py +0 -0
  15. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/client/client.py +0 -0
  16. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/code/__init__.py +0 -0
  17. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/code/_progress.py +0 -0
  18. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/code/apply.py +0 -0
  19. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/code/plan.py +0 -0
  20. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/code/scaffold.py +0 -0
  21. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/code/settings.py +0 -0
  22. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/config.py +0 -0
  23. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/dbt.py +0 -0
  24. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/exception.py +0 -0
  25. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/metadata.py +0 -0
  26. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/py.typed +0 -0
  27. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/__init__.py +0 -0
  28. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/_diff.py +0 -0
  29. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/_diff_util.py +0 -0
  30. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/_errors.py +0 -0
  31. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/_resource_graph.py +0 -0
  32. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/_serde.py +0 -0
  33. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/_update_namespace.py +0 -0
  34. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/_util.py +0 -0
  35. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/channels.py +0 -0
  36. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/enums.py +0 -0
  37. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/filters.py +0 -0
  38. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/notification_rules.py +0 -0
  39. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/replacement.py +0 -0
  40. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/segmentations.py +0 -0
  41. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/sources.py +0 -0
  42. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/tags.py +0 -0
  43. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/tests/__init__.py +0 -0
  44. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/tests/assets/example_manifest.json +0 -0
  45. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/tests/assets/expected_trimmed_manifest.json +0 -0
  46. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/tests/test__dbt.py +0 -0
  47. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/tests/test__diff.py +0 -0
  48. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/tests/test__plan.py +0 -0
  49. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/tests/test__resource.py +0 -0
  50. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/tests/test__sql_validation.py +0 -0
  51. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/thresholds.py +0 -0
  52. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/validators.py +0 -0
  53. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/resource/windows.py +0 -0
  54. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/scalars.py +0 -0
  55. {validio_sdk-7.4.0 → validio_sdk-7.4.2}/validio_sdk/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: validio-sdk
3
- Version: 7.4.0
3
+ Version: 7.4.2
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 = "7.4.0"
6
+ version = "7.4.2"
7
7
  description = "SDK to interact with the Validio platform"
8
8
  authors = ["Validio <support@validio.io>"]
9
9
  license = "Apache-2.0"
@@ -1023,6 +1023,12 @@ async def get_credentials(
1023
1023
  host
1024
1024
  port
1025
1025
  httpPath
1026
+ databricksAuth: auth {
1027
+ __typename
1028
+ ... on DatabricksCredentialOAuth {
1029
+ clientId
1030
+ }
1031
+ }
1026
1032
  }
1027
1033
  enableCatalog
1028
1034
  }
@@ -1242,6 +1248,7 @@ async def get_credentials(
1242
1248
  credential.get("config", {}),
1243
1249
  [
1244
1250
  ("powerBiAuth", "auth"),
1251
+ ("databricksAuth", "auth"),
1245
1252
  ("databaseRequired", "database"),
1246
1253
  ("optUser", "user"),
1247
1254
  ("optBaseUrl", "baseUrl"),
@@ -101,6 +101,7 @@ class ImportContext:
101
101
  async def _import(
102
102
  ctx: DiffContext,
103
103
  tags_ctx: DiffContext,
104
+ include_schema: bool = False,
104
105
  ) -> str:
105
106
  import_ctx = ImportContext()
106
107
 
@@ -189,16 +190,21 @@ async def _import(
189
190
  def import_sources(cls: type, name: str, r: Resource) -> None:
190
191
  credential = import_ctx.get_variable(Credential, cast(Any, r).credential_name)
191
192
 
193
+ inits: list[tuple[str, Any, str | None]] = [
194
+ ("credential", credential, None),
195
+ ("tags", resource_tags(r), None),
196
+ ]
197
+
198
+ if include_schema and isinstance(r, Source):
199
+ inits.append(("jtd_schema", r.jtd_schema, None))
200
+
192
201
  import_ctx.add_resource_decl(
193
202
  cls,
194
203
  name,
195
204
  r._import_str(
196
205
  indent_level=0,
197
206
  import_ctx=import_ctx,
198
- inits=[
199
- ("credential", credential, None),
200
- ("tags", resource_tags(r), None),
201
- ],
207
+ inits=inits,
202
208
  skip={"tag_names"},
203
209
  ),
204
210
  )
@@ -23,6 +23,12 @@ could enter a cycle.
23
23
  """
24
24
  MAX_RESOURCE_DEPTH = 15
25
25
 
26
+ """
27
+ When we format dictionaries this is the limit of how deep we can go to build a
28
+ formatted output.
29
+ """
30
+ MAX_FORMAT_DICT_DEPTH = 20
31
+
26
32
 
27
33
  class Diffable(ABC):
28
34
  """
@@ -162,8 +168,13 @@ class Diffable(ABC):
162
168
  import_args = []
163
169
 
164
170
  for field, arg, comment in sorted_params:
171
+ if isinstance(arg, dict):
172
+ value = _format_dict_value(arg, indent_level + 1, 0)
173
+ else:
174
+ value = arg
175
+
165
176
  comment_str = "" if not comment else f" # {comment}"
166
- import_args.append(f"{field}={arg},{comment_str}")
177
+ import_args.append(f"{field}={value},{comment_str}")
167
178
 
168
179
  params_str = line_indent.join(import_args)
169
180
  closing_indent = " " * self._num_ident_spaces(indent_level)
@@ -175,6 +186,39 @@ class Diffable(ABC):
175
186
  return 4 * indent_level
176
187
 
177
188
 
189
+ def _format_dict_value(value: Any, indent_level: int, recursion_depth: int) -> str:
190
+ """
191
+ Format dictionary for import.
192
+
193
+ This is only a best effort to try to wrap dict values instead of having a
194
+ long line for e.g. jtd schemas on import.
195
+ """
196
+ if recursion_depth >= MAX_FORMAT_DICT_DEPTH:
197
+ return value
198
+
199
+ indent = " " * (indent_level * 4)
200
+ if isinstance(value, dict):
201
+ if not value:
202
+ return "{}"
203
+
204
+ inner = indent + " " * 4
205
+
206
+ items = []
207
+ for k, v in value.items():
208
+ formatted = _format_dict_value(v, indent_level + 1, recursion_depth + 1)
209
+ items.append(f"{inner}'{k}': {formatted}")
210
+
211
+ return "{\n" + ",\n".join(items) + ",\n" + indent + "}"
212
+
213
+ if isinstance(value, bool):
214
+ return "True" if value else "False"
215
+
216
+ if value is None:
217
+ return "None"
218
+
219
+ return repr(value)
220
+
221
+
178
222
  class ApiSecretChangeNestedResource(Diffable):
179
223
  """An interface for nested structure inside a list of secret fields."""
180
224
 
@@ -195,6 +239,11 @@ class ApiSecretChangeNestedResource(Diffable):
195
239
  data[NODE_TYPE_FIELD_NAME] = self.__class__.__name__
196
240
  return data
197
241
 
242
+ def _nested_objects(
243
+ self,
244
+ ) -> dict[str, "Diffable | list[Diffable] | None"]:
245
+ return {}
246
+
198
247
  @staticmethod
199
248
  def _decode(
200
249
  type_: type,
@@ -218,6 +267,9 @@ class ApiSecretChangeNestedResource(Diffable):
218
267
  }
219
268
  }
220
269
 
270
+ def _api_secret_change_input(self) -> dict[str, Any]:
271
+ return self._api_input()
272
+
221
273
  def _api_secret_change_auth_query(self) -> str:
222
274
  """Returns the GraphQL query with fragments for the API secret change."""
223
275
  fields = "\n".join([to_camel(f) for f in self._secret_fields()])
@@ -546,7 +546,7 @@ class Resource(Diffable):
546
546
 
547
547
  def _api_secret_change_input(self) -> dict[str, Any]:
548
548
  nested_objects = {
549
- to_camel(f): obj._api_input()
549
+ to_camel(f): obj._api_secret_change_input()
550
550
  for f, obj in self._nested_secret_objects().items()
551
551
  }
552
552
 
@@ -50,6 +50,9 @@ from validio_sdk.resource.credentials import (
50
50
  ClickHouseCredential,
51
51
  Credential,
52
52
  DatabricksCredential,
53
+ DatabricksCredentialAuth,
54
+ DatabricksCredentialOAuth,
55
+ DatabricksCredentialPersonalAccessToken,
53
56
  DbtCloudCredential,
54
57
  DbtCoreCredential,
55
58
  DemoCredential,
@@ -326,12 +329,31 @@ async def load_credentials(
326
329
  __internal__=g,
327
330
  )
328
331
  case "DatabricksCredential":
332
+ access_token = None
333
+ auth: DatabricksCredentialAuth | None = None
334
+
335
+ auth_type_config = c.get("config", {}).get("auth", {}) or {}
336
+ auth_type = auth_type_config.get("__typename")
337
+
338
+ if auth_type == "DatabricksCredentialPersonalAccessToken":
339
+ auth = DatabricksCredentialPersonalAccessToken(token="UNSET")
340
+ elif auth_type == "DatabricksCredentialOAuth":
341
+ auth = DatabricksCredentialOAuth(
342
+ client_id=c["config"]["auth"]["clientId"],
343
+ client_secret="UNSET",
344
+ )
345
+ elif auth_type is None:
346
+ access_token = "UNSET"
347
+ else:
348
+ raise ValidioBugError(f"unknown auth type '{auth_type}'")
349
+
329
350
  credential = DatabricksCredential(
330
351
  name=name,
331
352
  host=c["config"]["host"],
332
353
  port=c["config"]["port"],
333
- access_token="UNSET",
334
354
  http_path=c["config"]["httpPath"],
355
+ access_token=access_token,
356
+ auth=auth,
335
357
  display_name=display_name,
336
358
  enable_catalog=c["enableCatalog"],
337
359
  __internal__=g,
@@ -8,6 +8,8 @@ from camel_converter import to_camel
8
8
 
9
9
  from validio_sdk._api.api import APIClient, test_credential
10
10
  from validio_sdk.client.client import Session
11
+ from validio_sdk.config import ValidioConfig
12
+ from validio_sdk.exception import ValidioError
11
13
  from validio_sdk.resource._resource import (
12
14
  ApiSecretChangeNestedResource,
13
15
  Resource,
@@ -749,11 +751,6 @@ class SnowflakeCredentialKeyPair(ApiSecretChangeNestedResource):
749
751
  def _secret_fields(self) -> set[str]:
750
752
  return {"private_key", "private_key_passphrase"}
751
753
 
752
- def _nested_objects(
753
- self,
754
- ) -> dict[str, "Diffable | list[Diffable] | None"]:
755
- return {}
756
-
757
754
 
758
755
  class SnowflakeCredentialUserPassword(ApiSecretChangeNestedResource):
759
756
  """Snowflake password-based authentication."""
@@ -785,11 +782,6 @@ class SnowflakeCredentialUserPassword(ApiSecretChangeNestedResource):
785
782
  def _secret_fields(self) -> set[str]:
786
783
  return {"password"}
787
784
 
788
- def _nested_objects(
789
- self,
790
- ) -> dict[str, "Diffable | list[Diffable] | None"]:
791
- return {}
792
-
793
785
 
794
786
  SnowflakeCredentialAuth = Union[
795
787
  SnowflakeCredentialKeyPair, SnowflakeCredentialUserPassword
@@ -1185,6 +1177,81 @@ class LookerCredential(Credential):
1185
1177
  return {"client_secret"}
1186
1178
 
1187
1179
 
1180
+ class DatabricksCredentialPersonalAccessToken(ApiSecretChangeNestedResource):
1181
+ """Databricks personal access token authentication."""
1182
+
1183
+ def __init__(
1184
+ self,
1185
+ *,
1186
+ token: str,
1187
+ ):
1188
+ """
1189
+ Constructor.
1190
+
1191
+ :param token: Databricks personal access token.
1192
+ """
1193
+ self.token = token
1194
+
1195
+ def _api_variant_name(self) -> str:
1196
+ return "personalAccessToken"
1197
+
1198
+ def _immutable_fields(self) -> set[str]:
1199
+ return set({})
1200
+
1201
+ def _mutable_fields(self) -> set[str]:
1202
+ return set({})
1203
+
1204
+ def _secret_fields(self) -> set[str]:
1205
+ return {"token"}
1206
+
1207
+
1208
+ class DatabricksCredentialOAuth(ApiSecretChangeNestedResource):
1209
+ """Databricks OAuth token authentication."""
1210
+
1211
+ def __init__(
1212
+ self,
1213
+ *,
1214
+ client_id: str,
1215
+ client_secret: str,
1216
+ ):
1217
+ """
1218
+ Constructor.
1219
+
1220
+ :param client_id: Databricks OAuth client ID.
1221
+ :param client_secret: Databricks OAuth client secret.
1222
+ """
1223
+ self.client_id = client_id
1224
+ self.client_secret = client_secret
1225
+
1226
+ def _api_variant_name(self) -> str:
1227
+ return "oauth"
1228
+
1229
+ def _immutable_fields(self) -> set[str]:
1230
+ return set({})
1231
+
1232
+ def _mutable_fields(self) -> set[str]:
1233
+ return {"client_id"}
1234
+
1235
+ def _secret_fields(self) -> set[str]:
1236
+ return {"client_secret"}
1237
+
1238
+ def _api_secret_change_input(self) -> dict[str, Any]:
1239
+ # We override this for Databricks since Databricks is the only one that
1240
+ # doesn't reuse the input type for creating credentials when checking if
1241
+ # secrets are changed. This mean we can use the API input as is, we need
1242
+ # to filter out non secrets.
1243
+ return {
1244
+ self._api_variant_name(): {
1245
+ to_camel(f): getattr(self, f) for f in self._secret_fields()
1246
+ }
1247
+ }
1248
+
1249
+
1250
+ DatabricksCredentialAuth = (
1251
+ DatabricksCredentialPersonalAccessToken | DatabricksCredentialOAuth
1252
+ )
1253
+
1254
+
1188
1255
  class DatabricksCredential(Credential):
1189
1256
  """A credential resource that can be used to connect to a Databricks table."""
1190
1257
 
@@ -1194,8 +1261,9 @@ class DatabricksCredential(Credential):
1194
1261
  name: str,
1195
1262
  host: str,
1196
1263
  port: int,
1197
- access_token: str,
1198
1264
  http_path: str,
1265
+ access_token: str | None = None,
1266
+ auth: DatabricksCredentialAuth | None = None,
1199
1267
  enable_catalog: bool = False,
1200
1268
  display_name: str | None = None,
1201
1269
  ignore_changes: bool = False,
@@ -1207,8 +1275,9 @@ class DatabricksCredential(Credential):
1207
1275
  :param name: Unique resource name assigned to the credential
1208
1276
  :param host: A host of Databricks deployment
1209
1277
  :param port: A port of Databricks deployment
1210
- :param access_token: An access token of system principal or a user
1211
1278
  :param http_path: Connection path of the compute resource to use.
1279
+ :param access_token: Deprecated.
1280
+ :param auth: Authentication method and config.
1212
1281
  :param enable_catalog: If set to true, this credential will
1213
1282
  be used to fetch catalog information.
1214
1283
  :param display_name: Human-readable name for the credential. This name is
@@ -1221,11 +1290,22 @@ class DatabricksCredential(Credential):
1221
1290
  ignore_changes=ignore_changes,
1222
1291
  __internal__=__internal__,
1223
1292
  )
1293
+
1294
+ if access_token and auth:
1295
+ raise ValidioError("only one of 'access_token' and 'auth' can be specified")
1296
+
1297
+ if not access_token and not auth:
1298
+ raise ValidioError("auth configuration missing")
1299
+
1300
+ if access_token:
1301
+ self.add_field_deprecation("access_token", "auth")
1302
+
1224
1303
  self.host = host
1225
1304
  self.port = port
1226
1305
  self.access_token = access_token
1227
1306
  self.http_path = http_path
1228
1307
  self.enable_catalog = enable_catalog
1308
+ self.auth = auth
1229
1309
 
1230
1310
  def _immutable_fields(self) -> set[str]:
1231
1311
  return set({})
@@ -1237,8 +1317,28 @@ class DatabricksCredential(Credential):
1237
1317
  }
1238
1318
 
1239
1319
  def _secret_fields(self) -> set[str]:
1320
+ # We must always include access token even when it's not used to ensure
1321
+ # we can go from the legacy way of using this to the new auth config.
1322
+ # When we pass auth we must also pass `access_token` as `null` to clear
1323
+ # it.
1240
1324
  return {"access_token"}
1241
1325
 
1326
+ def _nested_objects(
1327
+ self,
1328
+ ) -> dict[str, "Diffable | list[Diffable] | None"]:
1329
+ return {"auth": self.auth}
1330
+
1331
+ def _api_update_input(self, namespace: str, ctx: "DiffContext") -> Any:
1332
+ # Nested objects are not included in the input if they are `None` but we
1333
+ # want to pass `auth` in all requests to ensure we can go from the new
1334
+ # config (auth being set) to the old (access_token being set).
1335
+ #
1336
+ # Once we've dropped the legacy support we can also drop this override.
1337
+ if self.auth is None:
1338
+ return _api_update_input_params(self, overrides={"auth": None})
1339
+
1340
+ return super()._api_update_input(namespace, ctx)
1341
+
1242
1342
 
1243
1343
  class AzureSynapseCredential(Credential):
1244
1344
  """A base class of Azure Credential resource."""
@@ -165,7 +165,7 @@ notificationrule_0 = NotificationRule(
165
165
  assert doc.strip() == expected.strip()
166
166
 
167
167
 
168
- def test_import_sql_source() -> None:
168
+ def test_import_sql_source_with_include_schema() -> None:
169
169
  credential = PostgreSqlCredential(
170
170
  name="postgres",
171
171
  host="127.0.0.1",
@@ -188,7 +188,14 @@ def test_import_sql_source() -> None:
188
188
  "nullable": False,
189
189
  "optionalProperties": {},
190
190
  "properties": {
191
- "value": {"type": "int32"},
191
+ "value": {
192
+ "type": "int32",
193
+ "metadata": {
194
+ "json_path": "value",
195
+ "catalog_type": "NUMBER",
196
+ "sampled_field": False,
197
+ },
198
+ },
192
199
  },
193
200
  },
194
201
  )
@@ -224,6 +231,20 @@ source_0 = SqlSource(
224
231
  credential=credential_0,
225
232
  description=None,
226
233
  display_name='sql-source-postgres',
234
+ jtd_schema={
235
+ 'nullable': False,
236
+ 'optionalProperties': {},
237
+ 'properties': {
238
+ 'value': {
239
+ 'type': 'int32',
240
+ 'metadata': {
241
+ 'json_path': 'value',
242
+ 'catalog_type': 'NUMBER',
243
+ 'sampled_field': False,
244
+ },
245
+ },
246
+ },
247
+ },
227
248
  owner=None,
228
249
  priority=None,
229
250
  schedule='* * * * *',
@@ -240,7 +261,7 @@ source_0 = SqlSource(
240
261
  sources={source.name: source},
241
262
  )
242
263
 
243
- doc = asyncio.run(_import(ctx, DiffContext()))
264
+ doc = asyncio.run(_import(ctx, DiffContext(), include_schema=True))
244
265
 
245
266
  assert doc.strip() == expected.strip()
246
267
 
File without changes