dvt-core 1.11.0b4__py3-none-any.whl

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.

Potentially problematic release.


This version of dvt-core might be problematic. Click here for more details.

Files changed (261) hide show
  1. dvt/__init__.py +7 -0
  2. dvt/_pydantic_shim.py +26 -0
  3. dvt/adapters/__init__.py +16 -0
  4. dvt/adapters/multi_adapter_manager.py +268 -0
  5. dvt/artifacts/__init__.py +0 -0
  6. dvt/artifacts/exceptions/__init__.py +1 -0
  7. dvt/artifacts/exceptions/schemas.py +31 -0
  8. dvt/artifacts/resources/__init__.py +116 -0
  9. dvt/artifacts/resources/base.py +68 -0
  10. dvt/artifacts/resources/types.py +93 -0
  11. dvt/artifacts/resources/v1/analysis.py +10 -0
  12. dvt/artifacts/resources/v1/catalog.py +23 -0
  13. dvt/artifacts/resources/v1/components.py +275 -0
  14. dvt/artifacts/resources/v1/config.py +282 -0
  15. dvt/artifacts/resources/v1/documentation.py +11 -0
  16. dvt/artifacts/resources/v1/exposure.py +52 -0
  17. dvt/artifacts/resources/v1/function.py +53 -0
  18. dvt/artifacts/resources/v1/generic_test.py +32 -0
  19. dvt/artifacts/resources/v1/group.py +22 -0
  20. dvt/artifacts/resources/v1/hook.py +11 -0
  21. dvt/artifacts/resources/v1/macro.py +30 -0
  22. dvt/artifacts/resources/v1/metric.py +173 -0
  23. dvt/artifacts/resources/v1/model.py +146 -0
  24. dvt/artifacts/resources/v1/owner.py +10 -0
  25. dvt/artifacts/resources/v1/saved_query.py +112 -0
  26. dvt/artifacts/resources/v1/seed.py +42 -0
  27. dvt/artifacts/resources/v1/semantic_layer_components.py +72 -0
  28. dvt/artifacts/resources/v1/semantic_model.py +315 -0
  29. dvt/artifacts/resources/v1/singular_test.py +14 -0
  30. dvt/artifacts/resources/v1/snapshot.py +92 -0
  31. dvt/artifacts/resources/v1/source_definition.py +85 -0
  32. dvt/artifacts/resources/v1/sql_operation.py +10 -0
  33. dvt/artifacts/resources/v1/unit_test_definition.py +78 -0
  34. dvt/artifacts/schemas/__init__.py +0 -0
  35. dvt/artifacts/schemas/base.py +191 -0
  36. dvt/artifacts/schemas/batch_results.py +24 -0
  37. dvt/artifacts/schemas/catalog/__init__.py +12 -0
  38. dvt/artifacts/schemas/catalog/v1/__init__.py +0 -0
  39. dvt/artifacts/schemas/catalog/v1/catalog.py +60 -0
  40. dvt/artifacts/schemas/freshness/__init__.py +1 -0
  41. dvt/artifacts/schemas/freshness/v3/__init__.py +0 -0
  42. dvt/artifacts/schemas/freshness/v3/freshness.py +159 -0
  43. dvt/artifacts/schemas/manifest/__init__.py +2 -0
  44. dvt/artifacts/schemas/manifest/v12/__init__.py +0 -0
  45. dvt/artifacts/schemas/manifest/v12/manifest.py +212 -0
  46. dvt/artifacts/schemas/results.py +148 -0
  47. dvt/artifacts/schemas/run/__init__.py +2 -0
  48. dvt/artifacts/schemas/run/v5/__init__.py +0 -0
  49. dvt/artifacts/schemas/run/v5/run.py +184 -0
  50. dvt/artifacts/schemas/upgrades/__init__.py +4 -0
  51. dvt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
  52. dvt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
  53. dvt/artifacts/utils/validation.py +153 -0
  54. dvt/cli/__init__.py +1 -0
  55. dvt/cli/context.py +16 -0
  56. dvt/cli/exceptions.py +56 -0
  57. dvt/cli/flags.py +558 -0
  58. dvt/cli/main.py +971 -0
  59. dvt/cli/option_types.py +121 -0
  60. dvt/cli/options.py +79 -0
  61. dvt/cli/params.py +803 -0
  62. dvt/cli/requires.py +478 -0
  63. dvt/cli/resolvers.py +32 -0
  64. dvt/cli/types.py +40 -0
  65. dvt/clients/__init__.py +0 -0
  66. dvt/clients/checked_load.py +82 -0
  67. dvt/clients/git.py +164 -0
  68. dvt/clients/jinja.py +206 -0
  69. dvt/clients/jinja_static.py +245 -0
  70. dvt/clients/registry.py +192 -0
  71. dvt/clients/yaml_helper.py +68 -0
  72. dvt/compilation.py +833 -0
  73. dvt/compute/__init__.py +26 -0
  74. dvt/compute/base.py +288 -0
  75. dvt/compute/engines/__init__.py +13 -0
  76. dvt/compute/engines/duckdb_engine.py +368 -0
  77. dvt/compute/engines/spark_engine.py +273 -0
  78. dvt/compute/query_analyzer.py +212 -0
  79. dvt/compute/router.py +483 -0
  80. dvt/config/__init__.py +4 -0
  81. dvt/config/catalogs.py +95 -0
  82. dvt/config/compute_config.py +406 -0
  83. dvt/config/profile.py +411 -0
  84. dvt/config/profiles_v2.py +464 -0
  85. dvt/config/project.py +893 -0
  86. dvt/config/renderer.py +232 -0
  87. dvt/config/runtime.py +491 -0
  88. dvt/config/selectors.py +209 -0
  89. dvt/config/utils.py +78 -0
  90. dvt/connectors/.gitignore +6 -0
  91. dvt/connectors/README.md +306 -0
  92. dvt/connectors/catalog.yml +217 -0
  93. dvt/connectors/download_connectors.py +300 -0
  94. dvt/constants.py +29 -0
  95. dvt/context/__init__.py +0 -0
  96. dvt/context/base.py +746 -0
  97. dvt/context/configured.py +136 -0
  98. dvt/context/context_config.py +350 -0
  99. dvt/context/docs.py +82 -0
  100. dvt/context/exceptions_jinja.py +179 -0
  101. dvt/context/macro_resolver.py +195 -0
  102. dvt/context/macros.py +171 -0
  103. dvt/context/manifest.py +73 -0
  104. dvt/context/providers.py +2198 -0
  105. dvt/context/query_header.py +14 -0
  106. dvt/context/secret.py +59 -0
  107. dvt/context/target.py +74 -0
  108. dvt/contracts/__init__.py +0 -0
  109. dvt/contracts/files.py +413 -0
  110. dvt/contracts/graph/__init__.py +0 -0
  111. dvt/contracts/graph/manifest.py +1904 -0
  112. dvt/contracts/graph/metrics.py +98 -0
  113. dvt/contracts/graph/model_config.py +71 -0
  114. dvt/contracts/graph/node_args.py +42 -0
  115. dvt/contracts/graph/nodes.py +1806 -0
  116. dvt/contracts/graph/semantic_manifest.py +233 -0
  117. dvt/contracts/graph/unparsed.py +812 -0
  118. dvt/contracts/project.py +417 -0
  119. dvt/contracts/results.py +53 -0
  120. dvt/contracts/selection.py +23 -0
  121. dvt/contracts/sql.py +86 -0
  122. dvt/contracts/state.py +69 -0
  123. dvt/contracts/util.py +46 -0
  124. dvt/deprecations.py +347 -0
  125. dvt/deps/__init__.py +0 -0
  126. dvt/deps/base.py +153 -0
  127. dvt/deps/git.py +196 -0
  128. dvt/deps/local.py +80 -0
  129. dvt/deps/registry.py +131 -0
  130. dvt/deps/resolver.py +149 -0
  131. dvt/deps/tarball.py +121 -0
  132. dvt/docs/source/_ext/dbt_click.py +118 -0
  133. dvt/docs/source/conf.py +32 -0
  134. dvt/env_vars.py +64 -0
  135. dvt/event_time/event_time.py +40 -0
  136. dvt/event_time/sample_window.py +60 -0
  137. dvt/events/__init__.py +16 -0
  138. dvt/events/base_types.py +37 -0
  139. dvt/events/core_types_pb2.py +2 -0
  140. dvt/events/logging.py +109 -0
  141. dvt/events/types.py +2534 -0
  142. dvt/exceptions.py +1487 -0
  143. dvt/flags.py +89 -0
  144. dvt/graph/__init__.py +11 -0
  145. dvt/graph/cli.py +248 -0
  146. dvt/graph/graph.py +172 -0
  147. dvt/graph/queue.py +213 -0
  148. dvt/graph/selector.py +375 -0
  149. dvt/graph/selector_methods.py +976 -0
  150. dvt/graph/selector_spec.py +223 -0
  151. dvt/graph/thread_pool.py +18 -0
  152. dvt/hooks.py +21 -0
  153. dvt/include/README.md +49 -0
  154. dvt/include/__init__.py +3 -0
  155. dvt/include/global_project.py +4 -0
  156. dvt/include/starter_project/.gitignore +4 -0
  157. dvt/include/starter_project/README.md +15 -0
  158. dvt/include/starter_project/__init__.py +3 -0
  159. dvt/include/starter_project/analyses/.gitkeep +0 -0
  160. dvt/include/starter_project/dvt_project.yml +36 -0
  161. dvt/include/starter_project/macros/.gitkeep +0 -0
  162. dvt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
  163. dvt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
  164. dvt/include/starter_project/models/example/schema.yml +21 -0
  165. dvt/include/starter_project/seeds/.gitkeep +0 -0
  166. dvt/include/starter_project/snapshots/.gitkeep +0 -0
  167. dvt/include/starter_project/tests/.gitkeep +0 -0
  168. dvt/internal_deprecations.py +27 -0
  169. dvt/jsonschemas/__init__.py +3 -0
  170. dvt/jsonschemas/jsonschemas.py +309 -0
  171. dvt/jsonschemas/project/0.0.110.json +4717 -0
  172. dvt/jsonschemas/project/0.0.85.json +2015 -0
  173. dvt/jsonschemas/resources/0.0.110.json +2636 -0
  174. dvt/jsonschemas/resources/0.0.85.json +2536 -0
  175. dvt/jsonschemas/resources/latest.json +6773 -0
  176. dvt/links.py +4 -0
  177. dvt/materializations/__init__.py +0 -0
  178. dvt/materializations/incremental/__init__.py +0 -0
  179. dvt/materializations/incremental/microbatch.py +235 -0
  180. dvt/mp_context.py +8 -0
  181. dvt/node_types.py +37 -0
  182. dvt/parser/__init__.py +23 -0
  183. dvt/parser/analysis.py +21 -0
  184. dvt/parser/base.py +549 -0
  185. dvt/parser/common.py +267 -0
  186. dvt/parser/docs.py +52 -0
  187. dvt/parser/fixtures.py +51 -0
  188. dvt/parser/functions.py +30 -0
  189. dvt/parser/generic_test.py +100 -0
  190. dvt/parser/generic_test_builders.py +334 -0
  191. dvt/parser/hooks.py +119 -0
  192. dvt/parser/macros.py +137 -0
  193. dvt/parser/manifest.py +2204 -0
  194. dvt/parser/models.py +574 -0
  195. dvt/parser/partial.py +1179 -0
  196. dvt/parser/read_files.py +445 -0
  197. dvt/parser/schema_generic_tests.py +423 -0
  198. dvt/parser/schema_renderer.py +111 -0
  199. dvt/parser/schema_yaml_readers.py +936 -0
  200. dvt/parser/schemas.py +1467 -0
  201. dvt/parser/search.py +149 -0
  202. dvt/parser/seeds.py +28 -0
  203. dvt/parser/singular_test.py +20 -0
  204. dvt/parser/snapshots.py +44 -0
  205. dvt/parser/sources.py +557 -0
  206. dvt/parser/sql.py +63 -0
  207. dvt/parser/unit_tests.py +622 -0
  208. dvt/plugins/__init__.py +20 -0
  209. dvt/plugins/contracts.py +10 -0
  210. dvt/plugins/exceptions.py +2 -0
  211. dvt/plugins/manager.py +164 -0
  212. dvt/plugins/manifest.py +21 -0
  213. dvt/profiler.py +20 -0
  214. dvt/py.typed +1 -0
  215. dvt/runners/__init__.py +2 -0
  216. dvt/runners/exposure_runner.py +7 -0
  217. dvt/runners/no_op_runner.py +46 -0
  218. dvt/runners/saved_query_runner.py +7 -0
  219. dvt/selected_resources.py +8 -0
  220. dvt/task/__init__.py +0 -0
  221. dvt/task/base.py +504 -0
  222. dvt/task/build.py +197 -0
  223. dvt/task/clean.py +57 -0
  224. dvt/task/clone.py +162 -0
  225. dvt/task/compile.py +151 -0
  226. dvt/task/compute.py +366 -0
  227. dvt/task/debug.py +650 -0
  228. dvt/task/deps.py +280 -0
  229. dvt/task/docs/__init__.py +3 -0
  230. dvt/task/docs/generate.py +408 -0
  231. dvt/task/docs/index.html +250 -0
  232. dvt/task/docs/serve.py +28 -0
  233. dvt/task/freshness.py +323 -0
  234. dvt/task/function.py +122 -0
  235. dvt/task/group_lookup.py +46 -0
  236. dvt/task/init.py +374 -0
  237. dvt/task/list.py +237 -0
  238. dvt/task/printer.py +176 -0
  239. dvt/task/profiles.py +256 -0
  240. dvt/task/retry.py +175 -0
  241. dvt/task/run.py +1146 -0
  242. dvt/task/run_operation.py +142 -0
  243. dvt/task/runnable.py +802 -0
  244. dvt/task/seed.py +104 -0
  245. dvt/task/show.py +150 -0
  246. dvt/task/snapshot.py +57 -0
  247. dvt/task/sql.py +111 -0
  248. dvt/task/test.py +464 -0
  249. dvt/tests/fixtures/__init__.py +1 -0
  250. dvt/tests/fixtures/project.py +620 -0
  251. dvt/tests/util.py +651 -0
  252. dvt/tracking.py +529 -0
  253. dvt/utils/__init__.py +3 -0
  254. dvt/utils/artifact_upload.py +151 -0
  255. dvt/utils/utils.py +408 -0
  256. dvt/version.py +249 -0
  257. dvt_core-1.11.0b4.dist-info/METADATA +252 -0
  258. dvt_core-1.11.0b4.dist-info/RECORD +261 -0
  259. dvt_core-1.11.0b4.dist-info/WHEEL +5 -0
  260. dvt_core-1.11.0b4.dist-info/entry_points.txt +2 -0
  261. dvt_core-1.11.0b4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,309 @@
