chalkpy 2.89.22__py3-none-any.whl → 2.95.3__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.
Files changed (268) hide show
  1. chalk/__init__.py +2 -1
  2. chalk/_gen/chalk/arrow/v1/arrow_pb2.py +7 -5
  3. chalk/_gen/chalk/arrow/v1/arrow_pb2.pyi +6 -0
  4. chalk/_gen/chalk/artifacts/v1/chart_pb2.py +36 -33
  5. chalk/_gen/chalk/artifacts/v1/chart_pb2.pyi +41 -1
  6. chalk/_gen/chalk/artifacts/v1/cron_query_pb2.py +8 -7
  7. chalk/_gen/chalk/artifacts/v1/cron_query_pb2.pyi +5 -0
  8. chalk/_gen/chalk/common/v1/offline_query_pb2.py +19 -13
  9. chalk/_gen/chalk/common/v1/offline_query_pb2.pyi +37 -0
  10. chalk/_gen/chalk/common/v1/online_query_pb2.py +54 -54
  11. chalk/_gen/chalk/common/v1/online_query_pb2.pyi +13 -1
  12. chalk/_gen/chalk/common/v1/script_task_pb2.py +13 -11
  13. chalk/_gen/chalk/common/v1/script_task_pb2.pyi +19 -1
  14. chalk/_gen/chalk/dataframe/__init__.py +0 -0
  15. chalk/_gen/chalk/dataframe/v1/__init__.py +0 -0
  16. chalk/_gen/chalk/dataframe/v1/dataframe_pb2.py +48 -0
  17. chalk/_gen/chalk/dataframe/v1/dataframe_pb2.pyi +123 -0
  18. chalk/_gen/chalk/dataframe/v1/dataframe_pb2_grpc.py +4 -0
  19. chalk/_gen/chalk/dataframe/v1/dataframe_pb2_grpc.pyi +4 -0
  20. chalk/_gen/chalk/graph/v1/graph_pb2.py +150 -149
  21. chalk/_gen/chalk/graph/v1/graph_pb2.pyi +25 -0
  22. chalk/_gen/chalk/graph/v1/sources_pb2.py +94 -84
  23. chalk/_gen/chalk/graph/v1/sources_pb2.pyi +56 -0
  24. chalk/_gen/chalk/kubernetes/v1/horizontalpodautoscaler_pb2.py +79 -0
  25. chalk/_gen/chalk/kubernetes/v1/horizontalpodautoscaler_pb2.pyi +377 -0
  26. chalk/_gen/chalk/kubernetes/v1/horizontalpodautoscaler_pb2_grpc.py +4 -0
  27. chalk/_gen/chalk/kubernetes/v1/horizontalpodautoscaler_pb2_grpc.pyi +4 -0
  28. chalk/_gen/chalk/kubernetes/v1/scaledobject_pb2.py +43 -7
  29. chalk/_gen/chalk/kubernetes/v1/scaledobject_pb2.pyi +252 -2
  30. chalk/_gen/chalk/protosql/v1/sql_service_pb2.py +54 -27
  31. chalk/_gen/chalk/protosql/v1/sql_service_pb2.pyi +131 -3
  32. chalk/_gen/chalk/protosql/v1/sql_service_pb2_grpc.py +45 -0
  33. chalk/_gen/chalk/protosql/v1/sql_service_pb2_grpc.pyi +14 -0
  34. chalk/_gen/chalk/python/v1/types_pb2.py +14 -14
  35. chalk/_gen/chalk/python/v1/types_pb2.pyi +8 -0
  36. chalk/_gen/chalk/server/v1/benchmark_pb2.py +76 -0
  37. chalk/_gen/chalk/server/v1/benchmark_pb2.pyi +156 -0
  38. chalk/_gen/chalk/server/v1/benchmark_pb2_grpc.py +258 -0
  39. chalk/_gen/chalk/server/v1/benchmark_pb2_grpc.pyi +84 -0
  40. chalk/_gen/chalk/server/v1/billing_pb2.py +40 -38
  41. chalk/_gen/chalk/server/v1/billing_pb2.pyi +17 -1
  42. chalk/_gen/chalk/server/v1/branches_pb2.py +45 -0
  43. chalk/_gen/chalk/server/v1/branches_pb2.pyi +80 -0
  44. chalk/_gen/chalk/server/v1/branches_pb2_grpc.pyi +36 -0
  45. chalk/_gen/chalk/server/v1/builder_pb2.py +372 -272
  46. chalk/_gen/chalk/server/v1/builder_pb2.pyi +479 -12
  47. chalk/_gen/chalk/server/v1/builder_pb2_grpc.py +360 -0
  48. chalk/_gen/chalk/server/v1/builder_pb2_grpc.pyi +96 -0
  49. chalk/_gen/chalk/server/v1/chart_pb2.py +10 -10
  50. chalk/_gen/chalk/server/v1/chart_pb2.pyi +18 -2
  51. chalk/_gen/chalk/server/v1/clickhouse_pb2.py +42 -0
  52. chalk/_gen/chalk/server/v1/clickhouse_pb2.pyi +17 -0
  53. chalk/_gen/chalk/server/v1/clickhouse_pb2_grpc.py +78 -0
  54. chalk/_gen/chalk/server/v1/clickhouse_pb2_grpc.pyi +38 -0
  55. chalk/_gen/chalk/server/v1/cloud_components_pb2.py +153 -107
  56. chalk/_gen/chalk/server/v1/cloud_components_pb2.pyi +146 -4
  57. chalk/_gen/chalk/server/v1/cloud_components_pb2_grpc.py +180 -0
  58. chalk/_gen/chalk/server/v1/cloud_components_pb2_grpc.pyi +48 -0
  59. chalk/_gen/chalk/server/v1/cloud_credentials_pb2.py +11 -3
  60. chalk/_gen/chalk/server/v1/cloud_credentials_pb2.pyi +20 -0
  61. chalk/_gen/chalk/server/v1/cloud_credentials_pb2_grpc.py +45 -0
  62. chalk/_gen/chalk/server/v1/cloud_credentials_pb2_grpc.pyi +12 -0
  63. chalk/_gen/chalk/server/v1/dataplanejobqueue_pb2.py +59 -35
  64. chalk/_gen/chalk/server/v1/dataplanejobqueue_pb2.pyi +127 -1
  65. chalk/_gen/chalk/server/v1/dataplanejobqueue_pb2_grpc.py +135 -0
  66. chalk/_gen/chalk/server/v1/dataplanejobqueue_pb2_grpc.pyi +36 -0
  67. chalk/_gen/chalk/server/v1/dataplaneworkflows_pb2.py +90 -0
  68. chalk/_gen/chalk/server/v1/dataplaneworkflows_pb2.pyi +264 -0
  69. chalk/_gen/chalk/server/v1/dataplaneworkflows_pb2_grpc.py +170 -0
  70. chalk/_gen/chalk/server/v1/dataplaneworkflows_pb2_grpc.pyi +62 -0
  71. chalk/_gen/chalk/server/v1/datasets_pb2.py +36 -24
  72. chalk/_gen/chalk/server/v1/datasets_pb2.pyi +71 -2
  73. chalk/_gen/chalk/server/v1/datasets_pb2_grpc.py +45 -0
  74. chalk/_gen/chalk/server/v1/datasets_pb2_grpc.pyi +12 -0
  75. chalk/_gen/chalk/server/v1/deploy_pb2.py +9 -3
  76. chalk/_gen/chalk/server/v1/deploy_pb2.pyi +12 -0
  77. chalk/_gen/chalk/server/v1/deploy_pb2_grpc.py +45 -0
  78. chalk/_gen/chalk/server/v1/deploy_pb2_grpc.pyi +12 -0
  79. chalk/_gen/chalk/server/v1/deployment_pb2.py +20 -15
  80. chalk/_gen/chalk/server/v1/deployment_pb2.pyi +25 -0
  81. chalk/_gen/chalk/server/v1/environment_pb2.py +25 -15
  82. chalk/_gen/chalk/server/v1/environment_pb2.pyi +93 -1
  83. chalk/_gen/chalk/server/v1/eventbus_pb2.py +44 -0
  84. chalk/_gen/chalk/server/v1/eventbus_pb2.pyi +64 -0
  85. chalk/_gen/chalk/server/v1/eventbus_pb2_grpc.py +4 -0
  86. chalk/_gen/chalk/server/v1/eventbus_pb2_grpc.pyi +4 -0
  87. chalk/_gen/chalk/server/v1/files_pb2.py +65 -0
  88. chalk/_gen/chalk/server/v1/files_pb2.pyi +167 -0
  89. chalk/_gen/chalk/server/v1/files_pb2_grpc.py +4 -0
  90. chalk/_gen/chalk/server/v1/files_pb2_grpc.pyi +4 -0
  91. chalk/_gen/chalk/server/v1/graph_pb2.py +41 -3
  92. chalk/_gen/chalk/server/v1/graph_pb2.pyi +191 -0
  93. chalk/_gen/chalk/server/v1/graph_pb2_grpc.py +92 -0
  94. chalk/_gen/chalk/server/v1/graph_pb2_grpc.pyi +32 -0
  95. chalk/_gen/chalk/server/v1/incident_pb2.py +57 -0
  96. chalk/_gen/chalk/server/v1/incident_pb2.pyi +165 -0
  97. chalk/_gen/chalk/server/v1/incident_pb2_grpc.py +4 -0
  98. chalk/_gen/chalk/server/v1/incident_pb2_grpc.pyi +4 -0
  99. chalk/_gen/chalk/server/v1/indexing_job_pb2.py +44 -0
  100. chalk/_gen/chalk/server/v1/indexing_job_pb2.pyi +38 -0
  101. chalk/_gen/chalk/server/v1/indexing_job_pb2_grpc.py +78 -0
  102. chalk/_gen/chalk/server/v1/indexing_job_pb2_grpc.pyi +38 -0
  103. chalk/_gen/chalk/server/v1/integrations_pb2.py +11 -9
  104. chalk/_gen/chalk/server/v1/integrations_pb2.pyi +34 -2
  105. chalk/_gen/chalk/server/v1/kube_pb2.py +29 -19
  106. chalk/_gen/chalk/server/v1/kube_pb2.pyi +28 -0
  107. chalk/_gen/chalk/server/v1/kube_pb2_grpc.py +45 -0
  108. chalk/_gen/chalk/server/v1/kube_pb2_grpc.pyi +12 -0
  109. chalk/_gen/chalk/server/v1/log_pb2.py +21 -3
  110. chalk/_gen/chalk/server/v1/log_pb2.pyi +68 -0
  111. chalk/_gen/chalk/server/v1/log_pb2_grpc.py +90 -0
  112. chalk/_gen/chalk/server/v1/log_pb2_grpc.pyi +24 -0
  113. chalk/_gen/chalk/server/v1/metadataplanejobqueue_pb2.py +73 -0
  114. chalk/_gen/chalk/server/v1/metadataplanejobqueue_pb2.pyi +212 -0
  115. chalk/_gen/chalk/server/v1/metadataplanejobqueue_pb2_grpc.py +217 -0
  116. chalk/_gen/chalk/server/v1/metadataplanejobqueue_pb2_grpc.pyi +74 -0
  117. chalk/_gen/chalk/server/v1/model_registry_pb2.py +10 -10
  118. chalk/_gen/chalk/server/v1/model_registry_pb2.pyi +4 -1
  119. chalk/_gen/chalk/server/v1/monitoring_pb2.py +84 -75
  120. chalk/_gen/chalk/server/v1/monitoring_pb2.pyi +1 -0
  121. chalk/_gen/chalk/server/v1/monitoring_pb2_grpc.py +136 -0
  122. chalk/_gen/chalk/server/v1/monitoring_pb2_grpc.pyi +38 -0
  123. chalk/_gen/chalk/server/v1/offline_queries_pb2.py +32 -10
  124. chalk/_gen/chalk/server/v1/offline_queries_pb2.pyi +73 -0
  125. chalk/_gen/chalk/server/v1/offline_queries_pb2_grpc.py +90 -0
  126. chalk/_gen/chalk/server/v1/offline_queries_pb2_grpc.pyi +24 -0
  127. chalk/_gen/chalk/server/v1/plandebug_pb2.py +53 -0
  128. chalk/_gen/chalk/server/v1/plandebug_pb2.pyi +86 -0
  129. chalk/_gen/chalk/server/v1/plandebug_pb2_grpc.py +168 -0
  130. chalk/_gen/chalk/server/v1/plandebug_pb2_grpc.pyi +60 -0
  131. chalk/_gen/chalk/server/v1/queries_pb2.py +76 -48
  132. chalk/_gen/chalk/server/v1/queries_pb2.pyi +155 -2
  133. chalk/_gen/chalk/server/v1/queries_pb2_grpc.py +180 -0
  134. chalk/_gen/chalk/server/v1/queries_pb2_grpc.pyi +48 -0
  135. chalk/_gen/chalk/server/v1/scheduled_query_pb2.py +4 -2
  136. chalk/_gen/chalk/server/v1/scheduled_query_pb2_grpc.py +45 -0
  137. chalk/_gen/chalk/server/v1/scheduled_query_pb2_grpc.pyi +12 -0
  138. chalk/_gen/chalk/server/v1/scheduled_query_run_pb2.py +12 -6
  139. chalk/_gen/chalk/server/v1/scheduled_query_run_pb2.pyi +75 -2
  140. chalk/_gen/chalk/server/v1/scheduler_pb2.py +24 -12
  141. chalk/_gen/chalk/server/v1/scheduler_pb2.pyi +61 -1
  142. chalk/_gen/chalk/server/v1/scheduler_pb2_grpc.py +90 -0
  143. chalk/_gen/chalk/server/v1/scheduler_pb2_grpc.pyi +24 -0
  144. chalk/_gen/chalk/server/v1/script_tasks_pb2.py +26 -14
  145. chalk/_gen/chalk/server/v1/script_tasks_pb2.pyi +33 -3
  146. chalk/_gen/chalk/server/v1/script_tasks_pb2_grpc.py +90 -0
  147. chalk/_gen/chalk/server/v1/script_tasks_pb2_grpc.pyi +24 -0
  148. chalk/_gen/chalk/server/v1/sql_interface_pb2.py +75 -0
  149. chalk/_gen/chalk/server/v1/sql_interface_pb2.pyi +142 -0
  150. chalk/_gen/chalk/server/v1/sql_interface_pb2_grpc.py +349 -0
  151. chalk/_gen/chalk/server/v1/sql_interface_pb2_grpc.pyi +114 -0
  152. chalk/_gen/chalk/server/v1/sql_queries_pb2.py +48 -0
  153. chalk/_gen/chalk/server/v1/sql_queries_pb2.pyi +150 -0
  154. chalk/_gen/chalk/server/v1/sql_queries_pb2_grpc.py +123 -0
  155. chalk/_gen/chalk/server/v1/sql_queries_pb2_grpc.pyi +52 -0
  156. chalk/_gen/chalk/server/v1/team_pb2.py +156 -137
  157. chalk/_gen/chalk/server/v1/team_pb2.pyi +56 -10
  158. chalk/_gen/chalk/server/v1/team_pb2_grpc.py +90 -0
  159. chalk/_gen/chalk/server/v1/team_pb2_grpc.pyi +24 -0
  160. chalk/_gen/chalk/server/v1/topic_pb2.py +5 -3
  161. chalk/_gen/chalk/server/v1/topic_pb2.pyi +10 -1
  162. chalk/_gen/chalk/server/v1/trace_pb2.py +50 -28
  163. chalk/_gen/chalk/server/v1/trace_pb2.pyi +121 -0
  164. chalk/_gen/chalk/server/v1/trace_pb2_grpc.py +135 -0
  165. chalk/_gen/chalk/server/v1/trace_pb2_grpc.pyi +42 -0
  166. chalk/_gen/chalk/server/v1/webhook_pb2.py +9 -3
  167. chalk/_gen/chalk/server/v1/webhook_pb2.pyi +18 -0
  168. chalk/_gen/chalk/server/v1/webhook_pb2_grpc.py +45 -0
  169. chalk/_gen/chalk/server/v1/webhook_pb2_grpc.pyi +12 -0
  170. chalk/_gen/chalk/streaming/v1/debug_service_pb2.py +62 -0
  171. chalk/_gen/chalk/streaming/v1/debug_service_pb2.pyi +75 -0
  172. chalk/_gen/chalk/streaming/v1/debug_service_pb2_grpc.py +221 -0
  173. chalk/_gen/chalk/streaming/v1/debug_service_pb2_grpc.pyi +88 -0
  174. chalk/_gen/chalk/streaming/v1/simple_streaming_service_pb2.py +19 -7
  175. chalk/_gen/chalk/streaming/v1/simple_streaming_service_pb2.pyi +96 -3
  176. chalk/_gen/chalk/streaming/v1/simple_streaming_service_pb2_grpc.py +48 -0
  177. chalk/_gen/chalk/streaming/v1/simple_streaming_service_pb2_grpc.pyi +20 -0
  178. chalk/_gen/chalk/utils/v1/field_change_pb2.py +32 -0
  179. chalk/_gen/chalk/utils/v1/field_change_pb2.pyi +42 -0
  180. chalk/_gen/chalk/utils/v1/field_change_pb2_grpc.py +4 -0
  181. chalk/_gen/chalk/utils/v1/field_change_pb2_grpc.pyi +4 -0
  182. chalk/_lsp/error_builder.py +11 -0
  183. chalk/_monitoring/Chart.py +1 -3
  184. chalk/_version.py +1 -1
  185. chalk/cli.py +5 -10
  186. chalk/client/client.py +178 -64
  187. chalk/client/client_async.py +154 -0
  188. chalk/client/client_async_impl.py +22 -0
  189. chalk/client/client_grpc.py +738 -112
  190. chalk/client/client_impl.py +541 -136
  191. chalk/client/dataset.py +27 -6
  192. chalk/client/models.py +99 -2
  193. chalk/client/serialization/model_serialization.py +126 -10
  194. chalk/config/project_config.py +1 -1
  195. chalk/df/LazyFramePlaceholder.py +1154 -0
  196. chalk/df/ast_parser.py +2 -10
  197. chalk/features/_class_property.py +7 -0
  198. chalk/features/_embedding/embedding.py +1 -0
  199. chalk/features/_embedding/sentence_transformer.py +1 -1
  200. chalk/features/_encoding/converter.py +83 -2
  201. chalk/features/_encoding/pyarrow.py +20 -4
  202. chalk/features/_encoding/rich.py +1 -3
  203. chalk/features/_tensor.py +1 -2
  204. chalk/features/dataframe/_filters.py +14 -5
  205. chalk/features/dataframe/_impl.py +91 -36
  206. chalk/features/dataframe/_validation.py +11 -7
  207. chalk/features/feature_field.py +40 -30
  208. chalk/features/feature_set.py +1 -2
  209. chalk/features/feature_set_decorator.py +1 -0
  210. chalk/features/feature_wrapper.py +42 -3
  211. chalk/features/hooks.py +81 -12
  212. chalk/features/inference.py +65 -10
  213. chalk/features/resolver.py +338 -56
  214. chalk/features/tag.py +1 -3
  215. chalk/features/underscore_features.py +2 -1
  216. chalk/functions/__init__.py +456 -21
  217. chalk/functions/holidays.py +1 -3
  218. chalk/gitignore/gitignore_parser.py +5 -1
  219. chalk/importer.py +186 -74
  220. chalk/ml/__init__.py +6 -2
  221. chalk/ml/model_hooks.py +368 -51
  222. chalk/ml/model_reference.py +68 -10
  223. chalk/ml/model_version.py +34 -21
  224. chalk/ml/utils.py +143 -40
  225. chalk/operators/_utils.py +14 -3
  226. chalk/parsed/_proto/export.py +22 -0
  227. chalk/parsed/duplicate_input_gql.py +4 -0
  228. chalk/parsed/expressions.py +1 -3
  229. chalk/parsed/json_conversions.py +21 -14
  230. chalk/parsed/to_proto.py +16 -4
  231. chalk/parsed/user_types_to_json.py +31 -10
  232. chalk/parsed/validation_from_registries.py +182 -0
  233. chalk/queries/named_query.py +16 -6
  234. chalk/queries/scheduled_query.py +13 -1
  235. chalk/serialization/parsed_annotation.py +25 -12
  236. chalk/sql/__init__.py +221 -0
  237. chalk/sql/_internal/integrations/athena.py +6 -1
  238. chalk/sql/_internal/integrations/bigquery.py +22 -2
  239. chalk/sql/_internal/integrations/databricks.py +61 -18
  240. chalk/sql/_internal/integrations/mssql.py +281 -0
  241. chalk/sql/_internal/integrations/postgres.py +11 -3
  242. chalk/sql/_internal/integrations/redshift.py +4 -0
  243. chalk/sql/_internal/integrations/snowflake.py +11 -2
  244. chalk/sql/_internal/integrations/util.py +2 -1
  245. chalk/sql/_internal/sql_file_resolver.py +55 -10
  246. chalk/sql/_internal/sql_source.py +36 -2
  247. chalk/streams/__init__.py +1 -3
  248. chalk/streams/_kafka_source.py +5 -1
  249. chalk/streams/_windows.py +16 -4
  250. chalk/streams/types.py +1 -2
  251. chalk/utils/__init__.py +1 -3
  252. chalk/utils/_otel_version.py +13 -0
  253. chalk/utils/async_helpers.py +14 -5
  254. chalk/utils/df_utils.py +2 -2
  255. chalk/utils/duration.py +1 -3
  256. chalk/utils/job_log_display.py +538 -0
  257. chalk/utils/missing_dependency.py +5 -4
  258. chalk/utils/notebook.py +255 -2
  259. chalk/utils/pl_helpers.py +190 -37
  260. chalk/utils/pydanticutil/pydantic_compat.py +1 -2
  261. chalk/utils/storage_client.py +246 -0
  262. chalk/utils/threading.py +1 -3
  263. chalk/utils/tracing.py +194 -86
  264. {chalkpy-2.89.22.dist-info → chalkpy-2.95.3.dist-info}/METADATA +53 -21
  265. {chalkpy-2.89.22.dist-info → chalkpy-2.95.3.dist-info}/RECORD +268 -198
  266. {chalkpy-2.89.22.dist-info → chalkpy-2.95.3.dist-info}/WHEEL +0 -0
  267. {chalkpy-2.89.22.dist-info → chalkpy-2.95.3.dist-info}/entry_points.txt +0 -0
  268. {chalkpy-2.89.22.dist-info → chalkpy-2.95.3.dist-info}/top_level.txt +0 -0
