dataface 0.1.6.dev975__py3-none-any.whl → 0.1.6.dev1010__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.
- dataface/agent_api/describe.py +0 -5
- dataface/agent_api/docs/yaml-reference.md +41 -15
- dataface/cli/_error_format.py +4 -0
- dataface/cli/commands/_agent_server.py +1 -0
- dataface/cli/commands/init.py +2 -0
- dataface/cli/commands/mcp_init.py +2 -0
- dataface/cli/commands/render.py +12 -0
- dataface/cli/commands/schema.py +2 -0
- dataface/cli/commands/serve.py +15 -0
- dataface/cli/commands/skills_init.py +2 -0
- dataface/cli/main.py +5 -0
- dataface/core/compile/__init__.py +4 -6
- dataface/core/compile/compiler.py +74 -12
- dataface/core/compile/introspection.py +6 -4
- dataface/core/compile/models/chart/authored/_base.py +9 -0
- dataface/core/compile/models/chart/normalized/_flat.py +2 -3
- dataface/core/compile/models/query/normalized.py +1 -77
- dataface/core/compile/models/source.py +136 -48
- dataface/core/compile/models/style/resolved/_cascade.py +1 -1
- dataface/core/compile/normalize_charts.py +11 -4
- dataface/core/compile/normalize_charts_v2.py +5 -1
- dataface/core/compile/normalize_queries.py +390 -27
- dataface/core/compile/normalize_variables.py +11 -3
- dataface/core/compile/normalizer.py +3 -1
- dataface/core/compile/palette.py +10 -4
- dataface/core/defaults/themes/cream.yaml +2 -2
- dataface/core/defaults/themes/editorial.yaml +4 -4
- dataface/core/defaults/themes/stark.yaml +1 -1
- dataface/core/execute/adapters/__init__.py +4 -3
- dataface/core/execute/adapters/adapter_registry.py +0 -3
- dataface/core/project.py +11 -0
- dataface/core/registered_views/loader.py +37 -0
- dataface/core/render/board_links.py +6 -3
- {dataface-0.1.6.dev975.dist-info → dataface-0.1.6.dev1010.dist-info}/METADATA +3 -1
- {dataface-0.1.6.dev975.dist-info → dataface-0.1.6.dev1010.dist-info}/RECORD +38 -39
- dataface/core/execute/adapters/metricflow_adapter.py +0 -94
- {dataface-0.1.6.dev975.dist-info → dataface-0.1.6.dev1010.dist-info}/WHEEL +0 -0
- {dataface-0.1.6.dev975.dist-info → dataface-0.1.6.dev1010.dist-info}/entry_points.txt +0 -0
- {dataface-0.1.6.dev975.dist-info → dataface-0.1.6.dev1010.dist-info}/licenses/LICENSE +0 -0
dataface/agent_api/describe.py
CHANGED
|
@@ -14,7 +14,6 @@ from dataface.core.compile.models.face.normalized import Layout
|
|
|
14
14
|
from dataface.core.compile.models.query.normalized import (
|
|
15
15
|
DbtModelQuery,
|
|
16
16
|
HttpQuery,
|
|
17
|
-
MetricFlowQuery,
|
|
18
17
|
Query,
|
|
19
18
|
SqlQuery,
|
|
20
19
|
ValuesQuery,
|
|
@@ -135,10 +134,6 @@ def _build_query_description(name: str, query: Query) -> QueryDescription:
|
|
|
135
134
|
return QueryDescription(
|
|
136
135
|
name=name, type="http", summary=f"HTTP request: {query.url}"
|
|
137
136
|
)
|
|
138
|
-
case MetricFlowQuery():
|
|
139
|
-
return QueryDescription(
|
|
140
|
-
name=name, type="metricflow", summary="MetricFlow query"
|
|
141
|
-
)
|
|
142
137
|
case ValuesQuery():
|
|
143
138
|
return QueryDescription(name=name, type="values", summary="Inline values")
|
|
144
139
|
case _:
|
|
@@ -40,7 +40,7 @@ Sources section for faces.
|
|
|
40
40
|
| Field | Type | Optional | Description |
|
|
41
41
|
|-------|------|:--------:|-------------|
|
|
42
42
|
| `default` | str | ✓ | Default source name used for all queries that don't specify a source. |
|
|
43
|
-
| `<name>` | [PostgresSourceConfig](#postgressourceconfig) \| [SnowflakeSourceConfig](#snowflakesourceconfig) \| [BigQuerySourceConfig](#bigquerysourceconfig) \| [RedshiftSourceConfig](#redshiftsourceconfig) \| [MySQLSourceConfig](#mysqlsourceconfig) \| [DuckDBSourceConfig](#duckdbsourceconfig) \| [SQLiteSourceConfig](#sqlitesourceconfig) \| [CsvSourceConfig](#csvsourceconfig) \| [ParquetSourceConfig](#parquetsourceconfig) \| [JsonSourceConfig](#jsonsourceconfig) \| [HttpSourceConfig](#httpsourceconfig) \| [DbtProfileSourceConfig](#dbtprofilesourceconfig)
|
|
43
|
+
| `<name>` | [PostgresSourceConfig](#postgressourceconfig) \| [SnowflakeSourceConfig](#snowflakesourceconfig) \| [BigQuerySourceConfig](#bigquerysourceconfig) \| [RedshiftSourceConfig](#redshiftsourceconfig) \| [MySQLSourceConfig](#mysqlsourceconfig) \| [DuckDBSourceConfig](#duckdbsourceconfig) \| [SQLiteSourceConfig](#sqlitesourceconfig) \| [CsvSourceConfig](#csvsourceconfig) \| [ParquetSourceConfig](#parquetsourceconfig) \| [JsonSourceConfig](#jsonsourceconfig) \| [HttpSourceConfig](#httpsourceconfig) \| [DbtProfileSourceConfig](#dbtprofilesourceconfig) | ✓ | Additional named entry. |
|
|
44
44
|
|
|
45
45
|
<a id="variable"></a>
|
|
46
46
|
## Variable
|
|
@@ -114,6 +114,7 @@ Authored patch for bar and histogram charts.
|
|
|
114
114
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
115
115
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
116
116
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
117
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
117
118
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
118
119
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
119
120
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -141,6 +142,7 @@ Authored patch for line charts.
|
|
|
141
142
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
142
143
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
143
144
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
145
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
144
146
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
145
147
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
146
148
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -168,6 +170,7 @@ Authored patch for area charts.
|
|
|
168
170
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
169
171
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
170
172
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
173
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
171
174
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
172
175
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
173
176
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -195,6 +198,7 @@ Authored patch for scatter charts.
|
|
|
195
198
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
196
199
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
197
200
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
201
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
198
202
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
199
203
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
200
204
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -224,6 +228,7 @@ Authored patch for heatmap charts.
|
|
|
224
228
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
225
229
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
226
230
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
231
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
227
232
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
228
233
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
229
234
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -252,6 +257,7 @@ Authored patch for pie and donut charts.
|
|
|
252
257
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
253
258
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
254
259
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
260
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
255
261
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
256
262
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
257
263
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -273,6 +279,7 @@ Authored patch for KPI (key performance indicator) charts.
|
|
|
273
279
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
274
280
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
275
281
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
282
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
276
283
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
277
284
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
278
285
|
| `label` | str | ✓ | KPI label rendered above the headline value. |
|
|
@@ -292,6 +299,7 @@ Authored patch for table charts.
|
|
|
292
299
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
293
300
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
294
301
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
302
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
295
303
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
296
304
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
297
305
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -312,6 +320,7 @@ Authored patch for point_map and bubble_map charts.
|
|
|
312
320
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
313
321
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
314
322
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
323
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
315
324
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
316
325
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
317
326
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -339,6 +348,7 @@ Authored patch for map and geoshape charts.
|
|
|
339
348
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
340
349
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
341
350
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
351
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
342
352
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
343
353
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
344
354
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -365,6 +375,7 @@ Authored patch for layered multi-mark charts.
|
|
|
365
375
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
366
376
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
367
377
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
378
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
368
379
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
369
380
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
370
381
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -399,6 +410,7 @@ Authored patch for spark_bar charts (compact horizontal bars).
|
|
|
399
410
|
| `description` | str | ✓ | Human-readable description used by AI search and context tooltips. |
|
|
400
411
|
| `query` | str \| [Query](#query) \| QueryRef | ✓ | Named query reference, inline AuthoredQuery, or SQL string shorthand. |
|
|
401
412
|
| `link` | str | ✓ | Click-through URL template for drill-down links. |
|
|
413
|
+
| `model` | str | ✓ | Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`. |
|
|
402
414
|
| `conditional_formatting` | dict[str, [FieldConditionalFormatting](#fieldconditionalformatting)] | ✓ | Discrete rule-driven style overrides indexed by column name. |
|
|
403
415
|
| `warnings_ignore` | list[str] | ✓ | Codes of render warnings to suppress for this chart. |
|
|
404
416
|
| `title` | str | ✓ | Chart title displayed above the chart (not used on type: kpi). |
|
|
@@ -2613,6 +2625,8 @@ Postgres source configuration.
|
|
|
2613
2625
|
| `dbname` | str | | Database name (matches dbt 'dbname'). |
|
|
2614
2626
|
| `user` | str | | Database user name. |
|
|
2615
2627
|
| `password` | str | | Database password. |
|
|
2628
|
+
| `lookml_path` | str | ✓ | Relative path to the directory of .lkml files backing this source's models. |
|
|
2629
|
+
| `models` | dict[str, [LookMLModelConfig](#lookmlmodelconfig)] | ✓ | Named LookML model collections nested under this source. |
|
|
2616
2630
|
| `port` | int | ✓ | Database port number. |
|
|
2617
2631
|
| `schema` | str | ✓ | Default schema for queries. |
|
|
2618
2632
|
| `sslmode` | enum: "disable", "allow", "prefer", "require", "verify-ca", "verify-full" | ✓ | libpq SSL mode forwarded to psycopg2. None lets libpq decide its default. |
|
|
@@ -2628,6 +2642,8 @@ Snowflake source configuration.
|
|
|
2628
2642
|
| `user` | str | | Snowflake user name. |
|
|
2629
2643
|
| `database` | str | | Snowflake database name. |
|
|
2630
2644
|
| `warehouse` | str | | Snowflake virtual warehouse name. |
|
|
2645
|
+
| `lookml_path` | str | ✓ | Relative path to the directory of .lkml files backing this source's models. |
|
|
2646
|
+
| `models` | dict[str, [LookMLModelConfig](#lookmlmodelconfig)] | ✓ | Named LookML model collections nested under this source. |
|
|
2631
2647
|
| `password` | str | ✓ | Snowflake password. Omit when using OAuth or key-pair auth. |
|
|
2632
2648
|
| `schema` | str | ✓ | Default schema for queries. |
|
|
2633
2649
|
| `role` | str | ✓ | Snowflake role to assume for the session. |
|
|
@@ -2641,6 +2657,8 @@ BigQuery source configuration.
|
|
|
2641
2657
|
| `type` | enum: "bigquery" | | Source type identifier. |
|
|
2642
2658
|
| `project` | str | | GCP project ID. |
|
|
2643
2659
|
| `dataset` | str | | BigQuery dataset name (equivalent to schema). |
|
|
2660
|
+
| `lookml_path` | str | ✓ | Relative path to the directory of .lkml files backing this source's models. |
|
|
2661
|
+
| `models` | dict[str, [LookMLModelConfig](#lookmlmodelconfig)] | ✓ | Named LookML model collections nested under this source. |
|
|
2644
2662
|
| `keyfile` | str | ✓ | Path to service account JSON key file. |
|
|
2645
2663
|
| `keyfile_json` | dict[str, Any] | ✓ | Inline service account JSON dict. |
|
|
2646
2664
|
| `location` | str | ✓ | Dataset location (e.g. US, EU). |
|
|
@@ -2657,6 +2675,8 @@ Redshift source configuration.
|
|
|
2657
2675
|
| `dbname` | str | | Redshift database name. |
|
|
2658
2676
|
| `user` | str | | Redshift user name. |
|
|
2659
2677
|
| `password` | str | | Redshift password. |
|
|
2678
|
+
| `lookml_path` | str | ✓ | Relative path to the directory of .lkml files backing this source's models. |
|
|
2679
|
+
| `models` | dict[str, [LookMLModelConfig](#lookmlmodelconfig)] | ✓ | Named LookML model collections nested under this source. |
|
|
2660
2680
|
| `port` | int | ✓ | Redshift port number. |
|
|
2661
2681
|
| `schema` | str | ✓ | Default schema for queries. |
|
|
2662
2682
|
|
|
@@ -2671,6 +2691,8 @@ MySQL source configuration.
|
|
|
2671
2691
|
| `database` | str | | MySQL database name. |
|
|
2672
2692
|
| `user` | str | | MySQL user name. |
|
|
2673
2693
|
| `password` | str | | MySQL password. |
|
|
2694
|
+
| `lookml_path` | str | ✓ | Relative path to the directory of .lkml files backing this source's models. |
|
|
2695
|
+
| `models` | dict[str, [LookMLModelConfig](#lookmlmodelconfig)] | ✓ | Named LookML model collections nested under this source. |
|
|
2674
2696
|
| `port` | int | ✓ | MySQL port number. |
|
|
2675
2697
|
| `schema` | str | ✓ | Default schema for queries. |
|
|
2676
2698
|
|
|
@@ -2681,6 +2703,8 @@ DuckDB source configuration.
|
|
|
2681
2703
|
| Field | Type | Optional | Description |
|
|
2682
2704
|
|-------|------|:--------:|-------------|
|
|
2683
2705
|
| `type` | enum: "duckdb" | | Source type identifier. |
|
|
2706
|
+
| `lookml_path` | str | ✓ | Relative path to the directory of .lkml files backing this source's models. |
|
|
2707
|
+
| `models` | dict[str, [LookMLModelConfig](#lookmlmodelconfig)] | ✓ | Named LookML model collections nested under this source. |
|
|
2684
2708
|
| `path` | str | ✓ | DuckDB file path or ':memory:' for an in-memory database. |
|
|
2685
2709
|
| `schema` | str | ✓ | Default schema for unqualified table names (sets search_path). |
|
|
2686
2710
|
|
|
@@ -2688,10 +2712,12 @@ DuckDB source configuration.
|
|
|
2688
2712
|
## SQLiteSourceConfig
|
|
2689
2713
|
SQLite source configuration.
|
|
2690
2714
|
|
|
2691
|
-
| Field | Type | Description |
|
|
2692
|
-
|
|
2693
|
-
| `type` | enum: "sqlite" | Source type identifier. |
|
|
2694
|
-
| `path` | str | Path to the SQLite database file. |
|
|
2715
|
+
| Field | Type | Optional | Description |
|
|
2716
|
+
|-------|------|:--------:|-------------|
|
|
2717
|
+
| `type` | enum: "sqlite" | | Source type identifier. |
|
|
2718
|
+
| `path` | str | | Path to the SQLite database file. |
|
|
2719
|
+
| `lookml_path` | str | ✓ | Relative path to the directory of .lkml files backing this source's models. |
|
|
2720
|
+
| `models` | dict[str, [LookMLModelConfig](#lookmlmodelconfig)] | ✓ | Named LookML model collections nested under this source. |
|
|
2695
2721
|
|
|
2696
2722
|
<a id="csvsourceconfig"></a>
|
|
2697
2723
|
## CsvSourceConfig
|
|
@@ -2743,16 +2769,6 @@ Reference to a dbt profile.
|
|
|
2743
2769
|
| `target` | str | ✓ | dbt target to use; defaults to the profile's default target. |
|
|
2744
2770
|
| `profiles_dir` | str | ✓ | Directory containing profiles.yml, relative to the dataface project root. Use when profiles.yml is in a subdirectory (e.g. services/dbt). Resolution order: profiles_dir → $DBT_PROFILES_DIR → project root → ~/.dbt. |
|
|
2745
2771
|
|
|
2746
|
-
<a id="lookmlsourceconfig"></a>
|
|
2747
|
-
## LookMLSourceConfig
|
|
2748
|
-
Reference to a directory of LookML (.lkml) model files.
|
|
2749
|
-
|
|
2750
|
-
| Field | Type | Description |
|
|
2751
|
-
|-------|------|-------------|
|
|
2752
|
-
| `type` | enum: "lookml" | Source type identifier. |
|
|
2753
|
-
| `path` | str | Relative path to the directory of .lkml files, relative to the project root. |
|
|
2754
|
-
| `base_source` | str | Name of an existing Dataface warehouse source to execute compiled queries against. |
|
|
2755
|
-
|
|
2756
2772
|
<a id="variableref"></a>
|
|
2757
2773
|
## VariableRef
|
|
2758
2774
|
Cross-file variable reference. Bare string is coerced automatically.
|
|
@@ -2776,3 +2792,13 @@ Cross-file chart reference. Bare string is coerced automatically.
|
|
|
2776
2792
|
| Field | Type | Description |
|
|
2777
2793
|
|-------|------|-------------|
|
|
2778
2794
|
| `ref` | str | Reference path: '<file>.charts.<name>'. A bare string value is coerced automatically. |
|
|
2795
|
+
|
|
2796
|
+
<a id="lookmlmodelconfig"></a>
|
|
2797
|
+
## LookMLModelConfig
|
|
2798
|
+
One LookML model: a named collection of explores under a warehouse source.
|
|
2799
|
+
|
|
2800
|
+
| Field | Type | Optional | Description |
|
|
2801
|
+
|-------|------|:--------:|-------------|
|
|
2802
|
+
| `lkml` | str | ✓ | Path to a specific .lkml model file, relative to the project root. |
|
|
2803
|
+
| `group_label` | str | ✓ | LookML group_label selecting this model's explores. Not yet enforced at compile time. |
|
|
2804
|
+
| `explores` | list[str] | ✓ | Explicit list of explore names in this model. |
|
dataface/cli/_error_format.py
CHANGED
|
@@ -17,7 +17,11 @@ from typing import Literal
|
|
|
17
17
|
from rich.panel import Panel
|
|
18
18
|
|
|
19
19
|
from dataface.cli._console import dft_console
|
|
20
|
+
|
|
21
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
20
22
|
from dataface.core.errors import StructuredError
|
|
23
|
+
|
|
24
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
21
25
|
from dataface.core.warnings.base import RenderWarning
|
|
22
26
|
|
|
23
27
|
|
|
@@ -21,6 +21,7 @@ from dataclasses import dataclass
|
|
|
21
21
|
|
|
22
22
|
import uvicorn
|
|
23
23
|
|
|
24
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
24
25
|
from dataface.core.serve.embedded import build_embedded_server
|
|
25
26
|
|
|
26
27
|
# Seconds to wait for uvicorn to flip ``started``. A real bind failure surfaces
|
dataface/cli/commands/init.py
CHANGED
dataface/cli/commands/render.py
CHANGED
|
@@ -14,11 +14,23 @@ from dataface.agent_api._paths import (
|
|
|
14
14
|
from dataface.agent_api.cache import cache_ctx
|
|
15
15
|
from dataface.agent_api.dashboards import RenderedDashboard
|
|
16
16
|
from dataface.cli._error_format import print_structured_errors
|
|
17
|
+
|
|
18
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
17
19
|
from dataface.core.dashboard import RenderFormat
|
|
20
|
+
|
|
21
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
18
22
|
from dataface.core.errors import StructuredError
|
|
23
|
+
|
|
24
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
19
25
|
from dataface.core.render.warnings import registry as _warnings_registry
|
|
26
|
+
|
|
27
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
20
28
|
from dataface.core.warnings import unreferenced_chart
|
|
29
|
+
|
|
30
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
21
31
|
from dataface.core.warnings.base import RenderWarning
|
|
32
|
+
|
|
33
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
22
34
|
from dataface.core.warnings.from_query_diagnostic import KNOWN_RENDER_CODES
|
|
23
35
|
|
|
24
36
|
# Compile-time warning producers don't live on detector modules in the registry,
|
dataface/cli/commands/schema.py
CHANGED
|
@@ -33,6 +33,8 @@ from dataface.agent_api.schema import SchemaResponse, is_exact_target
|
|
|
33
33
|
from dataface.agent_api.schema_search import SchemaSearchResult
|
|
34
34
|
from dataface.cli._error_format import print_structured_errors
|
|
35
35
|
from dataface.cli._parsing import parse_kv_pairs
|
|
36
|
+
|
|
37
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
36
38
|
from dataface.core.errors import DF_UNKNOWN_INTERNAL, StructuredError
|
|
37
39
|
|
|
38
40
|
|
dataface/cli/commands/serve.py
CHANGED
|
@@ -8,7 +8,11 @@ import typer
|
|
|
8
8
|
import uvicorn
|
|
9
9
|
|
|
10
10
|
from dataface.cli._error_format import print_structured_errors
|
|
11
|
+
|
|
12
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
11
13
|
from dataface.core.errors import DF_SERVE_STARTUP_FAILED
|
|
14
|
+
|
|
15
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
12
16
|
from dataface.core.errors.base import DatafaceError
|
|
13
17
|
|
|
14
18
|
|
|
@@ -56,11 +60,22 @@ def serve_command(
|
|
|
56
60
|
Returns:
|
|
57
61
|
None (exits with code 0 on success, 1 on errors)
|
|
58
62
|
"""
|
|
63
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
59
64
|
from dataface.core.compile.config import list_built_in_themes, load_config
|
|
65
|
+
|
|
66
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
60
67
|
from dataface.core.errors import DF_SERVE_INVALID_DEFAULT_THEME
|
|
68
|
+
|
|
69
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
61
70
|
from dataface.core.project import Project
|
|
71
|
+
|
|
72
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
62
73
|
from dataface.core.project_roots import find_dft_root, infer_dialect_from_dbt
|
|
74
|
+
|
|
75
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
63
76
|
from dataface.core.serve.port import resolve_port
|
|
77
|
+
|
|
78
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
64
79
|
from dataface.core.serve.server import create_server
|
|
65
80
|
|
|
66
81
|
# Resolve the project root: --project-dir if given, else discover from cwd.
|
|
@@ -7,6 +7,8 @@ from pathlib import Path
|
|
|
7
7
|
import typer
|
|
8
8
|
|
|
9
9
|
from dataface.agent_api import skill_install
|
|
10
|
+
|
|
11
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
10
12
|
from dataface.core.project_roots import find_dft_root, find_repo_root
|
|
11
13
|
|
|
12
14
|
_VALID_TARGETS = skill_install.SKILL_INSTALL_TARGETS
|
dataface/cli/main.py
CHANGED
|
@@ -33,7 +33,11 @@ from dataface.cli.commands import (
|
|
|
33
33
|
)
|
|
34
34
|
from dataface.cli.commands.mcp_init import run_init as _mcp_run_init
|
|
35
35
|
from dataface.cli.commands.skills_init import run_init_skills as _skills_run_init
|
|
36
|
+
|
|
37
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
36
38
|
from dataface.core.dashboard import RenderFormat
|
|
39
|
+
|
|
40
|
+
# tach-ignore(cli->core debt: route via agent_api; burn-down task)
|
|
37
41
|
from dataface.core.project_roots import find_dft_root
|
|
38
42
|
|
|
39
43
|
# Evaluated once at process startup — mid-session env changes won't take effect.
|
|
@@ -615,6 +619,7 @@ def mcp_serve(
|
|
|
615
619
|
}
|
|
616
620
|
"""
|
|
617
621
|
try:
|
|
622
|
+
# tach-ignore(cli->ai debt: migrate lazy `dft mcp serve` import to dataface.cli._extras; burn-down task)
|
|
618
623
|
from dataface.ai.mcp import run_server
|
|
619
624
|
except ImportError as e:
|
|
620
625
|
typer.echo("MCP server requires additional dependencies.", err=True)
|
|
@@ -90,11 +90,9 @@ from dataface.core.compile.models.query.normalized import (
|
|
|
90
90
|
AnyQuery,
|
|
91
91
|
DbtModelQuery,
|
|
92
92
|
HttpQuery,
|
|
93
|
-
MetricFlowQuery,
|
|
94
93
|
SqlQuery,
|
|
95
94
|
is_dbt_model_query,
|
|
96
95
|
is_http_query,
|
|
97
|
-
is_metricflow_query,
|
|
98
96
|
is_sql_query,
|
|
99
97
|
)
|
|
100
98
|
from dataface.core.compile.models.source import (
|
|
@@ -105,7 +103,8 @@ from dataface.core.compile.models.source import (
|
|
|
105
103
|
DuckDBSourceConfig,
|
|
106
104
|
HttpSourceConfig,
|
|
107
105
|
JsonSourceConfig,
|
|
108
|
-
|
|
106
|
+
LookMLModelConfig,
|
|
107
|
+
LookMLModelsMixin,
|
|
109
108
|
MySQLSourceConfig,
|
|
110
109
|
ParquetSourceConfig,
|
|
111
110
|
PostgresSourceConfig,
|
|
@@ -173,7 +172,6 @@ __all__ = [
|
|
|
173
172
|
"ChartDependencies",
|
|
174
173
|
# Unified query types
|
|
175
174
|
"SqlQuery",
|
|
176
|
-
"MetricFlowQuery",
|
|
177
175
|
"HttpQuery",
|
|
178
176
|
"DbtModelQuery",
|
|
179
177
|
"VALID_QUERY_TYPES",
|
|
@@ -191,7 +189,8 @@ __all__ = [
|
|
|
191
189
|
"JsonSourceConfig",
|
|
192
190
|
"HttpSourceConfig",
|
|
193
191
|
"DbtProfileSourceConfig",
|
|
194
|
-
"
|
|
192
|
+
"LookMLModelConfig",
|
|
193
|
+
"LookMLModelsMixin",
|
|
195
194
|
"VALID_SOURCE_TYPES",
|
|
196
195
|
"parse_source_config",
|
|
197
196
|
"is_database_source",
|
|
@@ -213,7 +212,6 @@ __all__ = [
|
|
|
213
212
|
"is_face",
|
|
214
213
|
"is_chart",
|
|
215
214
|
"is_sql_query",
|
|
216
|
-
"is_metricflow_query",
|
|
217
215
|
"is_http_query",
|
|
218
216
|
"is_dbt_model_query",
|
|
219
217
|
# Enums
|
|
@@ -35,7 +35,7 @@ from dataclasses import dataclass, field
|
|
|
35
35
|
from typing import TYPE_CHECKING, Any
|
|
36
36
|
|
|
37
37
|
import yaml
|
|
38
|
-
from pydantic import ValidationError as PydanticValidationError
|
|
38
|
+
from pydantic import BaseModel, ValidationError as PydanticValidationError
|
|
39
39
|
|
|
40
40
|
from dataface.core.compile.authoring_warnings import detect_authoring_warnings
|
|
41
41
|
from dataface.core.compile.config import ProjectSourcesConfig
|
|
@@ -57,11 +57,16 @@ from dataface.core.compile.models.face.authored import (
|
|
|
57
57
|
QueryOrRef,
|
|
58
58
|
)
|
|
59
59
|
from dataface.core.compile.models.face.normalized import Face
|
|
60
|
+
from dataface.core.compile.models.query.authored import AuthoredQuery
|
|
60
61
|
from dataface.core.compile.models.query.normalized import AnyQuery
|
|
61
62
|
from dataface.core.compile.models.refs import ChartRef, QueryRef, VariableRef
|
|
62
63
|
from dataface.core.compile.models.variable.authored import Variable
|
|
63
64
|
from dataface.core.compile.normalize_charts import collect_lookml_channel_refs
|
|
64
|
-
from dataface.core.compile.
|
|
65
|
+
from dataface.core.compile.normalize_queries import find_lookml_model_source
|
|
66
|
+
from dataface.core.compile.normalize_variables import (
|
|
67
|
+
VariableReferenceErrors,
|
|
68
|
+
synthetic_query_name,
|
|
69
|
+
)
|
|
65
70
|
from dataface.core.compile.normalizer import normalize_face, normalize_query
|
|
66
71
|
from dataface.core.compile.parser import (
|
|
67
72
|
load_yaml_mapping,
|
|
@@ -200,23 +205,79 @@ def compile_authored_face(
|
|
|
200
205
|
except CompilationError as e:
|
|
201
206
|
return CompileResult(errors=[e.to_structured()])
|
|
202
207
|
|
|
208
|
+
# ════════════════════════════════════════════════════════════════════
|
|
209
|
+
# STEP 3b.5: Desugar chart-level `model: model.explore` sugar into a
|
|
210
|
+
# synthesized named lookml query, before Surface B channel collection
|
|
211
|
+
# (below) so the synthesized query is visible to that pass. Runs
|
|
212
|
+
# unconditionally (not gated on lookml_model_names) so an unknown/
|
|
213
|
+
# ambiguous `model:` name still raises a clear error.
|
|
214
|
+
# ════════════════════════════════════════════════════════════════════
|
|
215
|
+
try:
|
|
216
|
+
collectible_charts = dict(chart_registry)
|
|
217
|
+
_collect_inline_layout_charts(authored, collectible_charts)
|
|
218
|
+
if authored.queries is None:
|
|
219
|
+
authored.queries = {}
|
|
220
|
+
for _chart_key, _chart_def in collectible_charts.items():
|
|
221
|
+
# Use BaseModel (not _BaseChartFields) for dump so callout charts and
|
|
222
|
+
# other non-_BaseChartFields models are serialised to a dict first.
|
|
223
|
+
if isinstance(_chart_def, BaseModel):
|
|
224
|
+
_chart_dict = _chart_def.model_dump(exclude_none=True)
|
|
225
|
+
elif isinstance(_chart_def, dict):
|
|
226
|
+
_chart_dict = _chart_def
|
|
227
|
+
else:
|
|
228
|
+
continue
|
|
229
|
+
_model_value = _chart_dict.get("model")
|
|
230
|
+
if not _model_value:
|
|
231
|
+
continue
|
|
232
|
+
if _chart_dict.get("query") is not None:
|
|
233
|
+
raise CompilationError(
|
|
234
|
+
f"chart '{_chart_key}' sets both `model:` and `query:` — "
|
|
235
|
+
"`model:` is sugar for a query, so only one may be set."
|
|
236
|
+
)
|
|
237
|
+
_parts = _model_value.split(".")
|
|
238
|
+
if len(_parts) != 2 or not all(_parts):
|
|
239
|
+
raise CompilationError(
|
|
240
|
+
f"chart '{_chart_key}' has `model: {_model_value!r}` — expected "
|
|
241
|
+
"`model.explore` (a LookML model name and explore name "
|
|
242
|
+
"joined by a dot)."
|
|
243
|
+
)
|
|
244
|
+
_model_name, _explore_name = _parts
|
|
245
|
+
if find_lookml_model_source(_model_name, sources_registry) is None:
|
|
246
|
+
raise CompilationError(
|
|
247
|
+
f"chart '{_chart_key}' has `model: {_model_value}` naming "
|
|
248
|
+
f"unknown model '{_model_name}' — no source declares it in its "
|
|
249
|
+
"'models:' map."
|
|
250
|
+
)
|
|
251
|
+
_synth_name = synthetic_query_name("model_query", _chart_key)
|
|
252
|
+
authored.queries[_synth_name] = AuthoredQuery(
|
|
253
|
+
source=_model_name, explore=_explore_name
|
|
254
|
+
)
|
|
255
|
+
# Mutate in place: _BaseChartFields declares query + model; plain
|
|
256
|
+
# dicts use key assignment. Non-_BaseChartFields BaseModels (e.g.
|
|
257
|
+
# CalloutChart) have no `model:` field and are skipped above.
|
|
258
|
+
if isinstance(_chart_def, _BaseChartFields):
|
|
259
|
+
_chart_def.query = _synth_name
|
|
260
|
+
_chart_def.model = None
|
|
261
|
+
elif isinstance(_chart_def, dict):
|
|
262
|
+
_chart_def["query"] = _synth_name
|
|
263
|
+
_chart_def.pop("model", None)
|
|
264
|
+
except CompilationError as e:
|
|
265
|
+
return CompileResult(errors=[e.to_structured()])
|
|
266
|
+
|
|
203
267
|
# ════════════════════════════════════════════════════════════════════
|
|
204
268
|
# STEP 3c: Collect LookML dotted-ref chart channels into fields-less
|
|
205
269
|
# lookml queries (Surface B), before query normalization lowers them.
|
|
206
270
|
# ════════════════════════════════════════════════════════════════════
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if lookml_source_names:
|
|
271
|
+
lookml_model_names: set[str] = set()
|
|
272
|
+
for _cfg in sources_registry.values():
|
|
273
|
+
if isinstance(_cfg, dict) and isinstance(_cfg.get("models"), dict):
|
|
274
|
+
lookml_model_names.update(_cfg["models"].keys())
|
|
275
|
+
if lookml_model_names:
|
|
213
276
|
try:
|
|
214
277
|
raw_queries: dict[str, QueryOrRef] = {}
|
|
215
278
|
_collect_raw_queries(authored, raw_queries)
|
|
216
|
-
collectible_charts = dict(chart_registry)
|
|
217
|
-
_collect_inline_layout_charts(authored, collectible_charts)
|
|
218
279
|
collect_lookml_channel_refs(
|
|
219
|
-
collectible_charts, raw_queries,
|
|
280
|
+
collectible_charts, raw_queries, lookml_model_names
|
|
220
281
|
)
|
|
221
282
|
except CompilationError as e:
|
|
222
283
|
return CompileResult(errors=[e.to_structured()])
|
|
@@ -852,6 +913,7 @@ def _process_queries_for_registry(
|
|
|
852
913
|
query_def,
|
|
853
914
|
default_source=effective_default_source,
|
|
854
915
|
sources=sources,
|
|
916
|
+
base_dir=base_dir,
|
|
855
917
|
)
|
|
856
918
|
|
|
857
919
|
|
|
@@ -1016,7 +1078,7 @@ def load_from_reference(
|
|
|
1016
1078
|
item_def = section[item_name]
|
|
1017
1079
|
|
|
1018
1080
|
if section_name == "queries":
|
|
1019
|
-
return normalize_query(item_name, item_def)
|
|
1081
|
+
return normalize_query(item_name, item_def, base_dir=base_dir)
|
|
1020
1082
|
if section_name == "charts":
|
|
1021
1083
|
return item_def
|
|
1022
1084
|
# section_name == "variables"
|
|
@@ -28,7 +28,7 @@ from dataface.core.compile.models.source import (
|
|
|
28
28
|
DuckDBSourceConfig,
|
|
29
29
|
HttpSourceConfig,
|
|
30
30
|
JsonSourceConfig,
|
|
31
|
-
|
|
31
|
+
LookMLModelConfig,
|
|
32
32
|
MySQLSourceConfig,
|
|
33
33
|
ParquetSourceConfig,
|
|
34
34
|
PostgresSourceConfig,
|
|
@@ -96,8 +96,9 @@ def _unwrap_annotated(annotation: Any) -> Any:
|
|
|
96
96
|
def _is_authored_model(cls: Any) -> bool:
|
|
97
97
|
"""Return True if cls should be included in the IR.
|
|
98
98
|
|
|
99
|
-
Includes authored.* models, primitives, _PatchBase subclasses,
|
|
100
|
-
style models from style/theme
|
|
99
|
+
Includes authored.* models, primitives, _PatchBase subclasses, compiled
|
|
100
|
+
style models from style/theme/, and LookMLModelConfig so
|
|
101
|
+
dict[str, LookMLModelConfig] fields emit additionalProperties refs in JSON Schema.
|
|
101
102
|
"""
|
|
102
103
|
if not (isinstance(cls, type) and issubclass(cls, BaseModel)):
|
|
103
104
|
return False
|
|
@@ -109,6 +110,7 @@ def _is_authored_model(cls: Any) -> bool:
|
|
|
109
110
|
or module.endswith("primitives")
|
|
110
111
|
or module.endswith("style.theme")
|
|
111
112
|
or ".style.theme." in module
|
|
113
|
+
or issubclass(cls, LookMLModelConfig)
|
|
112
114
|
)
|
|
113
115
|
|
|
114
116
|
|
|
@@ -501,7 +503,7 @@ def introspect() -> AuthorableSchema:
|
|
|
501
503
|
JsonSourceConfig,
|
|
502
504
|
HttpSourceConfig,
|
|
503
505
|
DbtProfileSourceConfig,
|
|
504
|
-
|
|
506
|
+
LookMLModelConfig,
|
|
505
507
|
# Compiled style root — walks style/theme/ types so inherit-chain metadata
|
|
506
508
|
# (Inherit/InheritSlot markers) is visible in the schema IR.
|
|
507
509
|
Style,
|
|
@@ -121,6 +121,15 @@ class _BaseChartFields(BaseModel):
|
|
|
121
121
|
default=None, description="Click-through URL template for drill-down links."
|
|
122
122
|
),
|
|
123
123
|
]
|
|
124
|
+
# Semantic-layer chart sugar: normalizer desugars this into a synthesized
|
|
125
|
+
# named query and clears the field. Mutually exclusive with `query:`.
|
|
126
|
+
model: Annotated[
|
|
127
|
+
str | None,
|
|
128
|
+
Field(
|
|
129
|
+
default=None,
|
|
130
|
+
description="Semantic-layer entry point: 'model.explore' (LookML model name and explore joined by a dot). Mutually exclusive with `query:`.",
|
|
131
|
+
),
|
|
132
|
+
]
|
|
124
133
|
|
|
125
134
|
@model_validator(mode="before")
|
|
126
135
|
@classmethod
|
|
@@ -25,7 +25,6 @@ from dataface.core.compile.models.chart.authored import (
|
|
|
25
25
|
from dataface.core.compile.models.primitives import FormatConfig
|
|
26
26
|
from dataface.core.compile.models.query.normalized import (
|
|
27
27
|
AnyQuery,
|
|
28
|
-
MetricFlowQuery,
|
|
29
28
|
SchemaQuery,
|
|
30
29
|
SqlQuery,
|
|
31
30
|
)
|
|
@@ -84,7 +83,7 @@ class Chart(BaseModel):
|
|
|
84
83
|
id: str = Field(description="Unique identifier within the dashboard.")
|
|
85
84
|
query: AnyQuery | None = Field(
|
|
86
85
|
default=None,
|
|
87
|
-
description="Resolved query object (SqlQuery,
|
|
86
|
+
description="Resolved query object (SqlQuery, HttpQuery, etc.). None for blank/placeholder charts.",
|
|
88
87
|
)
|
|
89
88
|
query_name: str | None = Field(
|
|
90
89
|
default=None,
|
|
@@ -378,7 +377,7 @@ class Chart(BaseModel):
|
|
|
378
377
|
if isinstance(self.query, SqlQuery) and self.query.sql:
|
|
379
378
|
query_dict["sql"] = self.query.sql
|
|
380
379
|
if (
|
|
381
|
-
isinstance(self.query, (SqlQuery,
|
|
380
|
+
isinstance(self.query, (SqlQuery, SchemaQuery))
|
|
382
381
|
and isinstance(self.query.source, str)
|
|
383
382
|
and self.query.source
|
|
384
383
|
):
|