dataface 0.1.6.dev558__py3-none-any.whl → 0.1.6.dev622__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 (49) hide show
  1. dataface/DATAFACE_SYNTAX.md +14 -1
  2. dataface/agent_api/__init__.py +10 -1
  3. dataface/agent_api/docs/yaml-reference.md +19 -30
  4. dataface/agent_api/validate.py +1 -1
  5. dataface/cli/_error_format.py +13 -2
  6. dataface/cli/commands/render.py +100 -0
  7. dataface/cli/main.py +85 -28
  8. dataface/core/compile/compiler.py +8 -9
  9. dataface/core/compile/errors.py +18 -47
  10. dataface/core/compile/filter_injection.py +12 -2
  11. dataface/core/compile/jinja.py +54 -4
  12. dataface/core/compile/models/chart/normalized.py +1 -1
  13. dataface/core/compile/models/chart/resolved.py +6 -6
  14. dataface/core/compile/models/style/authored.py +3 -15
  15. dataface/core/compile/models/style/resolved.py +0 -3
  16. dataface/core/compile/models/style/theme.py +35 -31
  17. dataface/core/compile/normalize_variables.py +155 -31
  18. dataface/core/compile/normalizer.py +20 -5
  19. dataface/core/compile/parser.py +5 -22
  20. dataface/core/compile/schema_renderers/highlight_manifest.py +79 -0
  21. dataface/core/compile/schema_renderers/prompt.py +4 -1
  22. dataface/core/compile/schema_renderers/textmate_grammar.py +548 -0
  23. dataface/core/compile/style_cascade.py +35 -13
  24. dataface/core/compile/yaml_error_formatter.py +28 -322
  25. dataface/core/defaults/themes/_base.yaml +27 -3
  26. dataface/core/errors/codes_compile.py +48 -0
  27. dataface/core/errors/structured.py +0 -4
  28. dataface/core/execute/adapters/databricks_connection_manager.py +158 -0
  29. dataface/core/execute/adapters/dbt_adapter_factory.py +58 -18
  30. dataface/core/execute/adapters/sql_adapter.py +2 -3
  31. dataface/core/render/chart/callout.py +296 -57
  32. dataface/core/render/chart/decisions.py +6 -2
  33. dataface/core/render/chart/pipeline.py +60 -23
  34. dataface/core/render/chart/profile.py +42 -46
  35. dataface/core/render/chart/rendering.py +1 -0
  36. dataface/core/render/chart/spark.py +76 -2
  37. dataface/core/render/chart/standard_renderer.py +25 -31
  38. dataface/core/render/chart/table.py +35 -13
  39. dataface/core/render/chart/vl_field_maps.py +5 -0
  40. dataface/core/render/warnings/bar_color_1_to_1_with_x.py +2 -2
  41. dataface/data/highlighting/face/v1.json +82 -0
  42. dataface/integrations/highlighting.py +30 -1
  43. {dataface-0.1.6.dev558.dist-info → dataface-0.1.6.dev622.dist-info}/METADATA +1 -1
  44. {dataface-0.1.6.dev558.dist-info → dataface-0.1.6.dev622.dist-info}/RECORD +48 -45
  45. mdsvg/renderer.py +18 -2
  46. dataface/data/highlighting/sql_block_scalar_keys.json +0 -4
  47. {dataface-0.1.6.dev558.dist-info → dataface-0.1.6.dev622.dist-info}/WHEEL +0 -0
  48. {dataface-0.1.6.dev558.dist-info → dataface-0.1.6.dev622.dist-info}/entry_points.txt +0 -0
  49. {dataface-0.1.6.dev558.dist-info → dataface-0.1.6.dev622.dist-info}/licenses/LICENSE +0 -0
@@ -114,6 +114,12 @@ rows:
114
114
  ### Queries (named, parameterized, inline)
115
115
 
116
116
  ```yaml
117
+ variables:
118
+ region:
119
+ input: select
120
+ options:
121
+ static: [US, EU, APAC]
122
+
117
123
  queries:
118
124
  # Bare-string form — SQL inherits the face-level source
119
125
  revenue: SELECT month, SUM(amount) AS total FROM orders GROUP BY 1 ORDER BY 1
@@ -342,6 +348,12 @@ Queries are the data layer. Charts reference queries by name; queries never embe
342
348
  ```yaml
343
349
  source: my_profile # Optional: default source for every query below
344
350
 
351
+ variables:
352
+ region:
353
+ input: select
354
+ options:
355
+ static: [US, EU, APAC]
356
+
345
357
  queries:
346
358
  # SQL — the default. `type: sql` is implicit when `sql:` is present.
347
359
  revenue: SELECT month, SUM(amount) AS total FROM orders GROUP BY 1 ORDER BY 1