@@ -110,6 +110,22 @@ def project_settings_to_gql(config: ProjectSettings) -> ProjectSettingsGQL:
110
110
 
111
111
 
112
112
  def get_registered_types(scope_to: Path, failed: List[FailedImport]) -> UpsertGraphGQL:
113
+ # Validate registries BEFORE conversion to catch errors early
114
+ # This ensures parity with Proto validation path
115
+ from chalk.parsed.validation_from_registries import validate_all_from_registries
116
+
117
+ try:
118
+ validate_all_from_registries(
119
+ features_registry=FeatureSetBase.registry,
120
+ resolver_registry=RESOLVER_REGISTRY,
121
+ )
122
+ except Exception as e:
123
+ # If validation fails, add to failed but continue
124
+ # to allow other validation to complete
125
+ if not LSPErrorBuilder.promote_exception(e):
126
+ # Not an LSP error, so log it as a failed import
127
+ failed.append(build_failed_import(e, "validation"))
128
+
113
129
  features = []
114
130
  feature_classes: list[FeatureClassGQL] = []
115
131
  for x in FeatureSetBase.registry.values():
@@ -173,6 +189,14 @@ def get_registered_types(scope_to: Path, failed: List[FailedImport]) -> UpsertGr
173
189
  named_queries: list[UpsertNamedQueryGQL] = []
