dataface 0.4.1.dev224__py3-none-any.whl → 0.4.1.dev304__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/DATAFACE_SYNTAX.md +9 -9
- dataface/__init__.py +7 -7
- dataface/agent_api/__init__.py +23 -20
- dataface/agent_api/_init_templates/README.md +3 -3
- dataface/agent_api/_init_templates/guide.yaml +1 -1
- dataface/agent_api/_init_templates/meta.yaml +1 -1
- dataface/agent_api/_link_scan.py +7 -7
- dataface/agent_api/_paths.py +14 -14
- dataface/agent_api/board_artifact.py +3 -3
- dataface/agent_api/{dashboards.py → boards.py} +24 -24
- dataface/agent_api/cache.py +1 -1
- dataface/agent_api/data_paths.py +2 -3
- dataface/agent_api/describe.py +25 -17
- dataface/agent_api/docs/yaml-reference.md +16 -17
- dataface/agent_api/file_refs.py +1 -1
- dataface/agent_api/files.py +21 -21
- dataface/agent_api/init.py +11 -9
- dataface/agent_api/migrate.py +7 -6
- dataface/agent_api/pack.py +18 -17
- dataface/agent_api/project_session.py +11 -11
- dataface/agent_api/query.py +8 -8
- dataface/agent_api/search.py +31 -29
- dataface/agent_api/serve.py +2 -2
- dataface/agent_api/skills.py +1 -1
- dataface/agent_api/surface_aliases.yaml +27 -27
- dataface/agent_api/validate.py +40 -32
- dataface/ai/__init__.py +4 -13
- dataface/ai/agent.py +6 -6
- dataface/ai/context.py +10 -5
- dataface/ai/llm.py +77 -11
- dataface/ai/mcp/__init__.py +8 -8
- dataface/ai/mcp/server.py +16 -16
- dataface/ai/prompts.py +9 -9
- dataface/ai/skills/analyst-runbook/SKILL.md +5 -5
- dataface/ai/skills/{dashboard-build → board-build}/SKILL.md +21 -27
- dataface/ai/skills/{dashboard-design → board-design}/SKILL.md +6 -12
- dataface/ai/skills/{dashboard-pack-scaffolding → board-pack-scaffolding}/SKILL.md +14 -14
- dataface/ai/skills/{dashboard-replicate → board-replicate}/SKILL.md +7 -15
- dataface/ai/skills/{dashboard-review → board-review}/SKILL.md +10 -14
- dataface/ai/skills/{dashboard-structural-review → board-structural-review}/SKILL.md +10 -10
- dataface/ai/skills/{dashboard-visual-review → board-visual-review}/SKILL.md +8 -8
- dataface/ai/skills/data-exploration/SKILL.md +1 -1
- dataface/ai/skills/dataface-mcp-setup/SKILL.md +10 -10
- dataface/ai/skills/dataface-troubleshooting/SKILL.md +7 -7
- dataface/ai/skills/drill-down-link/SKILL.md +1 -1
- dataface/ai/skills/report-design/SKILL.md +3 -3
- dataface/ai/tool_schemas.py +36 -43
- dataface/ai/tools/__init__.py +26 -67
- dataface/cli/_error_format.py +3 -4
- dataface/cli/_extras.py +23 -10
- dataface/cli/_project.py +11 -10
- dataface/cli/commands/init.py +1 -1
- dataface/cli/commands/inspect.py +4 -3
- dataface/cli/commands/mcp_init.py +5 -5
- dataface/cli/commands/migrate.py +2 -2
- dataface/cli/commands/query.py +5 -5
- dataface/cli/commands/render.py +8 -8
- dataface/cli/commands/search.py +1 -1
- dataface/cli/commands/serve.py +3 -3
- dataface/cli/filesystem_project.py +7 -7
- dataface/cli/main.py +44 -44
- dataface/core/__init__.py +8 -8
- dataface/core/{dashboard.py → board.py} +36 -36
- dataface/core/compile/__init__.py +16 -16
- dataface/core/compile/authoring_warnings.py +1 -1
- dataface/core/compile/board_artifact.py +11 -11
- dataface/core/compile/chart_focus.py +5 -5
- dataface/core/compile/compiler.py +94 -89
- dataface/core/compile/config.py +36 -37
- dataface/core/compile/data_table.py +31 -1
- dataface/core/compile/face_warnings.py +11 -11
- dataface/core/compile/introspection.py +9 -9
- dataface/core/compile/markdown.py +3 -3
- dataface/core/compile/merge.py +68 -35
- dataface/core/compile/meta.py +6 -6
- dataface/core/compile/migrations/__init__.py +2 -0
- dataface/core/compile/migrations/migrations.py +459 -50
- dataface/core/compile/migrations/versions/__init__.py +0 -16
- dataface/core/compile/migrations/versions/current.py +29 -0
- dataface/core/compile/migrations/versions/v0_4_0.py +2 -2
- dataface/core/compile/migrations/versions/v0_5_0.py +40 -0
- dataface/core/compile/models/{face → board}/authored.py +20 -20
- dataface/core/compile/models/{face → board}/normalized.py +45 -43
- dataface/core/compile/models/{face → board}/patch.py +8 -8
- dataface/core/compile/models/{face → board}/resolved.py +9 -9
- dataface/core/compile/models/cache.py +2 -2
- dataface/core/compile/models/chart/resolved/_base.py +2 -2
- dataface/core/compile/models/chart/resolved/_channel.py +1 -1
- dataface/core/compile/models/config.py +7 -7
- dataface/core/compile/models/primitives.py +10 -10
- dataface/core/compile/models/query/authored.py +2 -2
- dataface/core/compile/models/refs.py +3 -3
- dataface/core/compile/models/source.py +3 -3
- dataface/core/compile/models/style/authored/table.py +1 -1
- dataface/core/compile/models/style/context.py +20 -16
- dataface/core/compile/models/style/resolved/__init__.py +9 -52
- dataface/core/compile/models/style/resolved/_base.py +2 -3
- dataface/core/compile/models/style/resolved/_marks.py +3 -2
- dataface/core/compile/models/style/theme/board.py +4 -4
- dataface/core/compile/models/style/theme/legend.py +0 -3
- dataface/core/compile/models/style/theme/style.py +1 -1
- dataface/core/compile/normalize_charts.py +5 -5
- dataface/core/compile/normalize_layout.py +35 -35
- dataface/core/compile/normalize_queries.py +4 -4
- dataface/core/compile/normalize_variables.py +13 -13
- dataface/core/compile/normalizer.py +46 -48
- dataface/core/compile/parser.py +15 -15
- dataface/core/compile/resolve/__init__.py +9 -32
- dataface/core/compile/resolve/chart/__init__.py +56 -0
- dataface/core/compile/resolve/{_axes.py → chart/_axes.py} +119 -36
- dataface/core/compile/resolve/{_channels.py → chart/_channels.py} +8 -8
- dataface/core/compile/resolve/{_dispatch.py → chart/_dispatch.py} +11 -11
- dataface/core/compile/resolve/{_domain.py → chart/_domain.py} +40 -29
- dataface/core/compile/resolve/{_kwargs.py → chart/_kwargs.py} +3 -6
- dataface/core/compile/resolve/{_layers.py → chart/_layers.py} +3 -3
- dataface/core/compile/resolve/{_links.py → chart/_links.py} +1 -1
- dataface/core/compile/resolve/{_marks.py → chart/_marks.py} +1 -3
- dataface/core/compile/resolve/{_palette.py → chart/_palette.py} +7 -5
- dataface/core/compile/resolve/{_table.py → chart/_table.py} +7 -9
- dataface/core/compile/resolve/{adaptive_stroke.py → chart/adaptive_stroke.py} +1 -1
- dataface/core/compile/resolve/{area.py → chart/area.py} +44 -28
- dataface/core/compile/resolve/{bar.py → chart/bar.py} +69 -21
- dataface/core/compile/resolve/{geo.py → chart/geo.py} +5 -5
- dataface/core/compile/resolve/{heatmap.py → chart/heatmap.py} +21 -19
- dataface/core/compile/resolve/{line.py → chart/line.py} +106 -49
- dataface/core/compile/resolve/{pie.py → chart/pie.py} +9 -9
- dataface/core/compile/resolve/{pie_attachment.py → chart/pie_attachment.py} +7 -7
- dataface/core/compile/resolve/{scatter.py → chart/scatter.py} +14 -11
- dataface/core/compile/resolve/{simple.py → chart/simple.py} +7 -10
- dataface/core/compile/resolve/style/__init__.py +49 -0
- dataface/core/compile/resolve/style/axis_cascade.py +943 -0
- dataface/core/compile/resolve/style/board.py +524 -0
- dataface/core/compile/{style_cascade.py → resolve/style/chart_context.py} +10 -451
- dataface/core/compile/{inherit_graph.py → resolve/style/inherit_graph.py} +2 -2
- dataface/core/compile/{inherit_resolver.py → resolve/style/inherit_resolver.py} +1 -1
- dataface/core/compile/resolve/style/scale.py +183 -0
- dataface/core/compile/resolve/style/tokens.py +298 -0
- dataface/core/compile/{typography.py → resolve/style/typography.py} +4 -4
- dataface/core/compile/schema_renderers/board_resolved.py +11 -11
- dataface/core/compile/schema_renderers/highlight_manifest.py +2 -2
- dataface/core/compile/schema_renderers/prompt.py +3 -3
- dataface/core/compile/schema_renderers/textmate_grammar.py +1 -1
- dataface/core/compile/schema_renderers/vscode_schema.py +4 -2
- dataface/core/compile/schema_renderers/yaml_schema.py +3 -3
- dataface/core/compile/schema_renderers/yaml_schema_catalog.py +20 -2
- dataface/core/compile/single_series_allocation.py +8 -8
- dataface/core/compile/sizing.py +6 -6
- dataface/core/compile/source_map.py +1 -1
- dataface/core/compile/validate_formats.py +6 -6
- dataface/core/compile/validator.py +23 -23
- dataface/core/compile/variables.py +1 -1
- dataface/core/compile/vega_lite/mapping.py +6 -8
- dataface/core/compile/yaml_error_formatter.py +14 -4
- dataface/core/compile/yaml_patch.py +5 -5
- dataface/core/defaults/default_config.yml +6 -6
- dataface/core/defaults/themes/_base.yaml +0 -6
- dataface/core/defaults/themes/editorial.yaml +1 -1
- dataface/core/defaults/themes/stark.yaml +1 -1
- dataface/core/diagnostics/__init__.py +2 -0
- dataface/core/diagnostics/codes_compile.py +15 -15
- dataface/core/diagnostics/codes_execute.py +5 -5
- dataface/core/diagnostics/codes_render.py +32 -3
- dataface/core/diagnostics/execution.py +1 -1
- dataface/core/diagnostics/suppression.py +3 -3
- dataface/core/execute/__init__.py +2 -2
- dataface/core/execute/_duckdb_cache_base.py +26 -9
- dataface/core/execute/adapters/adapter_registry.py +5 -5
- dataface/core/execute/adapters/base.py +1 -1
- dataface/core/execute/adapters/dbt_adapter.py +1 -1
- dataface/core/execute/adapters/duckdb_adapter.py +2 -2
- dataface/core/execute/adapters/http_adapter.py +1 -1
- dataface/core/execute/adapters/schema_adapter.py +1 -1
- dataface/core/execute/adapters/sql_adapter.py +2 -2
- dataface/core/execute/adapters/sqlite_adapter.py +4 -3
- dataface/core/execute/adapters/values_adapter.py +1 -1
- dataface/core/execute/cache_backend.py +4 -4
- dataface/core/execute/chart_data_provider.py +1 -1
- dataface/core/execute/chart_resolution.py +9 -2
- dataface/core/execute/collect.py +4 -4
- dataface/core/execute/duckdb_cache.py +3 -3
- dataface/core/execute/executor.py +9 -9
- dataface/core/execute/file_source_materializer.py +1 -1
- dataface/core/execute/parallel.py +1 -1
- dataface/core/execute/recording.py +4 -4
- dataface/core/execute/replay_provider.py +1 -1
- dataface/core/execute/source_resolver.py +2 -2
- dataface/core/execute/trivial_local_cache.py +3 -3
- dataface/core/fonts.py +74 -17
- dataface/core/inspect/renderer.py +1 -1
- dataface/core/inspect/resolver.py +2 -3
- dataface/core/numeric.py +1 -1
- dataface/core/pack/models.py +8 -8
- dataface/core/pack/planner.py +8 -7
- dataface/core/project.py +32 -16
- dataface/core/project_roots.py +10 -8
- dataface/core/registered_views/expander.py +9 -9
- dataface/core/registered_views/query_runner.py +1 -1
- dataface/core/registered_views/render_pipeline.py +13 -13
- dataface/core/registered_views/variable_planner.py +3 -3
- dataface/core/render/__init__.py +3 -3
- dataface/core/render/board_replay.py +8 -8
- dataface/core/render/chart/auto_link.py +5 -5
- dataface/core/render/chart/emitters/_cartesian.py +60 -20
- dataface/core/render/chart/emitters/_channels.py +1 -1
- dataface/core/render/chart/emitters/_measured_label_padding.py +1 -1
- dataface/core/render/chart/emitters/_overlay.py +86 -30
- dataface/core/render/chart/emitters/area.py +9 -0
- dataface/core/render/chart/emitters/bar.py +31 -3
- dataface/core/render/chart/emitters/line.py +13 -2
- dataface/core/render/chart/emitters/pie.py +3 -3
- dataface/core/render/chart/emitters/scatter.py +8 -10
- dataface/core/render/chart/features/__init__.py +0 -3
- dataface/core/render/chart/features/endpoint_labels.py +269 -9
- dataface/core/render/chart/features/mirror_axis.py +1 -1
- dataface/core/render/chart/features/value_labels.py +1 -1
- dataface/core/render/chart/rendering.py +15 -15
- dataface/core/render/chart/spec.py +1 -5
- dataface/core/render/chart/table.py +313 -69
- dataface/core/render/chart/table_overflow.py +1 -1
- dataface/core/render/chart/table_static_pagination.py +79 -0
- dataface/core/render/chart/table_support.py +1 -1
- dataface/core/render/chart/translate.py +2 -86
- dataface/core/render/chart/type_inference.py +1 -1
- dataface/core/render/chart/validation.py +6 -2
- dataface/core/render/chart/vega_lite.py +17 -3
- dataface/core/render/chart/vl_field_maps.py +16 -1
- dataface/core/render/column_packer.py +1 -1
- dataface/core/render/converters/chart.py +7 -0
- dataface/core/render/data_format.py +7 -7
- dataface/core/render/dir_context.py +12 -12
- dataface/core/render/face_resolve.py +169 -58
- dataface/core/render/face_to_dict.py +7 -7
- dataface/core/render/faces.py +18 -18
- dataface/core/render/fonts/NotoEmoji-Regular.ttf +0 -0
- dataface/core/render/fonts/NotoEmoji-Regular.woff2 +0 -0
- dataface/core/render/fonts/_font_face.css +14 -16
- dataface/core/render/json_format.py +3 -3
- dataface/core/render/layout_sizing.py +41 -26
- dataface/core/render/layouts.py +12 -13
- dataface/core/render/prose.py +1 -1
- dataface/core/render/renderer.py +116 -55
- dataface/core/render/sizing.py +206 -80
- dataface/core/render/svg_utils.py +3 -3
- dataface/core/render/templates/scripts/table_pagination.js +42 -0
- dataface/core/render/templates/svg/styles.css +1 -1
- dataface/core/render/terminal.py +7 -7
- dataface/core/render/terminal_charts.py +1 -1
- dataface/core/render/terminal_layouts.py +1 -1
- dataface/core/render/text_format.py +4 -4
- dataface/core/render/variables_resolve.py +2 -2
- dataface/core/render/warnings/base.py +12 -3
- dataface/core/render/warnings/facet_panel_width_below_minimum.py +1 -1
- dataface/core/render/warnings/palette_unsupported.py +2 -2
- dataface/core/render/warnings/registry.py +40 -8
- dataface/core/render/warnings/static_pagination_capped.py +37 -0
- dataface/core/render/yaml_format.py +4 -4
- dataface/core/render_format.py +2 -2
- dataface/core/serve/alias_index.py +18 -18
- dataface/core/serve/port.py +9 -7
- dataface/core/serve/server.py +66 -65
- dataface/core/utils.py +45 -0
- dataface/data/schemas/board-resolved/board-resolved.schema.json +233 -252
- dataface/data/schemas/yaml/0.5.0.json +1 -0
- dataface/data/schemas/yaml/manifest.json +7 -0
- dataface/integrations/markdown.py +16 -11
- {dataface-0.4.1.dev224.dist-info → dataface-0.4.1.dev304.dist-info}/METADATA +11 -11
- {dataface-0.4.1.dev224.dist-info → dataface-0.4.1.dev304.dist-info}/RECORD +281 -276
- dataface/core/compile/chart_update.py +0 -205
- dataface/core/compile/models/style/resolved/_cascade.py +0 -1440
- dataface/core/compile/vega_config.py +0 -39
- dataface/core/render/chart/features/legend_toggle.py +0 -43
- dataface/core/render/fonts/NOTO_COLOR_EMOJI_LICENSE.txt +0 -93
- dataface/core/render/fonts/NotoColorEmoji-Regular.ttf +0 -0
- dataface/core/render/fonts/NotoColorEmoji-Regular.woff2 +0 -0
- /dataface/agent_api/_init_templates/{dataface.yml → dbt_charts.yml} +0 -0
- /dataface/ai/skills/{dashboard-build → board-build}/examples/_smoke.yml +0 -0
- /dataface/core/compile/models/{face → board}/__init__.py +0 -0
- /dataface/core/compile/resolve/{_chart_rows.py → chart/_chart_rows.py} +0 -0
- /dataface/core/compile/{channel.py → resolve/chart/channel.py} +0 -0
- /dataface/core/compile/{enrich.py → resolve/chart/enrich.py} +0 -0
- /dataface/core/compile/{label_data.py → resolve/chart/label_data.py} +0 -0
- /dataface/core/compile/{link_keys.py → resolve/chart/link_keys.py} +0 -0
- /dataface/core/compile/{tick_values.py → resolve/chart/tick_values.py} +0 -0
- /dataface/core/compile/{inherit_registry.yaml → resolve/style/inherit_registry.yaml} +0 -0
- /dataface/core/compile/{palette.py → resolve/style/palette.py} +0 -0
- {dataface-0.4.1.dev224.dist-info → dataface-0.4.1.dev304.dist-info}/WHEEL +0 -0
- {dataface-0.4.1.dev224.dist-info → dataface-0.4.1.dev304.dist-info}/entry_points.txt +0 -0
- {dataface-0.4.1.dev224.dist-info → dataface-0.4.1.dev304.dist-info}/licenses/LICENSE +0 -0
dataface/DATAFACE_SYNTAX.md
CHANGED
|
@@ -11,7 +11,7 @@ Dataface workflow — from a dbt project to a running dashboard.
|
|
|
11
11
|
### Step 1 — Validate your YAML
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
dft validate
|
|
14
|
+
dft validate charts/my_dashboard.yml
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
`dft validate` performs YAML schema + cross-reference validation. It checks that every field, chart reference, query name, and variable is correctly structured. **No database connection is required.**
|
|
@@ -62,8 +62,8 @@ rows:
|
|
|
62
62
|
Then validate and render:
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
dft validate
|
|
66
|
-
dft render
|
|
65
|
+
dft validate charts/my_dashboard.yml
|
|
66
|
+
dft render charts/my_dashboard.yml
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
Add each additional chart after the previous one validates and renders cleanly.
|
|
@@ -189,7 +189,7 @@ title: "Sales Overview"
|
|
|
189
189
|
description: "Monthly KPIs and trend"
|
|
190
190
|
tags: [sales, weekly]
|
|
191
191
|
|
|
192
|
-
source: my_profile # Default source (a name from
|
|
192
|
+
source: my_profile # Default source (a name from dbt_charts.yml's sources: registry)
|
|
193
193
|
|
|
194
194
|
variables: # Optional — interactive controls
|
|
195
195
|
queries: # Named queries
|
|
@@ -220,7 +220,7 @@ Top-level fields (22 total):
|
|
|
220
220
|
| `description` | string | Description text |
|
|
221
221
|
| `tags` | list[string] | Tags for categorization/search |
|
|
222
222
|
| `text` | string | Markdown body for text-only faces |
|
|
223
|
-
| `source` | string | Default source name for every query below (from `
|
|
223
|
+
| `source` | string | Default source name for every query below (from `dbt_charts.yml`'s `sources:` registry), or an inline file path for a single colocated CSV/JSON/Parquet file. Inheritable via the `meta.yaml` cascade. |
|
|
224
224
|
| `variables` | object | See [Variables](#variables) |
|
|
225
225
|
| `queries` | object | See [Queries](#queries) |
|
|
226
226
|
| `charts` | object | See [Charts](#charts) |
|
|
@@ -265,7 +265,7 @@ query param of the same name — which the face then reads as its variable. Thi
|
|
|
265
265
|
gives a single detail face a clean per-entity URL:
|
|
266
266
|
|
|
267
267
|
```yaml
|
|
268
|
-
#
|
|
268
|
+
# charts/milestone.yml (canonical URL: /milestone)
|
|
269
269
|
aliases:
|
|
270
270
|
- /milestones/<name>
|
|
271
271
|
variables:
|
|
@@ -284,7 +284,7 @@ and `milestone.yml` renders with `name` bound to `m3-public-launch`.
|
|
|
284
284
|
treated as patterns.
|
|
285
285
|
|
|
286
286
|
There are two ways to override a data/inspector route for a given path:
|
|
287
|
-
- **Face file at that path** — create `
|
|
287
|
+
- **Face file at that path** — create `charts/data/warehouse/schema/table.yml` and the server renders it directly (no redirect).
|
|
288
288
|
- **`aliases:` entry** — any face can declare `/data/…/` as an alias; the server issues a 302 to the declaring face's canonical URL.
|
|
289
289
|
|
|
290
290
|
Both approaches work. A face file wins without a redirect round-trip; an alias lets a face live anywhere and still capture a system-view URL.
|
|
@@ -411,7 +411,7 @@ Common fields (all query types):
|
|
|
411
411
|
| Field | Description |
|
|
412
412
|
|-------|-------------|
|
|
413
413
|
| `description` | Metadata sentence for AI search and tooltips |
|
|
414
|
-
| `source` | Source name (from `
|
|
414
|
+
| `source` | Source name (from `dbt_charts.yml`'s `sources:` registry), or an inline file path (`./data/x.csv`) for a single colocated CSV/JSON/Parquet. An inline connection dict (`{type: postgres, ...}`) is rejected — reference a named source instead. Not accepted on `http` queries. |
|
|
415
415
|
| `target` | dbt target name (defaults to `dev`) |
|
|
416
416
|
| `filters` | Post-execution result filters |
|
|
417
417
|
| `limit` | Maximum rows returned |
|
|
@@ -424,7 +424,7 @@ HTTP fields: `url`, `method`, `headers`, `params`, `body`, `json_path`.
|
|
|
424
424
|
dbt-model fields: `model`, `columns`.
|
|
425
425
|
Inline-values fields: `columns`, `values` (or `rows` for record-shape).
|
|
426
426
|
|
|
427
|
-
Connection source types (named in the project root `
|
|
427
|
+
Connection source types (named in the project root `dbt_charts.yml`'s `sources:`
|
|
428
428
|
registry — never inline in a face): `postgres`, `snowflake`, `bigquery`,
|
|
429
429
|
`redshift`, `mysql`, `duckdb`, `sqlite`, `csv`, `json`, `parquet`, `http`, `dbt_profile`.
|
|
430
430
|
CSV/JSON/Parquet may instead be referenced inline as a `source:` file path
|
dataface/__init__.py
CHANGED
|
@@ -16,7 +16,7 @@ Quick Start:
|
|
|
16
16
|
>>> from dataface import compile, Executor, render
|
|
17
17
|
>>> from dataface.core.execute.adapters import build_adapter_registry
|
|
18
18
|
>>>
|
|
19
|
-
>>> # Compile YAML to
|
|
19
|
+
>>> # Compile YAML to Board
|
|
20
20
|
>>> result = compile(yaml_content)
|
|
21
21
|
>>> if result.success:
|
|
22
22
|
... face = result.face
|
|
@@ -53,10 +53,10 @@ if TYPE_CHECKING:
|
|
|
53
53
|
from dataface.core import validate as validate
|
|
54
54
|
from dataface.core.compile import (
|
|
55
55
|
AnyQuery as AnyQuery,
|
|
56
|
-
|
|
56
|
+
AuthoredBoard as AuthoredBoard,
|
|
57
|
+
Board as Board,
|
|
57
58
|
CompilationError as CompilationError,
|
|
58
59
|
CompileResult as CompileResult,
|
|
59
|
-
Face as Face,
|
|
60
60
|
Layout as Layout,
|
|
61
61
|
LayoutItem as LayoutItem,
|
|
62
62
|
Variable as Variable,
|
|
@@ -80,11 +80,11 @@ __all__ = [
|
|
|
80
80
|
"compile",
|
|
81
81
|
"compile_file",
|
|
82
82
|
"CompileResult",
|
|
83
|
-
"
|
|
83
|
+
"Board",
|
|
84
84
|
"AnyQuery",
|
|
85
85
|
"Layout",
|
|
86
86
|
"LayoutItem",
|
|
87
|
-
"
|
|
87
|
+
"AuthoredBoard",
|
|
88
88
|
"Variable",
|
|
89
89
|
"CompilationError",
|
|
90
90
|
# Execute
|
|
@@ -105,10 +105,10 @@ __all__ = [
|
|
|
105
105
|
_LAZY_ATTRS: dict[str, tuple[str, str]] = {
|
|
106
106
|
"validate": ("dataface.core", "validate"),
|
|
107
107
|
"AnyQuery": ("dataface.core.compile", "AnyQuery"),
|
|
108
|
-
"
|
|
108
|
+
"AuthoredBoard": ("dataface.core.compile", "AuthoredBoard"),
|
|
109
109
|
"CompilationError": ("dataface.core.compile", "CompilationError"),
|
|
110
110
|
"CompileResult": ("dataface.core.compile", "CompileResult"),
|
|
111
|
-
"
|
|
111
|
+
"Board": ("dataface.core.compile", "Board"),
|
|
112
112
|
"Layout": ("dataface.core.compile", "Layout"),
|
|
113
113
|
"LayoutItem": ("dataface.core.compile", "LayoutItem"),
|
|
114
114
|
"Variable": ("dataface.core.compile", "Variable"),
|
dataface/agent_api/__init__.py
CHANGED
|
@@ -50,9 +50,9 @@ if TYPE_CHECKING:
|
|
|
50
50
|
project_sources_for_face as project_sources_for_face,
|
|
51
51
|
)
|
|
52
52
|
from dataface.agent_api.describe import (
|
|
53
|
-
|
|
53
|
+
DescribeBoardArgs as DescribeBoardArgs,
|
|
54
54
|
DescribeFaceResult as DescribeFaceResult,
|
|
55
|
-
|
|
55
|
+
describe_board as describe_board,
|
|
56
56
|
)
|
|
57
57
|
from dataface.agent_api.docs import (
|
|
58
58
|
DocsArgs as DocsArgs,
|
|
@@ -72,15 +72,20 @@ if TYPE_CHECKING:
|
|
|
72
72
|
from dataface.agent_api.project_session import ProjectSession as ProjectSession
|
|
73
73
|
from dataface.agent_api.query import (
|
|
74
74
|
QueryFaceResult as QueryFaceResult,
|
|
75
|
-
|
|
75
|
+
query_board as query_board,
|
|
76
76
|
)
|
|
77
77
|
from dataface.agent_api.schema_hints import SchemaHints as SchemaHints
|
|
78
78
|
from dataface.agent_api.validate import (
|
|
79
|
-
|
|
79
|
+
ValidateBoardArgs as ValidateBoardArgs,
|
|
80
80
|
ValidateResult as ValidateResult,
|
|
81
81
|
)
|
|
82
82
|
from dataface.agent_api.validate_query import QueryDiagnostic as QueryDiagnostic
|
|
83
83
|
from dataface.core.attribution import set_surface as set_surface
|
|
84
|
+
from dataface.core.board import (
|
|
85
|
+
BoardRenderResult as BoardRenderResult,
|
|
86
|
+
RenderFormat as RenderFormat,
|
|
87
|
+
render_dashboard as render_dashboard,
|
|
88
|
+
)
|
|
84
89
|
from dataface.core.compile.compiler import (
|
|
85
90
|
CompileResult as CompileResult,
|
|
86
91
|
compile as compile,
|
|
@@ -88,11 +93,6 @@ if TYPE_CHECKING:
|
|
|
88
93
|
from dataface.core.compile.config import (
|
|
89
94
|
ProjectSourcesConfig as ProjectSourcesConfig,
|
|
90
95
|
)
|
|
91
|
-
from dataface.core.dashboard import (
|
|
92
|
-
RenderedDashboard as RenderedDashboard,
|
|
93
|
-
RenderFormat as RenderFormat,
|
|
94
|
-
render_dashboard as render_dashboard,
|
|
95
|
-
)
|
|
96
96
|
from dataface.core.diagnostics import Diagnostic as Diagnostic
|
|
97
97
|
from dataface.core.execute.cache_backend import (
|
|
98
98
|
QueryResultCache as QueryResultCache,
|
|
@@ -110,6 +110,7 @@ if TYPE_CHECKING:
|
|
|
110
110
|
FaceFile as FaceFile,
|
|
111
111
|
InMemoryFace as InMemoryFace,
|
|
112
112
|
Project as Project,
|
|
113
|
+
posix_relpath as posix_relpath,
|
|
113
114
|
)
|
|
114
115
|
from dataface.core.render.board_links import LinkContext as LinkContext
|
|
115
116
|
from dataface.core.render.errors import RenderError as RenderError
|
|
@@ -117,7 +118,7 @@ if TYPE_CHECKING:
|
|
|
117
118
|
__all__ = [
|
|
118
119
|
"compile",
|
|
119
120
|
"CompileResult",
|
|
120
|
-
"
|
|
121
|
+
"DescribeBoardArgs",
|
|
121
122
|
"DescribeFaceResult",
|
|
122
123
|
"Diagnostic",
|
|
123
124
|
"DocsArgs",
|
|
@@ -132,15 +133,16 @@ __all__ = [
|
|
|
132
133
|
"Project",
|
|
133
134
|
"ProjectSession",
|
|
134
135
|
"set_surface",
|
|
136
|
+
"posix_relpath",
|
|
135
137
|
"ProjectSourcesConfig",
|
|
136
138
|
"QueryDiagnostic",
|
|
137
139
|
"QueryFaceResult",
|
|
138
|
-
"
|
|
140
|
+
"BoardRenderResult",
|
|
139
141
|
"RenderError",
|
|
140
142
|
"RenderFormat",
|
|
141
143
|
"SchemaHints",
|
|
142
144
|
"Topic",
|
|
143
|
-
"
|
|
145
|
+
"ValidateBoardArgs",
|
|
144
146
|
"ValidateResult",
|
|
145
147
|
# Execution extension seams
|
|
146
148
|
"AllowlistedSourceResolver",
|
|
@@ -148,11 +150,11 @@ __all__ = [
|
|
|
148
150
|
"QueryResultCache",
|
|
149
151
|
"SourceResolver",
|
|
150
152
|
"WarehouseObserver",
|
|
151
|
-
"
|
|
153
|
+
"describe_board",
|
|
152
154
|
"get_fonts_dir",
|
|
153
155
|
"init_project",
|
|
154
156
|
"migrate_paths",
|
|
155
|
-
"
|
|
157
|
+
"query_board",
|
|
156
158
|
"render_dashboard",
|
|
157
159
|
]
|
|
158
160
|
|
|
@@ -177,9 +179,9 @@ _LAZY_ATTRS: dict[str, tuple[str, str]] = {
|
|
|
177
179
|
"dataface.agent_api._paths",
|
|
178
180
|
"project_sources_for_face",
|
|
179
181
|
),
|
|
180
|
-
"
|
|
182
|
+
"DescribeBoardArgs": ("dataface.agent_api.describe", "DescribeBoardArgs"),
|
|
181
183
|
"DescribeFaceResult": ("dataface.agent_api.describe", "DescribeFaceResult"),
|
|
182
|
-
"
|
|
184
|
+
"describe_board": ("dataface.agent_api.describe", "describe_board"),
|
|
183
185
|
"DocsArgs": ("dataface.agent_api.docs", "DocsArgs"),
|
|
184
186
|
"DocsResult": ("dataface.agent_api.docs", "DocsResult"),
|
|
185
187
|
"DocsSearchHit": ("dataface.agent_api.docs", "DocsSearchHit"),
|
|
@@ -191,18 +193,18 @@ _LAZY_ATTRS: dict[str, tuple[str, str]] = {
|
|
|
191
193
|
"migrate_paths": ("dataface.agent_api.migrate", "migrate_paths"),
|
|
192
194
|
"ProjectSession": ("dataface.agent_api.project_session", "ProjectSession"),
|
|
193
195
|
"QueryFaceResult": ("dataface.agent_api.query", "QueryFaceResult"),
|
|
194
|
-
"
|
|
196
|
+
"query_board": ("dataface.agent_api.query", "query_board"),
|
|
195
197
|
"SchemaHints": ("dataface.agent_api.schema_hints", "SchemaHints"),
|
|
196
|
-
"
|
|
198
|
+
"ValidateBoardArgs": ("dataface.agent_api.validate", "ValidateBoardArgs"),
|
|
197
199
|
"ValidateResult": ("dataface.agent_api.validate", "ValidateResult"),
|
|
198
200
|
"QueryDiagnostic": ("dataface.agent_api.validate_query", "QueryDiagnostic"),
|
|
199
201
|
"set_surface": ("dataface.core.attribution", "set_surface"),
|
|
200
202
|
"compile": ("dataface.core.compile.compiler", "compile"),
|
|
201
203
|
"CompileResult": ("dataface.core.compile.compiler", "CompileResult"),
|
|
202
204
|
"ProjectSourcesConfig": ("dataface.core.compile.config", "ProjectSourcesConfig"),
|
|
203
|
-
"
|
|
205
|
+
"BoardRenderResult": ("dataface.core.board", "BoardRenderResult"),
|
|
204
206
|
"RenderFormat": ("dataface.core.render_format", "RenderFormat"),
|
|
205
|
-
"render_dashboard": ("dataface.core.
|
|
207
|
+
"render_dashboard": ("dataface.core.board", "render_dashboard"),
|
|
206
208
|
"Diagnostic": ("dataface.core.diagnostics", "Diagnostic"),
|
|
207
209
|
"QueryResultCache": ("dataface.core.execute.cache_backend", "QueryResultCache"),
|
|
208
210
|
"WarehouseObserver": (
|
|
@@ -222,6 +224,7 @@ _LAZY_ATTRS: dict[str, tuple[str, str]] = {
|
|
|
222
224
|
"FaceFile": ("dataface.core.project", "FaceFile"),
|
|
223
225
|
"InMemoryFace": ("dataface.core.project", "InMemoryFace"),
|
|
224
226
|
"Project": ("dataface.core.project", "Project"),
|
|
227
|
+
"posix_relpath": ("dataface.core.project", "posix_relpath"),
|
|
225
228
|
"LinkContext": ("dataface.core.render.board_links", "LinkContext"),
|
|
226
229
|
"RenderError": ("dataface.core.render.errors", "RenderError"),
|
|
227
230
|
}
|
|
@@ -4,7 +4,7 @@ title: Dataface
|
|
|
4
4
|
|
|
5
5
|
# Welcome to Dataface
|
|
6
6
|
|
|
7
|
-
This is your project's landing page. Everything under `
|
|
7
|
+
This is your project's landing page. Everything under `charts/` becomes a
|
|
8
8
|
served page — edit the files here to build dashboards, reports, and docs
|
|
9
9
|
for your data project.
|
|
10
10
|
|
|
@@ -18,7 +18,7 @@ queries and charts, then embed them inline with `{% raw %}{{ chart my_chart }}{%
|
|
|
18
18
|
|
|
19
19
|
## Next steps
|
|
20
20
|
|
|
21
|
-
1. Open `
|
|
21
|
+
1. Open `charts/guide.yaml` and tweak the content.
|
|
22
22
|
2. Run `dft serve` and open the URL it prints.
|
|
23
|
-
3. Add new `.yaml` or `.md` files under `
|
|
23
|
+
3. Add new `.yaml` or `.md` files under `charts/` — they appear automatically.
|
|
24
24
|
4. Run `dft validate` to validate your face YAML for errors.
|
|
@@ -21,7 +21,7 @@ text: |
|
|
|
21
21
|
Welcome to **Dataface** — dashboards as YAML files.
|
|
22
22
|
|
|
23
23
|
This file is your starter guide. Edit it, add new `.yaml` files under
|
|
24
|
-
`
|
|
24
|
+
`charts/`, and run `dft serve` to preview everything in your browser.
|
|
25
25
|
|
|
26
26
|
# ── Queries ───────────────────────────────────────────────────────────────────
|
|
27
27
|
# `type: values` embeds data directly — no database needed.
|
dataface/agent_api/_link_scan.py
CHANGED
|
@@ -15,18 +15,18 @@ import re
|
|
|
15
15
|
|
|
16
16
|
from pydantic import BaseModel, ConfigDict, Field
|
|
17
17
|
|
|
18
|
-
from dataface.core.project import
|
|
18
|
+
from dataface.core.project import CHARTS_SUBDIR, Project
|
|
19
19
|
|
|
20
|
-
_FACES_GLOB = f"{
|
|
20
|
+
_FACES_GLOB = f"{CHARTS_SUBDIR}/**/*"
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def
|
|
24
|
-
"""Return the dashboard slug for a ``
|
|
23
|
+
def board_slug(relpath: str) -> str | None:
|
|
24
|
+
"""Return the dashboard slug for a ``charts/`` path (no prefix, no suffix).
|
|
25
25
|
|
|
26
|
-
``
|
|
27
|
-
outside ``
|
|
26
|
+
``charts/finance/rev.yml`` -> ``finance/rev``. Returns None for a path
|
|
27
|
+
outside ``charts/`` -- link scanning only has meaning for dashboard slugs.
|
|
28
28
|
"""
|
|
29
|
-
prefix = f"{
|
|
29
|
+
prefix = f"{CHARTS_SUBDIR}/"
|
|
30
30
|
if not relpath.startswith(prefix):
|
|
31
31
|
return None
|
|
32
32
|
tail = relpath[len(prefix) :]
|
dataface/agent_api/_paths.py
CHANGED
|
@@ -16,7 +16,7 @@ from dataface.core.diagnostics import (
|
|
|
16
16
|
)
|
|
17
17
|
from dataface.core.diagnostics.base import DatafaceError
|
|
18
18
|
from dataface.core.project import (
|
|
19
|
-
|
|
19
|
+
CHARTS_SUBDIR as CHARTS_SUBDIR,
|
|
20
20
|
FaceFile,
|
|
21
21
|
Project,
|
|
22
22
|
ProjectPath,
|
|
@@ -37,19 +37,19 @@ if TYPE_CHECKING:
|
|
|
37
37
|
def resolve_face_relpath(relpath: PurePosixPath, project: Project) -> ProjectPath:
|
|
38
38
|
"""Project-relative face identity -> ProjectPath, with the faces-first retry.
|
|
39
39
|
|
|
40
|
-
The relpath-native counterpart to ``
|
|
40
|
+
The relpath-native counterpart to ``resolve_board_path``: for callers that
|
|
41
41
|
already hold a project-relative face identity (Cloud's context strings)
|
|
42
42
|
rather than a real filesystem path, this is the single owner of the
|
|
43
43
|
face-relative vs root-relative reconciliation — a bare name like
|
|
44
|
-
``looker/x.yaml`` retries under ``
|
|
45
|
-
root, without producing a ``
|
|
46
|
-
caller already supplies the full ``
|
|
44
|
+
``looker/x.yaml`` retries under ``CHARTS_SUBDIR`` when it doesn't exist at
|
|
45
|
+
root, without producing a ``charts/charts/...`` double prefix when the
|
|
46
|
+
caller already supplies the full ``charts/looker/x.yaml``.
|
|
47
47
|
|
|
48
48
|
Existence is checked via ``project.exists(...)`` so it works for all
|
|
49
49
|
``Project`` implementations (FilesystemProject, CloudManagedProject
|
|
50
50
|
git-blob store, etc.) — not just the local filesystem. Paths that exist
|
|
51
51
|
at root resolve from root — non-faces paths like ``models/schema.sql``
|
|
52
|
-
are not rewritten under
|
|
52
|
+
are not rewritten under charts/. ``str`` is used only at the identity seam
|
|
53
53
|
(``project.path`` / ``project.exists``); everything else is real
|
|
54
54
|
``PurePosixPath`` operations.
|
|
55
55
|
"""
|
|
@@ -57,8 +57,8 @@ def resolve_face_relpath(relpath: PurePosixPath, project: Project) -> ProjectPat
|
|
|
57
57
|
assert_relpath(relpath_str)
|
|
58
58
|
if project.exists(relpath_str):
|
|
59
59
|
return project.path(relpath_str)
|
|
60
|
-
if not relpath.parts or relpath.parts[0] !=
|
|
61
|
-
candidate = PurePosixPath(
|
|
60
|
+
if not relpath.parts or relpath.parts[0] != CHARTS_SUBDIR:
|
|
61
|
+
candidate = PurePosixPath(CHARTS_SUBDIR) / relpath
|
|
62
62
|
candidate_str = str(candidate)
|
|
63
63
|
if project.exists(candidate_str):
|
|
64
64
|
return project.path(candidate_str)
|
|
@@ -78,7 +78,7 @@ def _relpath_for_fs_location(path: Path, project: Project) -> str:
|
|
|
78
78
|
Two-try containment check (mirrors the pre-refactor behavior): ``resolve()``
|
|
79
79
|
follows symlinks (handles e.g. ``/var`` -> ``/private/var`` on macOS); a
|
|
80
80
|
symlink-blind ``normpath`` fallback accepts paths through intentional
|
|
81
|
-
project-internal symlinks (e.g. ``
|
|
81
|
+
project-internal symlinks (e.g. ``charts/tasks/`` -> ``../../tasks/``).
|
|
82
82
|
Raises ``ValueError`` if neither check places *path* inside the root.
|
|
83
83
|
"""
|
|
84
84
|
if not isinstance(project, FilesystemProject):
|
|
@@ -99,13 +99,13 @@ def _relpath_for_fs_location(path: Path, project: Project) -> str:
|
|
|
99
99
|
raise ValueError(f"Path {path!r} is outside project root {root!r}") from None
|
|
100
100
|
|
|
101
101
|
|
|
102
|
-
def
|
|
102
|
+
def resolve_board_path(path: Path, project: Project) -> ProjectPath:
|
|
103
103
|
"""User/agent-supplied filesystem-shaped face path -> ProjectPath.
|
|
104
104
|
|
|
105
105
|
Absolute and ``..``-leading paths are explicit locations: they relativize
|
|
106
106
|
against a concrete ``FilesystemProject`` root (``_relpath_for_fs_location``,
|
|
107
107
|
a leading ``..`` resolving against cwd for CLI shell-nav feel) and are
|
|
108
|
-
returned as-is — no ``
|
|
108
|
+
returned as-is — no ``charts/`` retry, even when the exact path doesn't
|
|
109
109
|
exist. A bare relative name (no explicit location) delegates to
|
|
110
110
|
``resolve_face_relpath`` for the faces-first retry, which works against
|
|
111
111
|
any ``Project`` implementation.
|
|
@@ -131,7 +131,7 @@ def resolve_face_or_error(path: Path, project: Project) -> FaceFile | Diagnostic
|
|
|
131
131
|
(``ERR-INTERNAL``) or a missing face (``ERR-FILE-NOT-FOUND``).
|
|
132
132
|
"""
|
|
133
133
|
try:
|
|
134
|
-
resolved =
|
|
134
|
+
resolved = resolve_board_path(path, project)
|
|
135
135
|
except ValueError as exc:
|
|
136
136
|
return DatafaceError.from_code(ERR_INTERNAL, message=str(exc)).to_diagnostic()
|
|
137
137
|
if not resolved.exists():
|
|
@@ -238,11 +238,11 @@ def project_sources_for_face(face_path: Path) -> ProjectSourcesConfig:
|
|
|
238
238
|
parse finding trustworthy enough to report.
|
|
239
239
|
|
|
240
240
|
A face outside any project needs no special case: `find_project_root`
|
|
241
|
-
falls back to the starting directory, which has no `
|
|
241
|
+
falls back to the starting directory, which has no `dbt_charts.yml`, and the
|
|
242
242
|
registry comes back empty — compile then stays silent about SQL syntax
|
|
243
243
|
rather than guessing a dialect.
|
|
244
244
|
|
|
245
|
-
A `
|
|
245
|
+
A `dbt_charts.yml` that exists but does not load raises, deliberately. That
|
|
246
246
|
is a real fault at a real location, and swallowing it here would decide on
|
|
247
247
|
the author's behalf that a broken project config is invisible — while
|
|
248
248
|
handing the caller an empty registry indistinguishable from "no project".
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Emit a resolved-board artifact + recording, and render one back.
|
|
2
2
|
|
|
3
3
|
`emit_board_artifact` compiles, resolves, and executes a face, then writes the
|
|
4
|
-
board's published `
|
|
4
|
+
board's published `ResolvedBoard` contract and a data sidecar (the rows it was
|
|
5
5
|
resolved against). `render_board_from_files` reads both back and renders
|
|
6
6
|
without a compile step or a warehouse connection — the "skip the
|
|
7
7
|
compilation" win the resolved-board artifact exists for.
|
|
@@ -22,7 +22,7 @@ from pydantic import BaseModel, ConfigDict
|
|
|
22
22
|
|
|
23
23
|
from dataface.agent_api._paths import resolve_face_or_error
|
|
24
24
|
from dataface.core.compile import compile_file
|
|
25
|
-
from dataface.core.compile.models.
|
|
25
|
+
from dataface.core.compile.models.board.resolved import ChartResolveFailure
|
|
26
26
|
from dataface.core.compile.variables import normalize_multiselect_values
|
|
27
27
|
from dataface.core.diagnostics import ERR_FILE_NOT_FOUND, Diagnostic
|
|
28
28
|
from dataface.core.diagnostics.base import DatafaceError
|
|
@@ -89,7 +89,7 @@ def emit_board_artifact(
|
|
|
89
89
|
) -> EmitBoardArtifactResult:
|
|
90
90
|
"""Compile, resolve, and execute a face, then write its artifact + recording.
|
|
91
91
|
|
|
92
|
-
Writes `artifact_path` (the published, data-free `
|
|
92
|
+
Writes `artifact_path` (the published, data-free `ResolvedBoard` contract)
|
|
93
93
|
and `recording_path` (the rows it was resolved against, the variable
|
|
94
94
|
values, and a `recorded_at` stamp) — kept separate so the board contract
|
|
95
95
|
carries no data payload.
|
|
@@ -21,11 +21,11 @@ else:
|
|
|
21
21
|
|
|
22
22
|
from dataface.agent_api._paths import resolve_face_or_error
|
|
23
23
|
from dataface.agent_api.query import VariableBinding, variables_to_dict as _vars_to_dict
|
|
24
|
-
from dataface.core.
|
|
25
|
-
from dataface.core.
|
|
24
|
+
from dataface.core.board import BoardRenderResult as BoardRenderResult
|
|
25
|
+
from dataface.core.compile import Board, compile_file
|
|
26
26
|
from dataface.core.diagnostics import Diagnostic
|
|
27
27
|
from dataface.core.project import (
|
|
28
|
-
|
|
28
|
+
CHARTS_SUBDIR,
|
|
29
29
|
Project,
|
|
30
30
|
ProjectDirectory,
|
|
31
31
|
ProjectPath,
|
|
@@ -39,7 +39,7 @@ DASHBOARD_KEYS = frozenset({"queries", "charts", "rows", "cols", "grid", "tabs"}
|
|
|
39
39
|
# ---------------------------------------------------------------------------
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
class
|
|
42
|
+
class BoardSummary(BaseModel):
|
|
43
43
|
model_config = ConfigDict(
|
|
44
44
|
arbitrary_types_allowed=True, populate_by_name=True, frozen=True
|
|
45
45
|
)
|
|
@@ -69,12 +69,12 @@ class SkippedFile(BaseModel):
|
|
|
69
69
|
return pf.relpath
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
class
|
|
72
|
+
class ListBoardsResult(BaseModel):
|
|
73
73
|
model_config = ConfigDict(arbitrary_types_allowed=True, frozen=True)
|
|
74
74
|
|
|
75
75
|
success: bool
|
|
76
76
|
errors: list[Diagnostic] = []
|
|
77
|
-
|
|
77
|
+
boards: list[BoardSummary] = []
|
|
78
78
|
count: int = 0
|
|
79
79
|
directory: ProjectDirectory
|
|
80
80
|
skipped_files: list[SkippedFile] = []
|
|
@@ -84,26 +84,26 @@ class ListDashboardsResult(BaseModel):
|
|
|
84
84
|
return d.relpath
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
class
|
|
87
|
+
class CompiledBoard(BaseModel):
|
|
88
88
|
model_config = ConfigDict(frozen=True)
|
|
89
89
|
|
|
90
90
|
success: bool
|
|
91
|
-
|
|
91
|
+
board: Board | None = None
|
|
92
92
|
errors: list[Diagnostic] = []
|
|
93
93
|
warnings: list[Diagnostic] = []
|
|
94
94
|
raw_yaml: str | None = None
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
class
|
|
97
|
+
class RenderBoardArgs(BaseModel):
|
|
98
98
|
"""Validate, compile, and render a Dataface dashboard, returning resolved chart semantics + executed data for reasoning. Use this to verify YAML is valid, inspect query results, and iterate on a dashboard. When 'path' is provided, the response also includes a localhost URL the user can open in a browser to view the live dashboard (from the embedded HTTP server used by agent sessions). Pass `as_link=true` with a path to skip execution and return only the preview URL."""
|
|
99
99
|
|
|
100
100
|
path: Path | None = Field(
|
|
101
101
|
None,
|
|
102
102
|
description=(
|
|
103
103
|
"Path to dashboard YAML file (use this OR yaml_content). "
|
|
104
|
-
"Face-relative (no
|
|
105
|
-
"root-relative (e.g. '
|
|
106
|
-
"path came from
|
|
104
|
+
"Face-relative (no charts/ prefix needed, e.g. 'looker/x.yaml') or "
|
|
105
|
+
"root-relative (e.g. 'charts/looker/x.yaml') both resolve. If the "
|
|
106
|
+
"path came from search_boards, use the hit's face_path."
|
|
107
107
|
),
|
|
108
108
|
)
|
|
109
109
|
yaml_content: str | None = Field(
|
|
@@ -171,14 +171,14 @@ class RenderDashboardArgs(BaseModel):
|
|
|
171
171
|
# ---------------------------------------------------------------------------
|
|
172
172
|
|
|
173
173
|
|
|
174
|
-
def
|
|
174
|
+
def list_boards(
|
|
175
175
|
project: Project,
|
|
176
176
|
*,
|
|
177
|
-
under: str =
|
|
177
|
+
under: str = CHARTS_SUBDIR,
|
|
178
178
|
recursive: bool = True,
|
|
179
|
-
) ->
|
|
179
|
+
) -> ListBoardsResult:
|
|
180
180
|
"""List all available dashboards in a project."""
|
|
181
|
-
dashboards: list[
|
|
181
|
+
dashboards: list[BoardSummary] = []
|
|
182
182
|
skipped: list[SkippedFile] = []
|
|
183
183
|
|
|
184
184
|
for pf in project.iter_faces(under=under, recursive=recursive):
|
|
@@ -193,7 +193,7 @@ def list_dashboards(
|
|
|
193
193
|
continue
|
|
194
194
|
stem = pf.stem
|
|
195
195
|
dashboards.append(
|
|
196
|
-
|
|
196
|
+
BoardSummary(
|
|
197
197
|
file=pf,
|
|
198
198
|
title=content.get("title", stem),
|
|
199
199
|
description=content.get("description", ""),
|
|
@@ -207,31 +207,31 @@ def list_dashboards(
|
|
|
207
207
|
except OSError as e:
|
|
208
208
|
skipped.append(SkippedFile(file=pf, reason=f"Read error: {e}"))
|
|
209
209
|
|
|
210
|
-
return
|
|
210
|
+
return ListBoardsResult(
|
|
211
211
|
success=True,
|
|
212
|
-
|
|
212
|
+
boards=dashboards,
|
|
213
213
|
count=len(dashboards),
|
|
214
214
|
directory=project.directory(under),
|
|
215
215
|
skipped_files=skipped,
|
|
216
216
|
)
|
|
217
217
|
|
|
218
218
|
|
|
219
|
-
def
|
|
219
|
+
def get_board(
|
|
220
220
|
path: Path,
|
|
221
221
|
*,
|
|
222
222
|
project: Project,
|
|
223
223
|
include_raw: bool = False,
|
|
224
|
-
) ->
|
|
224
|
+
) -> CompiledBoard:
|
|
225
225
|
"""Get the compiled structure of a dashboard."""
|
|
226
226
|
# One faces-first resolve/exists/is-file seam, shared with the render path.
|
|
227
227
|
face = resolve_face_or_error(path, project)
|
|
228
228
|
if isinstance(face, Diagnostic):
|
|
229
|
-
return
|
|
229
|
+
return CompiledBoard(success=False, errors=[face])
|
|
230
230
|
result = compile_file(face)
|
|
231
231
|
|
|
232
|
-
return
|
|
232
|
+
return CompiledBoard(
|
|
233
233
|
success=result.success,
|
|
234
|
-
|
|
234
|
+
board=result.face if result.success else None,
|
|
235
235
|
errors=list(result.errors),
|
|
236
236
|
warnings=result.warnings,
|
|
237
237
|
raw_yaml=face.content if include_raw else None,
|
dataface/agent_api/cache.py
CHANGED
|
@@ -53,7 +53,7 @@ def project_cache_ctx(
|
|
|
53
53
|
Precedence: ``no_cache=True`` (the CLI's ``--no-cache``) skips the cache
|
|
54
54
|
entirely; ``cache_path`` (``--cache PATH``, or its ``DFT_CACHE_PATH`` env
|
|
55
55
|
backing) opens that persistent file. Otherwise the project's
|
|
56
|
-
``
|
|
56
|
+
``dbt_charts.yml`` ``cache:`` block picks the location — a configured ``path``
|
|
57
57
|
opens that file (created if absent); no path opens the zero-config
|
|
58
58
|
in-memory default. A project-level ``cache: false`` defaults the *cascade*
|
|
59
59
|
to off without closing the door on a nearer scope's opt-in, so it still
|
dataface/agent_api/data_paths.py
CHANGED
|
@@ -6,7 +6,6 @@ from the validate path, which must stay connection-free.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
from pathlib import Path
|
|
10
9
|
from typing import TYPE_CHECKING
|
|
11
10
|
|
|
12
11
|
if TYPE_CHECKING:
|
|
@@ -67,7 +66,7 @@ def validate_data_aliases(
|
|
|
67
66
|
|
|
68
67
|
|
|
69
68
|
def data_alias_errors_for_file(
|
|
70
|
-
face_file:
|
|
69
|
+
face_file: str,
|
|
71
70
|
source_names: frozenset[str],
|
|
72
71
|
project: Project,
|
|
73
72
|
) -> list[str]:
|
|
@@ -83,7 +82,7 @@ def data_alias_errors_for_file(
|
|
|
83
82
|
"""
|
|
84
83
|
from dataface.core.serve.alias_index import read_aliases_from_file
|
|
85
84
|
|
|
86
|
-
project_path = project.path(face_file
|
|
85
|
+
project_path = project.path(face_file)
|
|
87
86
|
try:
|
|
88
87
|
aliases = read_aliases_from_file(project_path)
|
|
89
88
|
except ValueError:
|