@@ -423,6 +435,7 @@ Queries are Jinja-rendered before execution. Reference variables as bare names
423
435
  ```yaml
424
436
  variables:
425
437
  region: { input: select, options: { static: [US, EU, APAC] } }
438
+ period: { input: daterange }
426
439
 
427
440
  queries:
428
441
  sales:
@@ -518,7 +531,7 @@ charts:
518
531
  style: # Chart-local style patch (typed; not raw CSS) — paint only
519
532
  orientation: vertical # style: does NOT accept height or aspect_ratio
520
533
  number_format: ",.0f" # D3 format string or named alias for axis/tooltip format
521
- stack: zero # false | true | zero | normalize | center
534
+ stack: zero # none | zero | normalize | center
522
535
  ```
523
536
 
524
537
  ### Chart types (29 total)
@@ -53,11 +53,18 @@ from dataface.agent_api.schema_hints import (
53
53
  SchemaHints as SchemaHints,
54
54
  schema_hints as schema_hints,
55
55
  )
56
- from dataface.agent_api.validate import ValidateDashboardArgs, ValidateResult
56
+ from dataface.agent_api.validate import (
57
+ ValidateDashboardArgs,
58
+ ValidateResult,
59
+ )
57
60
  from dataface.agent_api.validate_query import (
58
61
  QueryDiagnostic as QueryDiagnostic,
59
62
  validate_query as validate_query,
60
63
  )
64
+ from dataface.core.compile.compiler import (
65
+ CompileResult as CompileResult,
66
+ compile as compile,
67
+ )
61
68
  from dataface.core.compile.config import ProjectSourcesConfig as ProjectSourcesConfig