174
190
  for named_query in NAMED_QUERY_REGISTRY.values():
175
191
  if named_query.filename is None or _is_relative_to(Path(named_query.filename), scope_to):
192
+ # only try to convert if there are no errors
193
+ if not named_query.errors:
194
+ try:
195
+ named_queries.append(convert_type_to_gql(named_query, path_prefix=path_prefix_to_remove))
196
+ except Exception as e:
197
+ failed.append(build_failed_import(e, f"named query '{named_query.name}'"))
198
+
199
+ # named_query.errors can go from empty to non-empty after conversion
176
200
  if named_query.errors:
177
201
  code_object_diagnostics[named_query.filename or ""].extend(
178
202
  [
@@ -185,15 +209,17 @@ def get_registered_types(scope_to: Path, failed: List[FailedImport]) -> UpsertGr
185
209
  for error in named_query.errors
186
210
  ]
187
211
  )
188
- continue
189
- try:
190
- named_queries.append(convert_type_to_gql(named_query, path_prefix=path_prefix_to_remove))
191
- except Exception as e:
192
- failed.append(build_failed_import(e, f"named query '{named_query.name}'"))
193
212
 
194
213
  model_references: list[UpsertModelReferenceGQL] = []
195
214
  for mr in MODEL_REFERENCE_REGISTRY.values():