1
+ import json
2
+ import os
3
+ import re
4
+ from datetime import date, datetime
5
+ from pathlib import Path
6
+ from typing import Any, Dict, Iterator, List, Optional, Union
7
+
8
+ import jsonschema
9
+ from dvt import deprecations
10
+ from dvt.jsonschemas import JSONSCHEMAS_PATH
11
+ from jsonschema import ValidationError
12
+ from jsonschema._keywords import type as type_rule
13
+ from jsonschema.validators import Draft7Validator, extend
14
+
15
+ from dbt_common.context import get_invocation_context
16
+
17
+ _PROJECT_SCHEMA: Optional[Dict[str, Any]] = None
18
+ _RESOURCES_SCHEMA: Optional[Dict[str, Any]] = None
19
+
20
+ _JSONSCHEMA_SUPPORTED_ADAPTERS = {
21
+ "bigquery",
22
+ "databricks",
23
+ "redshift",
24
+ "snowflake",
25
+ }
26
+
27
+ _HIERARCHICAL_CONFIG_KEYS = {
28
+ "seeds",
29
+ "sources",
30
+ "models",
31
+ "snapshots",
32
+ "tests",
33
+ "exposures",
34
+ "data_tests",
35
+ "metrics",
36
+ "saved_queries",
37
+ "semantic_models",
38
+ "unit_tests",
39
+ }
40
+
41
+
42
+ def load_json_from_package(jsonschema_type: str, filename: str) -> Dict[str, Any]:
43
+ """Loads a JSON file from within a package."""
44
+
45
+ path = Path(JSONSCHEMAS_PATH).joinpath(jsonschema_type, filename)
46
+ data = path.read_bytes()
47
+ return json.loads(data)
48
+
49
+
50
+ def project_schema() -> Dict[str, Any]:
51
+ global _PROJECT_SCHEMA
52
+
53
+ if _PROJECT_SCHEMA is None:
54
+ _PROJECT_SCHEMA = load_json_from_package(
55
+ jsonschema_type="project", filename="0.0.110.json"
56
+ )
57
+ return _PROJECT_SCHEMA
58
+
59
+
60
+ def resources_schema() -> Dict[str, Any]:
61
+ global _RESOURCES_SCHEMA
62
+
63
+ if _RESOURCES_SCHEMA is None:
64
+ _RESOURCES_SCHEMA = load_json_from_package(
65
+ jsonschema_type="resources", filename="latest.json"
66
+ )
67
+
68
+ return _RESOURCES_SCHEMA
69
+
70
+
71
+ def custom_type_rule(validator, types, instance, schema):
72
+ """This is necessary because PyYAML loads things that look like dates or datetimes as those
73
+ python objects. Then jsonschema.validate() fails because it expects strings.
74
+ """
75
+ if "string" in types and (isinstance(instance, datetime) or isinstance(instance, date)):
76
+ return
77
+ else:
78
+ return type_rule(validator, types, instance, schema)
79
+
80
+
81
+ CustomDraft7Validator = extend(Draft7Validator, validators={"type": custom_type_rule})
82
+
83
+
84
+ def error_path_to_string(error: jsonschema.ValidationError) -> str:
85
+ if len(error.path) == 0:
86
+ return ""
87
+ else:
88
+ path = str(error.path.popleft())
89
+ for part in error.path:
90
+ if isinstance(part, int):
91
+ path += f"[{part}]"
92
+ else:
93
+ path += f".{part}"
94
+
95
+ return path
96
+
97
+
98
+ def _additional_properties_violation_keys(error: ValidationError) -> List[str]:
99
+ found_keys = re.findall(r"'\S+'", error.message)
100
+ return [key.strip("'") for key in found_keys]
101
+
102
+
103
+ def _validate_with_schema(
104
+ schema: Dict[str, Any], json: Dict[str, Any]
105
+ ) -> Iterator[ValidationError]:
106
+ validator = CustomDraft7Validator(schema)
107
+ return validator.iter_errors(json)
108
+
109
+
110
+ def _get_allowed_config_fields_from_error_path(
111
+ yml_schema: Dict[str, Any], error_path: List[Union[str, int]]
112
+ ) -> Optional[List[str]]:
113
+ property_field_name = None
114
+ node_schema = yml_schema["properties"]
115
+ for part in error_path:
116
+ if isinstance(part, str):
117
+ if part in node_schema:
118
+ if "items" not in node_schema[part]:
119
+ break
120
+
121
+ # Update property field name
122
+ property_field_name = node_schema[part]["items"]["$ref"].split("/")[-1]
123
+
124
+ # Jump to the next level of the schema
125
+ item_definition = node_schema[part]["items"]["$ref"].split("/")[-1]
126
+ node_schema = yml_schema["definitions"][item_definition]["properties"]
127
+
128
+ if not property_field_name:
129
+ return None
130
+
131
+ if "config" not in yml_schema["definitions"][property_field_name]["properties"]:
132
+ return None
133
+
134
+ config_field_name = yml_schema["definitions"][property_field_name]["properties"]["config"][
135
+ "anyOf"
136
+ ][0]["$ref"].split("/")[-1]
137
+
138
+ allowed_config_fields = list(set(yml_schema["definitions"][config_field_name]["properties"]))
139
+
140
+ return allowed_config_fields
141
+
142
+
143
+ def _can_run_validations() -> bool:
144
+ if not os.environ.get("DBT_ENV_PRIVATE_RUN_JSONSCHEMA_VALIDATIONS"):
145
+ return False
146
+
147
+ invocation_context = get_invocation_context()
148
+ return invocation_context.adapter_types.issubset(_JSONSCHEMA_SUPPORTED_ADAPTERS)
149
+
150
+
151
+ def jsonschema_validate(schema: Dict[str, Any], json: Dict[str, Any], file_path: str) -> None:
152
+ if not _can_run_validations():
153
+ return
154
+
155
+ errors = _validate_with_schema(schema, json)
156
+ for error in errors:
157
+ # Listify the error path to make it easier to work with (it's a deque in the ValidationError object)
158
+ error_path = list(error.path)
159
+ if error.validator == "additionalProperties":
160
+ keys = _additional_properties_violation_keys(error)
161
+ if len(error.path) == 0:
162
+ for key in keys:
163
+ deprecations.warn(
164
+ "custom-top-level-key-deprecation",
165
+ msg="Unexpected top-level key" + (" " + key if key else ""),
166
+ file=file_path,
167
+ )
168
+ else:
169
+ key_path = error_path_to_string(error)
170
+ for key in keys:
171
+ if key == "overrides" and key_path.startswith("sources"):
172
+
173
+ deprecations.warn(
174
+ "source-override-deprecation",
175
+ source_name=key_path.split(".")[-1],
176
+ file=file_path,
177
+ )
178
+ else:
179
+ allowed_config_fields = _get_allowed_config_fields_from_error_path(
180
+ schema, error_path
181
+ )
182
+ if allowed_config_fields and key in allowed_config_fields:
183
+ deprecations.warn(
184
+ "property-moved-to-config-deprecation",
185
+ key=key,
186
+ file=file_path,
187
+ key_path=key_path,
188
+ )
189
+ else:
190
+ deprecations.warn(
191
+ "custom-key-in-object-deprecation",
192
+ key=key,
193
+ file=file_path,
194
+ key_path=key_path,
195
+ )
196
+ elif error.validator == "anyOf" and len(error_path) > 0:
197
+ sub_errors = error.context or []
198
+ # schema yaml resource configs
199
+ if error_path[-1] == "config":
200
+ for sub_error in sub_errors:
201
+ if (
202
+ isinstance(sub_error, ValidationError)
203
+ and sub_error.validator == "additionalProperties"
204
+ ):
205
+ keys = _additional_properties_violation_keys(sub_error)
206
+ key_path = error_path_to_string(error)
207
+ for key in keys:
208
+ deprecations.warn(
209
+ "custom-key-in-config-deprecation",
210
+ key=key,
211
+ file=file_path,
212
+ key_path=key_path,
213
+ )
214
+ # dbt_project.yml configs
215
+ elif "dbt_project.yml" in file_path and error_path[0] in _HIERARCHICAL_CONFIG_KEYS:
216
+ for sub_error in sub_errors:
217
+ if isinstance(sub_error, ValidationError) and sub_error.validator == "type":
218
+ # Only raise type-errors if they are indicating leaf config without a plus prefix
219
+ if (
220
+ len(sub_error.path) > 0
221
+ and isinstance(sub_error.path[-1], str)
222
+ and not sub_error.path[-1].startswith("+")
223
+ ):
224
+ deprecations.warn(
225
+ "missing-plus-prefix-in-config-deprecation",
226
+ key=sub_error.path[-1],
227
+ file=file_path,
228
+ key_path=error_path_to_string(sub_error),
229
+ )
230
+ elif error.validator == "type":
231
+ # Not deprecating invalid types yet
232
+ pass
233
+ else:
234
+ deprecations.warn(
235
+ "generic-json-schema-validation-deprecation",
236
+ violation=error.message,
237
+ file=file_path,
238
+ key_path=error_path_to_string(error),
239
+ )
240
+
241
+
242
+ def validate_model_config(config: Dict[str, Any], file_path: str) -> None:
243
+ if not _can_run_validations():
244
+ return
245
+
246
+ resources_jsonschema = resources_schema()
247
+ nested_definition_name = "ModelConfig"
248
+
249
+ model_config_schema = {
250
+ "$schema": "http://json-schema.org/draft-07/schema#",
251
+ "title": nested_definition_name,
252
+ **resources_jsonschema["definitions"][nested_definition_name],
253
+ "definitions": {
254
+ k: v
255
+ for k, v in resources_jsonschema["definitions"].items()
256
+ if k != nested_definition_name
257
+ },
258
+ }
259
+
260
+ errors = _validate_with_schema(model_config_schema, config)
261
+ for error in errors:
262
+ error_path = list(error.path)
263
+ if error.validator == "additionalProperties":
264
+ keys = _additional_properties_violation_keys(error)
265
+ if len(error.path) == 0:
266
+ key_path = error_path_to_string(error)
267
+ for key in keys:
268
+ deprecations.warn(
269
+ "custom-key-in-config-deprecation",
270
+ key=key,
271
+ file=file_path,
272
+ key_path=key_path,
273
+ )
274
+ else:
275
+ error.path.appendleft("config")
276
+ key_path = error_path_to_string(error)
277
+ for key in keys:
278
+ deprecations.warn(
279
+ "custom-key-in-object-deprecation",
280
+ key=key,
281
+ file=file_path,
282
+ key_path=key_path,
283
+ )
284
+ elif error.validator == "type":
285
+ # Not deprecating invalid types yet, except for pre-existing deprecation_date deprecation
286
+ pass
287
+ elif error.validator == "anyOf" and len(error_path) > 0:
288
+ for sub_error in error.context or []:
289
+ if (
290
+ isinstance(sub_error, ValidationError)
291
+ and sub_error.validator == "additionalProperties"
292
+ ):
293
+ error.path.appendleft("config")
294
+ keys = _additional_properties_violation_keys(sub_error)
295
+ key_path = error_path_to_string(error)
296
+ for key in keys:
297
+ deprecations.warn(
298
+ "custom-key-in-object-deprecation",
299
+ key=key,
300
+ file=file_path,
301
+ key_path=key_path,
302
+ )
303
+ else:
304
+ deprecations.warn(
305
+ "generic-json-schema-validation-deprecation",
306
+ violation=error.message,
307
+ file=file_path,
308
+ key_path=error_path_to_string(error),
309
+ )