62
69
  from dataface.core.dashboard import (
63
70
  RenderedDashboard as RenderedDashboard,
@@ -69,6 +76,8 @@ from dataface.core.render.board_links import LinkContext as LinkContext
69
76
  from dataface.core.render.errors import RenderError as RenderError
70
77
 
71
78
  __all__ = [
79
+ "compile",
80
+ "CompileResult",
72
81
  "DescribeFaceArgs",
73
82
  "DescribeFaceResult",
74
83
  "DocsArgs",
@@ -578,7 +578,6 @@ Authored overlay for BarChartStyle. Bar chart style: chart-level fields + marks
578
578
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
579
579
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
580
580
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
581
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
582
581
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
583
582
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
584
583
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -595,7 +594,7 @@ Authored overlay for BarChartStyle. Bar chart style: chart-level fields + marks
595
594
  | `range` | [RangeStyle](#rangestyle) | ✓ | Color range/palette overrides for this chart type; None means no override. |
596
595
  | `data_table` | [DataTableStyle](#datatablestyle) | ✓ | Per-chart-type data_table style override. Unset fields fall back to [`style.charts.data_table`](#chartsstyle). |
597
596
  | `orientation` | enum: "horizontal", "vertical", "auto" | ✓ | Preferred bar orientation; None uses the renderer default (vertical). |
598
- | `stack` | enum: "zero", "normalize", "center" | ✓ | Default stack mode for bar charts; None uses the renderer default (VL stacks by default). |
597
+ | `stack` | enum: "none", "zero", "normalize", "center" | ✓ | Default stack mode for bar charts; none renders side-by-side columns. |
599
598
  | `stack_order` | enum: "value", "data", "alphabetical" | ✓ | Z-order of stacked segments. None/'value' puts the largest aggregate at baseline. 'data' follows SQL row order (orientation-stable not guaranteed). 'alphabetical' sorts by color field name. Ignored when stacking is off or no color. |
600
599
  | `endpoint_labels` | [EndpointLabelsConfig](#endpointlabelsconfig) | ✓ | Endpoint label pane configuration for bar charts. |
601
600
  | `marks` | [BarChartMarksStyle](#barchartmarksstyle) | ✓ | Bar-family mark overrides. Unset fields fall back to [`style.charts.marks`](#chartsstyle). |
@@ -615,7 +614,6 @@ Authored overlay for LineChartStyle. Line chart style: chart-level fields + mark
615
614
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
616
615
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
617
616
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
618
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
619
617
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
620
618
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
621
619
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -649,7 +647,6 @@ Authored overlay for AreaChartStyle. Area chart style: chart-level fields + mark
649
647
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
650
648
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
651
649
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
652
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
653
650
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
654
651
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
655
652
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -665,7 +662,7 @@ Authored overlay for AreaChartStyle. Area chart style: chart-level fields + mark
665
662
  | `scale` | [ScaleStyle](#scalestyle) | ✓ | Chart-type encoding scale overrides applied to both x and y; None means no override. |
666
663
  | `range` | [RangeStyle](#rangestyle) | ✓ | Color range/palette overrides for this chart type; None means no override. |
667
664
  | `data_table` | [DataTableStyle](#datatablestyle) | ✓ | Per-chart-type data_table style override. Unset fields fall back to [`style.charts.data_table`](#chartsstyle). |
668
- | `stack` | enum: "zero", "normalize", "center" | ✓ | Default stack mode for area charts; False overlaps silhouettes. |
665
+ | `stack` | enum: "none", "zero", "normalize", "center" | ✓ | Default stack mode for area charts; none overlaps silhouettes. |
669
666
  | `endpoint_labels` | [EndpointLabelsConfig](#endpointlabelsconfig) | ✓ | Endpoint label pane configuration for area charts. |
670
667
  | `marks` | [AreaChartMarksStyle](#areachartmarksstyle) | ✓ | Area-family mark overrides. Unset fields fall back to [`style.charts.marks`](#chartsstyle). |
671
668
 
@@ -684,7 +681,6 @@ Authored overlay for ScatterChartStyle. Scatter chart style: chart-level fields
684
681
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
685
682
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
686
683
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
687
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
688
684
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
689
685
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
690
686
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -717,7 +713,6 @@ Authored overlay for HeatmapChartStyle. Heatmap chart style.
717
713
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
718
714
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
719
715
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
720
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
721
716
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
722
717
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
723
718
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -762,7 +757,6 @@ Authored overlay for PieChartStyle. Pie/donut chart style: geometry + total (fla
762
757
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
763
758
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
764
759
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
765
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
766
760
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
767
761
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
768
762
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -796,7 +790,6 @@ Authored overlay for KpiChartStyle. Produced by cascade from theme YAML.
796
790
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
797
791
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
798
792
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
799
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
800
793
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
801
794
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
802
795
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -825,7 +818,6 @@ Authored overlay for TableChartStyle. Table chart style overrides layered on top
825
818
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
826
819
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
827
820
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
828
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
829
821
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
830
822
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
831
823
  | `background` | str | ✓ | Table background color; None inherits from theme. |
@@ -883,7 +875,6 @@ Authored overlay for PointMapChartStyle. Point map chart style.
883
875
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
884
876
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
885
877
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
886
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
887
878
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
888
879
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
889
880
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -908,7 +899,6 @@ Authored overlay for GeoshapeChartStyle. Geoshape (choropleth) chart style.
908
899
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
909
900
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
910
901
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
911
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
912
902
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
913
903
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
914
904
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -959,7 +949,6 @@ Flat style patch for layered multi-mark charts.
959
949
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
960
950
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
961
951
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
962
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
963
952
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style overrides. |
964
953
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Chart tooltip style overrides. |
965
954
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -976,7 +965,7 @@ Flat style patch for layered multi-mark charts.
976
965
  | `range` | [RangeStyle](#rangestyle) | ✓ | Color range/palette overrides for this chart type; None means no override. |
977
966
  | `data_table` | [DataTableStyle](#datatablestyle) | ✓ | Per-chart-type data_table style override. Unset fields fall back to [`style.charts.data_table`](#chartsstyle). |
978
967
  | `orientation` | enum: "horizontal", "vertical", "auto" | ✓ | Preferred bar orientation; None uses the renderer default (vertical). |
979
- | `stack` | enum: "zero", "normalize", "center" | ✓ | Default stack mode for bar/area charts. |
968
+ | `stack` | enum: "none", "zero", "normalize", "center" | ✓ | Default stack mode for bar/area charts. |
980
969
  | `stack_order` | enum: "value", "data", "alphabetical" | ✓ | Z-order of stacked segments. |
981
970
  | `endpoint_labels` | [EndpointLabelsConfig](#endpointlabelsconfig) | ✓ | Endpoint label pane configuration. |
982
971
  | `marks` | [LayeredMarksStyle](#layeredmarksstyle) | ✓ | Per-mark-type style overrides (bar/line/area/point). |
@@ -1102,7 +1091,7 @@ Authored overlay for TitleStyle. Board and face titles.
1102
1091
  | `min_height` | float | ✓ | Minimum title row height in pixels. |
1103
1092
  | `overflow` | str | ✓ | Text overflow mode (clip, truncate, wrap-two, wrap). |
1104
1093
  | `position` | [TitlePositionStyle](#titlepositionstyle) | ✓ | Vega-Lite title positioning: anchor, angle, offset, baseline. |
1105
- | `level` | enum: "auto" | ✓ | Heading level override for face titles. ``'auto'`` (default) computes the level semantically as the count of titled ancestors. An integer value locks all titles in this face and its descendants to that H-level. |
1094
+ | `level` | int \| enum: "auto" | ✓ | Heading level override for face titles. ``'auto'`` (default) computes the level semantically as the count of titled ancestors. An integer value locks all titles in this face and its descendants to that H-level. |
1106
1095
  | `subtitle` | [TitleSubtitleStyle](#titlesubtitlestyle) | ✓ | Subtitle font styles. |
1107
1096
 
1108
1097
  <a id="textstyle"></a>
@@ -1142,7 +1131,6 @@ Authored overlay for ChartsStyle. Registry of all chart-type styles plus shared
1142
1131
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. |
1143
1132
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. |
1144
1133
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. |
1145
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
1146
1134
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
1147
1135
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Chart tooltip style. |
1148
1136
  | `background` | str | ✓ | Chart canvas background; None inherits from the board background via apply_inherit. Falls back to [`style.background`](#style). |
@@ -1335,15 +1323,6 @@ Authored overlay for PaddingStyle. Per-chart padding inset (px). All 4 sides req
1335
1323
  | `top` | float | ✓ | Top padding in pixels. |
1336
1324
  | `bottom` | float | ✓ | Bottom padding in pixels. |
1337
1325
 
1338
- <a id="inferencestyle"></a>
1339
- ## InferenceStyle
1340
- Authored overlay for InferenceStyle.
1341
-
1342
- | Field | Type | Optional | Description |
1343
- |-------|------|:--------:|-------------|
1344
- | `infer_zero_when_missing` | bool | ✓ | Auto-infer zero-baseline when not authored. |
1345
- | `infer_fields_when_missing` | bool | ✓ | Auto-infer chart fields (x, y, etc.) when not authored. |
1346
-
1347
1326
  <a id="legendstyle"></a>
1348
1327
  ## LegendStyle
1349
1328
  Authored overlay for LegendStyle.
@@ -1417,7 +1396,7 @@ Authored overlay for ScaleStyle. Scale configuration primitive.
1417
1396
  | `point_padding` | float | ✓ | Padding fraction for point scales; None uses Vega-Lite's default. |
1418
1397
  | `rect_band_padding_inner` | float | ✓ | Inner padding fraction for rect band scales; None uses Vega-Lite's default. |
1419
1398
  | `round` | bool | ✓ | Round scale outputs to nearest integer; None uses Vega-Lite's default (no rounding). |
1420
- | `zero` | bool | ✓ | Force scale to include zero; None uses Vega-Lite's default. |
1399
+ | `zero` | bool \| enum: "auto" | ✓ | Force scale zero-baseline: True/False pins it; "auto" runs the Dataface smart-zero heuristic; None passes through to Vega-Lite. |
1421
1400
  | `clamp` | bool | ✓ | Clamp values to scale domain; None uses Vega-Lite's default (no clamping). |
1422
1401
  | `continuous_padding` | float | ✓ | Padding in pixels for continuous scales; None uses Vega-Lite's default. |
1423
1402
  | `band` | [ScaleBandStyle](#scalebandstyle) | ✓ | Band mark size constraints; None uses Vega-Lite's defaults. |
@@ -1654,7 +1633,7 @@ Configuration for a single table column.
1654
1633
  |-------|------|:--------:|-------------|
1655
1634
  | `label` | str | ✓ | Display header label (defaults to column name). |
1656
1635
  | `format` | str \| [FormatConfig](#formatconfig) | ✓ | Number format (D3 string, preset name, or FormatConfig). |
1657
- | `spark` | enum: "line", "area", "bar", "bar-normalize", "columns" | ✓ | Inline spark chart config or spark type name. |
1636
+ | `spark` | enum: "line", "area", "bar", "bar-normalize", "column", "columns" | ✓ | Inline spark chart config or spark type name. |
1658
1637
  | `swatch` | bool | ✓ | When True, render this column's cells as small rounded color squares instead of text. Cell value must be a CSS color string (e.g. '#3164a3'). Useful for series-keyed tables — e.g. a 'Series' column where each row is identified by its color in the parent chart's palette. |
1659
1638
  | `width` | int \| str | ✓ | Column width (integer pixels or CSS string like '10%'). |
1660
1639
  | `max_width` | int \| str | ✓ | Maximum column width for auto-sized text columns (integer pixels or CSS string like '30%'). Cannot be set together with width:. |
@@ -1702,6 +1681,7 @@ Authored overlay for SparkStyle. Inline sparkline defaults (inside table cells).
1702
1681
  | `empty` | [SparkEmptyStyle](#sparkemptystyle) | ✓ | Style for empty/no-data sparklines. |
1703
1682
  | `single_value` | [SparkSingleValueStyle](#sparksinglevaluestyle) | ✓ | Style for single-data-point sparklines. |
1704
1683
  | `columns` | [SparkColumnsStyle](#sparkcolumnsstyle) | ✓ | Style for column-type sparklines. |
1684
+ | `column` | [SparkColumnStyle](#sparkcolumnstyle) | ✓ | Style for the single vertical `column` spark mark. |
1705
1685
  | `bar` | [SparkBarCellStyle](#sparkbarcellstyle) | ✓ | Style for bar/bar-normalize sparklines. |
1706
1686
  | `area` | [SparkAreaStyle](#sparkareastyle) | ✓ | Style for area sparklines. |
1707
1687
 
@@ -1944,7 +1924,6 @@ Authored overlay for HistogramChartStyle. Histogram chart style.
1944
1924
  | `animation_duration` | float | ✓ | Vega-Lite animation duration in milliseconds. Falls back to [`style.charts.animation_duration`](#chartsstyle). |
1945
1925
  | `palette` | list[str] \| str | ✓ | Ordered list of categorical color stops or a palette name; expanded from a palette name at validation time. Falls back to [`style.charts.palette`](#chartsstyle). |
1946
1926
  | `single_series_palette` | list[str] \| str | ✓ | Ordered list of single-series mark inks (must be non-empty), or a palette name. Cycled across single-series charts in face reading order. Falls back to [`style.charts.single_series_palette`](#chartsstyle). |
1947
- | `inference` | [InferenceStyle](#inferencestyle) | ✓ | Engine inference behavior flags. |
1948
1927
  | `legend` | [LegendStyle](#legendstyle) | ✓ | Chart legend style. |
1949
1928
  | `tooltip` | [TooltipStyle](#tooltipstyle) | ✓ | Per-chart-type tooltip style override; None uses the universal style.charts.tooltip. |
1950
1929
  | `background` | str | ✓ | Chart-local background color override; None inherits from theme. |
@@ -2119,7 +2098,7 @@ Scale configuration for a single style target (background or color).
2119
2098
  | `min` | float \| int | ✓ | Minimum scale domain value (overrides data minimum). |
2120
2099
  | `max` | float \| int | ✓ | Maximum scale domain value (overrides data maximum). |
2121
2100
  | `null_color` | str | ✓ | Color assigned to null values. |
2122
- | `hinge` | enum: "auto" | ✓ | Diverging scale midpoint value, or 'auto' to use the data midpoint. |
2101
+ | `hinge` | float \| enum: "auto" | ✓ | Diverging scale midpoint value, or 'auto' to use the data midpoint. |
2123
2102
  | `arm_mode` | enum: "asymmetric", "symmetric" | ✓ | How diverging scale arms are stretched: 'asymmetric' (proportional) or 'symmetric' (equal arms). |
2124
2103
 
2125
2104
  <a id="axisgridstyle"></a>
@@ -2306,6 +2285,7 @@ Authored overlay for SliceMarkStyle. Pie/donut slice mark — mark-level paint a
2306
2285
 
2307
2286
  | Field | Type | Optional | Description |
2308
2287
  |-------|------|:--------:|-------------|
2288
+ | `opacity` | float | ✓ | Arc slice opacity (0–1); None means not overridden at this level. |
2309
2289
  | `gap` | float | ✓ | Angular gap between slices in radians. |
2310
2290
  | `corner_radius` | float | ✓ | Corner radius of arc slices in pixels. |
2311
2291
  | `stroke` | [StrokeStyle](#strokestyle) | ✓ | Arc slice stroke style. |
@@ -2334,7 +2314,7 @@ Configuration for spark charts (inline sparklines) in table columns.
2334
2314
 
2335
2315
  | Field | Type | Optional | Description |
2336
2316
  |-------|------|:--------:|-------------|
2337
- | `type` | enum: "line", "area", "bar", "bar-normalize", "columns" | ✓ | Spark chart type (line, area, bar, bar-normalize, columns). |
2317
+ | `type` | enum: "line", "area", "bar", "bar-normalize", "column", "columns" | ✓ | Spark chart type (line, area, bar, bar-normalize, column, columns). |
2338
2318
  | `color` | str | ✓ | Color for the spark mark. |
2339
2319
  | `height` | int | ✓ | Spark chart height in pixels. |
2340
2320
  | `width` | int | ✓ | Spark chart width in pixels. |
@@ -2386,6 +2366,15 @@ Authored overlay for SparkColumnsStyle. Inline `spark.type: columns` (multi-valu
2386
2366
  | `min_bar_height` | float | ✓ | Minimum rendered bar height in pixels. |
2387
2367
  | `border` | [BorderStyle](#borderstyle) | ✓ | Column bar border style. |
2388
2368
 
2369
+ <a id="sparkcolumnstyle"></a>
2370
+ ## SparkColumnStyle
2371
+ Authored overlay for SparkColumnStyle. Inline `spark.type: column` (single vertical bar) defaults.
2372
+
2373
+ | Field | Type | Optional | Description |
2374
+ |-------|------|:--------:|-------------|
2375
+ | `width` | float | ✓ | Spark column default width in pixels. |
2376
+ | `height` | float | ✓ | Spark column default height in pixels. |
2377
+
2389
2378
  <a id="sparkbarcellstyle"></a>
2390
2379
  ## SparkBarCellStyle
2391
2380
  Authored overlay for SparkBarCellStyle. Inline `spark.type: bar` and `bar-normalize` (single horizontal bar) defaults.
@@ -170,7 +170,7 @@ def _validate_meta_file(path: Path) -> ValidateResult:
170
170
  DatafaceError.from_code(
171
171
  DF_COMPILE_META_SCHEMA,
172
172
  message=(
173
- f"{''.join(str(loc) for loc in e['loc'])}: {e['msg']}"
173
+ f"{'.'.join(str(loc) for loc in e['loc'])}: {e['msg']}"
174
174
  if e["loc"]
175
175
  else e["msg"]
176
176
  ),
@@ -21,6 +21,18 @@ from dataface.core.errors import StructuredError
21
21
  from dataface.core.render.warnings.base import RenderWarning
22
22
 
23
23
 
24
+ def _display_path(abs_path: str, line: int | None, cwd: Path | None = None) -> str:
25
+ """Return path relative to cwd when possible, with optional :line suffix."""
26
+ p = Path(abs_path)
27
+ base = cwd if cwd is not None else Path.cwd()
28
+ try:
29
+ rel = p.relative_to(base)
30
+ display = str(rel)
31
+ except ValueError:
32
+ display = abs_path
33
+ return f"{display}:{line}" if line else display
34
+
35
+
24
36
  def print_structured_errors(
25
37
  errs: list[StructuredError],
26
38
  *,
@@ -42,8 +54,7 @@ def print_structured_errors(
42
54
  if e.hint:
43
55
  body_parts.append(f"[dim]Hint:[/] {e.hint}")
44
56
  if e.file:
45
- loc = e.file + (f":{e.line}" if e.line else "")
46
- body_parts.append(f"[dim]At:[/] {loc}")
57
+ body_parts.append(f"[dim]At:[/] {_display_path(e.file, e.line)}")
47
58
  if e.docs_topic:
48
59
  body_parts.append(f"[dim]Docs:[/] dft docs {e.docs_topic}")
49
60
  elif e.doc_url:
@@ -29,6 +29,29 @@ from dataface.core.render.warnings.from_query_diagnostic import KNOWN_RENDER_COD
29
29
  # for query-validator codes; only orphan emitters (e.g. unreferenced_chart) add here.
30
30
  _COMPILE_PRODUCER_CODES: frozenset[str] = KNOWN_RENDER_CODES | {unreferenced_chart.CODE}
31
31
 
32
+ # Maps common file extensions to render formats for format inference.
33
+ _EXT_TO_FORMAT: dict[str, RenderFormat] = {
34
+ "svg": "svg",
35
+ "html": "html",
36
+ "htm": "html",
37
+ "png": "png",
38
+ "pdf": "pdf",
39
+ "json": "json",
40
+ "txt": "text",
41
+ "yaml": "yaml",
42
+ "yml": "yaml",
43
+ }
44
+
45
+
46
+ def infer_format_from_extension(output: str) -> RenderFormat | None:
47
+ """Infer render format from output file extension. Returns None for unknown extensions."""
48
+ return _EXT_TO_FORMAT.get(Path(output).suffix.lstrip(".").lower())
49
+
50
+
51
+ def expand_output_template(template: str, face: Path) -> str:
52
+ """Expand {stem} and {dir} placeholders in an output path template."""
53
+ return template.format(stem=face.stem, dir=str(face.parent))
54
+
32
55
 
33
56
  def _exit_with_errors(errs: list[StructuredError], json_errors: bool) -> None:
34
57
  print_structured_errors(errs, json_output=json_errors)
@@ -96,6 +119,7 @@ def render_command(
96
119
  ignore_codes: set[str] | None = None,
97
120
  fail_on_chart_errors: bool = True,
98
121
  max_workers: int | None = None,
122
+ print0: bool = False,
99
123
  ) -> str | None:
100
124
  """Render a dashboard to SVG, HTML, PNG, PDF, or terminal.
101
125
 
@@ -170,6 +194,7 @@ def render_command(
170
194
  output_dir=output_dir,
171
195
  default_output_stem=ctx.face_file.stem,
172
196
  source_label=str(face_path),
197
+ print0=print0,
173
198
  )
174
199
 
175
200
 
@@ -185,6 +210,7 @@ def render_command_from_yaml(
185
210
  ignore_codes: set[str] | None = None,
186
211
  fail_on_chart_errors: bool = True,
187
212
  max_workers: int | None = None,
213
+ print0: bool = False,
188
214
  ) -> str | None:
189
215
  """Render a dashboard from YAML content (e.g. stdin).
190
216
 
@@ -255,6 +281,7 @@ def render_command_from_yaml(
255
281
  output_dir=output_dir,
256
282
  default_output_stem="stdin",
257
283
  source_label="<stdin>",
284
+ print0=print0,
258
285
  )
259
286
 
260
287
 
@@ -265,6 +292,7 @@ def _write_output(
265
292
  output_dir: Path,
266
293
  default_output_stem: str,
267
294
  source_label: str,
295
+ print0: bool = False,
268
296
  ) -> str | None:
269
297
  """Write rendered content to the appropriate destination."""
270
298
  # `terminal` is stdout-only by design — --output is meaningless for the
@@ -318,4 +346,76 @@ def _write_output(
318
346
  f"Rendered {source_label} to {output_path} ({format} format)",
319
347
  file=sys.stderr,
320
348
  )
349
+ sys.stdout.write(str(output_path) + ("\0" if print0 else "\n"))
350
+ sys.stdout.flush()
321
351
  return str(output_path)
352
+
353
+
354
+ def render_commands(
355
+ face_paths: list[Path],
356
+ output: str | None = None,
357
+ format: RenderFormat = "svg",
358
+ project_dir: Path | None = None,
359
+ variables: dict[str, str] | None = None,
360
+ use_cache: bool = True,
361
+ json_errors: bool = False,
362
+ no_warnings: bool = False,
363
+ ignore_codes: set[str] | None = None,
364
+ fail_on_chart_errors: bool = True,
365
+ max_workers: int | None = None,
366
+ print0: bool = False,
367
+ fail_fast: bool = False,
368
+ ) -> None:
369
+ """Render one or more dashboards, printing output paths to stdout.
370
+
371
+ For multiple faces, `output` must contain {stem} or {dir} placeholders
372
+ (e.g. "renders/{stem}.svg"). With a single face, any output path is valid.
373
+
374
+ Per-face errors are reported to stderr; processing continues unless
375
+ `fail_fast=True`. Exits 1 if any face failed.
376
+ """
377
+ # Fail early when two inputs expand to the same output path — later renders
378
+ # would silently overwrite earlier ones.
379
+ if output and len(face_paths) > 1:
380
+ planned: list[str] = [expand_output_template(output, f) for f in face_paths]
381
+ seen: dict[str, Path] = {}
382
+ for face_path, dest in zip(face_paths, planned, strict=True):
383
+ if dest in seen:
384
+ print(
385
+ f"Error: {face_path} and {seen[dest]} both expand to {dest!r}; "
386
+ "use a more specific template (add {{dir}} or rename the files)",
387
+ file=sys.stderr,
388
+ )
389
+ sys.exit(1)
390
+ seen[dest] = face_path
391
+
392
+ has_failure = False
393
+ for face_path in face_paths:
394
+ face_output = expand_output_template(output, face_path) if output else None
395
+ try:
396
+ render_command(
397
+ face_path=face_path,
398
+ output=face_output,
399
+ format=format,
400
+ project_dir=project_dir,
401
+ variables=variables,
402
+ use_cache=use_cache,
403
+ json_errors=json_errors,
404
+ no_warnings=no_warnings,
405
+ ignore_codes=ignore_codes,
406
+ fail_on_chart_errors=fail_on_chart_errors,
407
+ max_workers=max_workers,
408
+ print0=print0,
409
+ )
410
+ except SystemExit as exc:
411
+ if fail_fast or exc.code != 1:
412
+ raise
413
+ has_failure = True
414
+ except Exception as exc: # noqa: BLE001 — per-face error; batch continues
415
+ print(f"Error rendering {face_path}: {exc}", file=sys.stderr)
416
+ has_failure = True
417
+ if fail_fast:
418
+ sys.exit(1)
419
+
420
+ if has_failure:
421
+ sys.exit(1)
dataface/cli/main.py CHANGED
@@ -690,23 +690,28 @@ def describe(
690
690
 
691
691
  @app.command("render", rich_help_panel="Dashboards")
692
692
  def render(
693
- face: Annotated[
694
- Path,
693
+ faces: Annotated[
694
+ list[Path],
695
695
  typer.Argument(
696
696
  # No exists=/file_okay=: "-" is a valid stdin sentinel and must not fail the check.
697
- help='Path to face YAML file, or "-" to read YAML from stdin',
697
+ help='Path(s) to face YAML file(s), or "-" to read YAML from stdin (single path only)',
698
698
  ),
699
699
  ],
700
700
  output: Annotated[
701
- Path | None,
702
- typer.Option(help="Output file path (default: face name with extension)"),
701
+ str | None,
702
+ typer.Option(
703
+ help=(
704
+ "Output file path. For multiple inputs, use {stem} or {dir} "
705
+ "placeholders (e.g. renders/{stem}.svg). Default: renders/<face>.<ext>."
706
+ )
707
+ ),
703
708
  ] = None,
704
709
  format: Annotated[
705
- RenderFormat,
710
+ RenderFormat | None,
706
711
  typer.Option(
707
712
  help="Output format: svg, html, png, pdf, terminal, json, text, or yaml"
708
713
  ),
709
- ] = "svg",
714
+ ] = None,
710
715
  project_dir: ProjectDirOption = None,
711
716
  var: Annotated[
712
717
  list[str] | None,
@@ -775,11 +780,35 @@ def render(
775
780
  ),
776
781
  ),
777
782
  ] = None,
783
+ print0: Annotated[
784
+ bool,
785
+ typer.Option(
786
+ "--print0",
787
+ "-0",
788
+ help=(
789
+ "Delimit produced output paths with NUL (\\0) instead of newline. "
790
+ "Enables safe piping to xargs -0 for paths containing spaces."
791
+ ),
792
+ ),
793
+ ] = False,
794
+ fail_fast: Annotated[
795
+ bool,
796
+ typer.Option(
797
+ "--fail-fast",
798
+ help=(
799
+ "Stop immediately on the first render failure. "
800
+ "Default: continue rendering remaining faces, exit 1 at end."
801
+ ),
802
+ ),
803
+ ] = False,
778
804
  ) -> None:
779
- """Render a dashboard to SVG, HTML, PNG, PDF, or terminal.
805
+ """Render one or more dashboards to SVG, HTML, PNG, PDF, or terminal.
780
806
 
781
- Use "-" as the face argument to read YAML from stdin (useful for agents
782
- and shell pipelines).
807
+ Accepts multiple face paths; output paths are printed to stdout (one per
808
+ line) so results can be piped to other tools. Use --print0 for NUL-delimited
809
+ output safe with xargs -0.
810
+
811
+ Use "-" as the sole face argument to read YAML from stdin.
783
812
 
784
813
  By default, per-chart runtime errors (missing columns, query failures)
785
814
  cause exit 1 so CI smoke tests detect broken charts. Pass
@@ -790,6 +819,8 @@ def render(
790
819
  Examples:
791
820
  dft render faces/sales.yml
792
821
  dft render faces/sales.yml --format html
822
+ dft render faces/*.yml --output renders/{stem}.svg
823
+ dft render faces/*.yml --output renders/{stem}.svg --print0 | xargs -0 ls -lh
793
824
  dft render faces/sales.yml --var region=West --var category=Electronics
794
825
  dft render faces/sales.yml --format terminal
795
826
  dft render faces/sales.yml --no-cache
@@ -800,34 +831,42 @@ def render(
800
831
  echo 'charts: {c: {query: {type: csv, file: data.csv}}}' | dft render - --format terminal
801
832
  """
802
833
  variables = parse_kv_pairs(var or [], "--var")
803
-
804
834
  use_cache = not no_cache
805
835
  ignore_codes = set(ignore_warning) if ignore_warning else None
806
836
  fail_on_chart_errors = not allow_chart_errors
807
837
 
808
- if str(face) == "-":
838
+ # Reject stdin mixed with other paths
839
+ has_stdin = any(str(f) == "-" for f in faces)
840
+ if has_stdin and len(faces) > 1:
841
+ raise typer.BadParameter(
842
+ '"-" (stdin) can only be used as the sole face argument',
843
+ param_hint="FACES",
844
+ )
845
+
846
+ # Infer format from output extension when not explicitly given
847
+ effective_format: RenderFormat = (
848
+ format or (output and render_cmd.infer_format_from_extension(output)) or "svg"
849
+ )
850
+
851
+ # Reject flat --output when rendering multiple faces (ambiguous destination)
852
+ if len(faces) > 1 and output is not None:
853
+ if "{stem}" not in output and "{dir}" not in output:
854
+ raise typer.BadParameter(
855
+ f'use a template like "{{stem}}.{effective_format}" for multiple inputs; '
856
+ f'"{output}" is ambiguous with {len(faces)} face arguments',
857
+ param_hint="--output",
858
+ )
859
+
860
+ # Stdin path (single face "-")
861
+ if has_stdin:
809
862
  yaml_content = sys.stdin.read()
810
863
  if not yaml_content.strip():
811
864
  print("Error: No YAML input received from stdin", file=sys.stderr)
812
865
  raise typer.Exit(1)
813
866
  render_cmd.render_command_from_yaml(
814
867
  yaml_content=yaml_content,
815
- output=str(output) if output else None,
816
- format=format,
817
- project_dir=project_dir,
818
- variables=variables or None,
819
- use_cache=use_cache,
820
- json_errors=json_errors,
821
- no_warnings=no_warnings,
822
- ignore_codes=ignore_codes,
823
- fail_on_chart_errors=fail_on_chart_errors,
824
- max_workers=max_workers,
825
- )
826
- else:
827
- render_cmd.render_command(
828
- face_path=face,
829
- output=str(output) if output else None,
830
- format=format,
868
+ output=output,
869
+ format=effective_format,
831
870
  project_dir=project_dir,
832
871
  variables=variables or None,
833
872
  use_cache=use_cache,
@@ -836,7 +875,25 @@ def render(
836
875
  ignore_codes=ignore_codes,
837
876
  fail_on_chart_errors=fail_on_chart_errors,
838
877
  max_workers=max_workers,
878
+ print0=print0,
839
879
  )
880
+ return
881
+
882
+ render_cmd.render_commands(
883
+ face_paths=faces,
884
+ output=output,
885
+ format=effective_format,
886
+ project_dir=project_dir,
887
+ variables=variables or None,
888
+ use_cache=use_cache,
889
+ json_errors=json_errors,
890
+ no_warnings=no_warnings,
891
+ ignore_codes=ignore_codes,
892
+ fail_on_chart_errors=fail_on_chart_errors,
893
+ max_workers=max_workers,
894
+ print0=print0,
895
+ fail_fast=fail_fast,
896
+ )
840
897
 
841
898
 
842
899
  @app.command("search", rich_help_panel="Dashboards")