196
215
  if mr.filename is None or _is_relative_to(Path(mr.filename), scope_to):
216
+ # similar logic to named_queries above
217
+ if not mr.errors:
218
+ try:
219
+ model_references.append(convert_type_to_gql(mr, path_prefix=path_prefix_to_remove))
220
+ except Exception as e:
221
+ failed.append(build_failed_import(e, f"model reference '{mr.name}'"))
222
+
197
223
  if mr.errors:
198
224
  code_object_diagnostics[mr.filename or ""].extend(
199
225
  [
@@ -206,11 +232,6 @@ def get_registered_types(scope_to: Path, failed: List[FailedImport]) -> UpsertGr
206
232
  for error in mr.errors
207
233
  ]
208
234
  )
209
- continue
210
- try:
211
- model_references.append(convert_type_to_gql(mr, path_prefix=path_prefix_to_remove))
212
- except Exception as e:
213
- failed.append(build_failed_import(e, f"model reference '{mr.name}'"))
214
235
 
215
236
  # online store configs
216
237
  for osc in ONLINE_STORE_CONFIG_REGISTRY.values():
@@ -0,0 +1,182 @@
1
+ """
2
+ Unified validation layer that operates directly on registries.
3
+
4
+ This module provides validation that works for BOTH GQL and Proto conversion paths.
5
+ It triggers lazy validations by accessing properties on registry objects and performs
6
+ explicit validation checks.
7
+
8
+ This ensures validation parity between:
9
+ - GQL path: get_registered_types() → validate_graph()
10
+ - Proto path: ToProtoConverter.convert_graph()
11
+
12
+ By calling validate_all_from_registries() before conversion in both paths, we ensure
13
+ developers cannot add validation to one path and forget the other.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import TYPE_CHECKING
19
+
20
+ from chalk._lsp.error_builder import LSPErrorBuilder
21
+
22
+ if TYPE_CHECKING:
23
+ from chalk.features.feature_field import Feature
24
+ from chalk.features.feature_set import Features
25
+ from chalk.features.resolver import ResolverRegistry
26
+
27
+
28
+ def validate_all_from_registries(
29
+ features_registry: dict[str, type["Features"]],
30
+ resolver_registry: "ResolverRegistry",
31
+ ) -> None:
32
+ """
33
+ Trigger all validations by accessing properties on registry objects.
34
+ This can be run multiple times and not show duplicates.
35
+
36
+ This function should be called by BOTH GQL and Proto conversion paths BEFORE
37
+ they perform their conversions. It validates by triggering lazy validations:
38
+
39
+ - Error[24]: Feature names with protected prefixes
40
+ - Error[25]: Namespace names with protected prefixes
41
+ - Error[32]: Invalid join syntax (composite joins must use & not and)
42
+ - Error[35]: Missing has-one join definition
43
+ - Error[37]: Join filter with incorrect type annotation
44
+ - Error[40]: Invalid join lambda
45
+ - Error[42]: Bad foreign key types (type mismatch)
46
+ - Error[43]: Multi-namespace joins
47
+ - Error[51]: Multiple primary features (versioned primary keys)
48
+ - Error[119]: State type validation (stream resolvers)
49
+ - Error[135]: Unrecognized feature reference
50
+
51
+ Parameters
52
+ ----------
53
+ features_registry : dict[str, type[Features]]
54
+ The feature registry to validate (FeatureSetBase.registry).
55
+ resolver_registry : ResolverRegistry
56
+ The resolver registry to validate (RESOLVER_REGISTRY).
57
+
58
+ Returns
59
+ -------
60
+ None
61
+ Validation errors are accumulated in LSPErrorBuilder and raised as exceptions.
62
+ """
63
+
64
+ # ========================================================================
65
+ # FEATURE VALIDATION
66
+ # ========================================================================
67
+
68
+ for _, features_cls in features_registry.items():
69
+ # --------------------------------------------------------------------
70
+ # Error[51]: Multiple primary features (versioned primary keys)
71
+ # --------------------------------------------------------------------
72
+ # Accessing __chalk_primary__ triggers _discover_feature() which
73
+ # validates that there's only one primary key. Versioned features
74
+ # create multiple primary keys (e.g., id, id@2, id@3, id@4) which
75
+ # triggers Error[51].
76
+ try:
77
+ _ = features_cls.__chalk_primary__
78
+ except Exception as e:
79
+ # LSPErrorBuilder.promote_exception() re-raises LSP errors
80
+ if not LSPErrorBuilder.promote_exception(e):
81
+ # If it's not an LSP error, something else went wrong
82
+ raise
83
+
84
+ # --------------------------------------------------------------------
85
+ # Iterate through all features in this feature set
86
+ # --------------------------------------------------------------------
87
+ for feature in features_cls.features:
88
+ # Skip autogenerated and no-display features (same as user_types_to_json.py:138)
89
+ # This prevents validating internal features like __chalk_* that are allowed
90
+ # to have protected names
91
+ if feature.is_autogenerated or feature.no_display:
92
+ continue
93
+
94
+ # ----------------------------------------------------------------
95
+ # Error[32,35,37,40,42,43]: Join validation
96
+ # ----------------------------------------------------------------
97
+ # Accessing the .join property triggers:
98
+ # - _validate_join() in feature_field.py (Error[32,37])
99
+ # - _validate_filter() in feature_field.py (Error[40,42,43])
100
+ #
101
+ # During GQL conversion, convert_type_to_gql() also checks:
102
+ # - Error[35]: if t.is_has_one and t.join is None
103
+ try:
104
+ _ = feature.join
105
+ except Exception as e:
106
+ if not LSPErrorBuilder.promote_exception(e):
107
+ raise
108
+
109
+ # ----------------------------------------------------------------
110
+ # Error[24,25]: Feature and namespace name validation
111
+ # ----------------------------------------------------------------
112
+ try:
113
+ _validate_feature_names_from_registry(feature)
114
+ except Exception as e:
115
+ if not LSPErrorBuilder.promote_exception(e):
116
+ raise
117
+
118
+ # ========================================================================
119
+ # RESOLVER VALIDATION
120
+ # ========================================================================
121
+
122
+ for resolver in resolver_registry.get_all_resolvers():
123
+ # --------------------------------------------------------------------
124
+ # Error[135]: Unrecognized feature reference
125
+ # --------------------------------------------------------------------
126
+ # Accessing resolver.inputs triggers _do_parse() which validates
127
+ # that all input features are recognized and exist in the registry.
128
+ try:
129
+ _ = resolver.inputs
130
+ except Exception as e:
131
+ if not LSPErrorBuilder.promote_exception(e):
132
+ raise
133
+
134
+ # --------------------------------------------------------------------
135
+ # Error[119]: State type validation (stream resolvers)
136
+ # --------------------------------------------------------------------
137
+ # Accessing resolver state and default_args triggers validation
138
+ # that default state values match their type annotations.
139
+ try:
140
+ _ = resolver.state
141
+ _ = resolver.default_args
142
+ except Exception as e:
143
+ if not LSPErrorBuilder.promote_exception(e):
144
+ raise
145
+
146
+
147
+ def _validate_feature_names_from_registry(feature: "Feature") -> None:
148
+ """
149
+ Validate that feature names and namespace names don't use protected prefixes.
150
+
151
+ This performs the same validation as _validate_feature_names() in
152
+ _graph_validation.py, but operates on Feature objects from the registry
153
+ rather than UpsertFeatureGQL objects.
154
+
155
+ Parameters
156
+ ----------
157
+ feature : Feature
158
+ The feature to validate from FeatureSetBase.registry
159
+
160
+ Raises
161
+ ------
162
+ Exception
163
+ If feature or namespace name starts with '_chalk' or '__'
164
+ """
165
+ # Error[24]: Feature names cannot begin with '_chalk' or '__'
166
+ if feature.name.startswith("__") or feature.name.startswith("_chalk"):
167
+ feature.lsp_error_builder.add_diagnostic(
168
+ message="Feature names cannot begin with '_chalk' or '__'.",
169
+ range=feature.lsp_error_builder.property_range(feature.attribute_name or feature.name),
170
+ label="protected name",
171
+ code="24",
172
+ )
173
+
174
+ # Error[25]: Namespace names cannot begin with '_chalk' or '__'
175
+ if feature.namespace.startswith("__") or feature.namespace.startswith("_chalk"):
176
+ feature.lsp_error_builder.add_diagnostic(
177
+ message="Feature classes cannot have names that begin with '_chalk' or '__'.",
178
+ label="protected namespace",
179
+ range=feature.lsp_error_builder.decorator_kwarg_value_range("name")
180
+ or feature.lsp_error_builder.class_definition_range(),
181
+ code="25",
182
+ )
@@ -4,6 +4,7 @@ import inspect
4
4
  import traceback
5
5
  from typing import TYPE_CHECKING, Mapping, Sequence
6
6
 
7
+ from chalk._lsp.error_builder import LSPErrorBuilder
7
8
  from chalk.features import unwrap_feature
8
9
  from chalk.utils.object_inspect import get_source_object_starting
9
10
  from chalk.utils.source_parsing import should_skip_source_code_parsing
@@ -157,9 +158,12 @@ class NamedQuery:
157
158
  self._input = [str(f) for f in self._input_raw]
158
159
  elif self._output_raw is not None:
159
160
  self._input = [str(unwrap_feature(o).primary_feature) for o in self._output_raw]
160
- except Exception:
161
+ except Exception as e:
161
162
  self._input = None
162
- self.errors.append(traceback.format_exc())
163
+ if not LSPErrorBuilder.promote_exception(e):
164
+ self.errors.append(
165
+ f"Error creating NamedQuery '{self.name} ({self.version})': {traceback.format_exc()}"
166
+ )
163
167
 
164
168
  return self._input
165
169
 
@@ -170,9 +174,12 @@ class NamedQuery:
170
174
  try:
171
175
  if self._output_raw is not None:
172
176
  self._output = [str(o) for o in self._output_raw]
173
- except Exception:
177
+ except Exception as e:
174
178
  self._output = None
175
- self.errors.append(f"Error creating NamedQuery '{self.name} ({self.version})': {traceback.format_exc()}")
179
+ if not LSPErrorBuilder.promote_exception(e):
180
+ self.errors.append(
181
+ f"Error creating NamedQuery '{self.name} ({self.version})': {traceback.format_exc()}"
182
+ )
176
183
 
177
184
  return self._output
178
185
 
@@ -183,9 +190,12 @@ class NamedQuery:
183
190
  try:
184
191
  if self._additional_logged_features_raw is not None:
185
192
  self._additional_logged_features = [str(alf) for alf in self._additional_logged_features_raw]
186
- except Exception:
193
+ except Exception as e:
187
194
  self._additional_logged_features = None
188
- self.errors.append(f"Error creating NamedQuery '{self.name} ({self.version})': {traceback.format_exc()}")
195
+ if not LSPErrorBuilder.promote_exception(e):
196
+ self.errors.append(
197
+ f"Error creating NamedQuery '{self.name} ({self.version})': {traceback.format_exc()}"
198
+ )
189
199
 
190
200
  return self._additional_logged_features
191
201
 
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import inspect
4
- from datetime import datetime, timezone
4
+ from datetime import datetime, timedelta, timezone
5
5
  from typing import TYPE_CHECKING, Collection
6
6
 
7
7
  from chalk.utils.duration import CronTab, Duration
@@ -21,12 +21,16 @@ class ScheduledQuery:
21
21
  lower_bound: datetime | None = None,
22
22
  upper_bound: datetime | None = None,
23
23
  tags: Collection[str] | None = None,
24
+ dataset_name: str | None = None,
24
25
  required_resolver_tags: Collection[str] | None = None,
25
26
  store_online: bool = True,
26
27
  store_offline: bool = True,
27
28
  incremental_resolvers: Collection[str] | None = None,
28
29
  planner_options: dict[str, str] | None = None,
29
30
  resource_group: str | None = None,
31
+ completion_deadline: timedelta | None = None,
32
+ num_shards: int | None = None,
33
+ num_workers: int | None = None,
30
34
  ):
31
35
  """Create an offline query which runs on a schedule.
32
36
 
@@ -64,6 +68,8 @@ class ScheduledQuery:
64
68
  incrementalization.
65
69
  tags
66
70
  Allows selecting resolvers with these tags.
71
+ dataset_name
72
+ Associated dataset name for the scheduled query.
67
73
  required_resolver_tags
68
74
  Requires that resolvers have these tags.
69
75
  store_online
@@ -143,6 +149,7 @@ class ScheduledQuery:
143
149
  self.lower_bound = lower_bound
144
150
  self.upper_bound = upper_bound
145
151
  self.tags = tags
152
+ self.dataset_name = dataset_name
146
153
  self.required_resolver_tags = required_resolver_tags
147
154
  self.filename = caller_filename
148
155
  self.store_online = store_online
@@ -155,6 +162,11 @@ class ScheduledQuery:
155
162
  self.planner_options = {k: str(v) for k, v in planner_options.items()} if planner_options else None
156
163
  self.resource_group = resource_group
157
164
 
165
+ self.completion_deadline = completion_deadline
166
+
167
+ self.num_shards = num_shards
168
+ self.num_workers = num_workers
169
+
158
170
  CRON_QUERY_REGISTRY[name] = self
159
171
 
160
172
 
@@ -111,7 +111,7 @@ class ParsedAnnotation:
111
111
  typ = self._features_cls.__annotations__[self._attribute_name]
112
112
  else:
113
113
  typ = self._parsed_annotation or self._underlying or self._unparsed_underlying
114
- if sys.version_info >= (3, 9) and get_origin(typ) == typing.Annotated:
114
+ if get_origin(typ) == typing.Annotated:
115
115
  typ = typ.__origin__ # pyright: ignore
116
116
  if isinstance(typ, type):
117
117
  typ = typ.__name__
@@ -350,6 +350,7 @@ class ParsedAnnotation:
350
350
  if "__chalk_document__" in args:
351
351
  self._is_document = True
352
352
  origin = get_origin(annotation)
353
+ self._parsed_annotation = cast(type, annotation)
353
354
 
354
355
  # The only allowed collections here are Set, List, or DataFrame
355
356
  if origin in (set, Set):
@@ -372,17 +373,6 @@ class ParsedAnnotation:
372
373
  annotation = args[0]
373
374
  if origin in (tuple, Tuple):
374
375
  args = get_args(annotation)
375
- if len(args) != 2 or args[1] is not ... or args[0] is ...:
376
- self._type_error(
377
- (
378
- "Tuple should be given exactly two type parameters. "
379
- "The first should be the type of the elements, and the second should be '...', "
380
- "which indicates that the tuple is of variable length. "
381
- "For example, 'Tuple[int, ...]' is a tuple of ints of variable length."
382
- ),
383
- code="74",
384
- label="invalid tuple",
385
- )
386
376
  annotation = args[0]
387
377
  if origin in (list, List):
388
378
  args = get_args(annotation)
@@ -567,3 +557,26 @@ class ParsedAnnotation:
567
557
  if self._parsed_annotation is None:
568
558
  self._parse_annotation()
569
559
  return self._is_feature_time
560
+
561
+ def is_dataframe_annotation(self) -> bool:
562
+ """
563
+ Check if the annotation represents a DataFrame type, even if validation failed.
564
+ This checks the raw parsed annotation without triggering full validation,
565
+ useful for preventing false positive errors when DataFrame validation fails.
566
+ """
567
+ from typing import get_args
568
+
569
+ from chalk.features.dataframe import DataFrameMeta
570
+
571
+ if self._parsed_annotation is None:
572
+ self._parse_annotation()
573
+
574
+ # Check if directly a DataFrame
575
+ if isinstance(self.parsed_annotation, DataFrameMeta):
576
+ return True
577
+
578
+ # Check if wrapped in Optional, Union, etc.
579
+ if any(isinstance(x, DataFrameMeta) for x in get_args(self.parsed_annotation)):
580
+ return True
581
+
582
+ return False