dataface 0.3.2.dev111__py3-none-any.whl → 0.3.2.dev150__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 +15 -4
- dataface/agent_api/docs/yaml-reference.md +33 -133
- dataface/agent_api/serve.py +0 -2
- dataface/agent_api/validate.py +8 -0
- dataface/cli/commands/render.py +6 -0
- dataface/cli/commands/serve.py +0 -6
- dataface/cli/main.py +20 -14
- dataface/core/aliases.py +27 -0
- dataface/core/compile/__init__.py +0 -8
- dataface/core/compile/channel.py +0 -13
- dataface/core/compile/compiler.py +73 -71
- dataface/core/compile/introspection.py +2 -13
- dataface/core/compile/models/chart/authored/_base.py +1 -1
- dataface/core/compile/models/chart/normalized/__init__.py +2 -0
- dataface/core/compile/models/chart/normalized/_base.py +26 -0
- dataface/core/compile/models/config.py +5 -0
- dataface/core/compile/models/face/authored.py +24 -89
- dataface/core/compile/models/query/authored.py +1 -119
- dataface/core/compile/models/refs.py +0 -2
- dataface/core/compile/models/source.py +73 -159
- dataface/core/compile/models/style/theme/variables.py +0 -3
- dataface/core/compile/normalize_charts.py +4 -152
- dataface/core/compile/normalize_layout.py +20 -284
- dataface/core/compile/normalize_queries.py +3 -506
- dataface/core/compile/normalizer.py +4 -10
- dataface/core/compile/palette.py +19 -7
- dataface/core/compile/validator.py +121 -44
- dataface/core/compile/yaml_error_formatter.py +107 -2
- dataface/core/dashboard.py +3 -1
- dataface/core/defaults/default_config.yml +4 -0
- dataface/core/defaults/themes/_base.yaml +0 -1
- dataface/core/defaults/themes/editorial.yaml +3 -0
- dataface/core/defaults/themes/stark.yaml +8 -0
- dataface/core/diagnostics/__init__.py +10 -0
- dataface/core/diagnostics/codes_compile.py +4 -2
- dataface/core/diagnostics/codes_execute.py +70 -0
- dataface/core/diagnostics/codes_render.py +58 -4
- dataface/core/execute/adapters/__init__.py +1 -1
- dataface/core/execute/cache_keys.py +4 -9
- dataface/core/execute/executor.py +25 -3
- dataface/core/execute/file_source_materializer.py +185 -32
- dataface/core/execute/trivial_local_cache.py +5 -2
- dataface/core/inspect/__init__.py +0 -1
- dataface/core/project.py +6 -2
- dataface/core/render/chart/mark_extents.py +339 -0
- dataface/core/render/chart/rendering.py +97 -34
- dataface/core/render/conditions.py +122 -0
- dataface/core/render/controls.py +60 -187
- dataface/core/render/data_format.py +1 -1
- dataface/core/render/face_resolve.py +7 -0
- dataface/core/render/faces.py +94 -30
- dataface/core/render/layout_sizing.py +46 -0
- dataface/core/render/renderer.py +14 -1
- dataface/core/render/sizing.py +42 -105
- dataface/core/render/svg_utils.py +60 -14
- dataface/core/render/terminal.py +1 -1
- dataface/core/render/variables_layout.py +211 -0
- dataface/core/render/variables_resolve.py +376 -0
- dataface/core/render/variables_strip.py +291 -368
- dataface/core/render/warnings/base.py +18 -0
- dataface/core/render/warnings/layout_min_exceeds_height.py +68 -0
- dataface/core/render/warnings/registry.py +2 -0
- dataface/core/serve/alias_index.py +16 -22
- dataface/data/schemas/board-resolved/board-resolved.schema.json +1 -499
- {dataface-0.3.2.dev111.dist-info → dataface-0.3.2.dev150.dist-info}/METADATA +1 -3
- {dataface-0.3.2.dev111.dist-info → dataface-0.3.2.dev150.dist-info}/RECORD +69 -67
- dataface/core/inspect/partials/categorical.yml +0 -38
- dataface/core/inspect/partials/date.yml +0 -38
- dataface/core/inspect/partials/numeric.yml +0 -53
- dataface/core/inspect/templates/charts.yml +0 -94
- {dataface-0.3.2.dev111.dist-info → dataface-0.3.2.dev150.dist-info}/WHEEL +0 -0
- {dataface-0.3.2.dev111.dist-info → dataface-0.3.2.dev150.dist-info}/entry_points.txt +0 -0
- {dataface-0.3.2.dev111.dist-info → dataface-0.3.2.dev150.dist-info}/licenses/LICENSE +0 -0
|
@@ -18,9 +18,6 @@ from dataface.core.compile.models.chart.authored import (
|
|
|
18
18
|
from dataface.core.compile.models.chart.normalized import Chart
|
|
19
19
|
from dataface.core.compile.models.face.authored import (
|
|
20
20
|
AuthoredFace,
|
|
21
|
-
ForeachConfig,
|
|
22
|
-
ForeachItem,
|
|
23
|
-
ForeachQuery,
|
|
24
21
|
GridLayout,
|
|
25
22
|
LayoutType,
|
|
26
23
|
TabLayout,
|
|
@@ -36,7 +33,6 @@ from dataface.core.compile.normalize_charts import (
|
|
|
36
33
|
generate_inline_chart_id,
|
|
37
34
|
normalize_chart,
|
|
38
35
|
)
|
|
39
|
-
from dataface.core.compile.palette import palette as resolve_palette
|
|
40
36
|
from dataface.core.utils import UniqueKeyLoader
|
|
41
37
|
|
|
42
38
|
|
|
@@ -75,7 +71,6 @@ def build_unified_layout(
|
|
|
75
71
|
theme: str | None = None,
|
|
76
72
|
parent_variables: dict[str, Any] | None = None,
|
|
77
73
|
*,
|
|
78
|
-
_resolve_jinja: bool = False,
|
|
79
74
|
resolved_style: ResolvedStyle,
|
|
80
75
|
parent_level: int = 0,
|
|
81
76
|
sources: dict[str, Any],
|
|
@@ -125,7 +120,6 @@ def build_unified_layout(
|
|
|
125
120
|
theme,
|
|
126
121
|
used_chart_ids,
|
|
127
122
|
parent_variables,
|
|
128
|
-
_resolve_jinja=_resolve_jinja,
|
|
129
123
|
parent_level=parent_level,
|
|
130
124
|
cache_root=cache_root,
|
|
131
125
|
sources=sources,
|
|
@@ -148,7 +142,6 @@ def build_unified_layout(
|
|
|
148
142
|
theme,
|
|
149
143
|
used_chart_ids,
|
|
150
144
|
parent_variables,
|
|
151
|
-
_resolve_jinja=_resolve_jinja,
|
|
152
145
|
parent_level=parent_level,
|
|
153
146
|
cache_root=cache_root,
|
|
154
147
|
sources=sources,
|
|
@@ -171,7 +164,6 @@ def build_unified_layout(
|
|
|
171
164
|
theme,
|
|
172
165
|
used_chart_ids,
|
|
173
166
|
parent_variables,
|
|
174
|
-
_resolve_jinja=_resolve_jinja,
|
|
175
167
|
parent_level=parent_level,
|
|
176
168
|
cache_root=cache_root,
|
|
177
169
|
sources=sources,
|
|
@@ -197,7 +189,6 @@ def build_unified_layout(
|
|
|
197
189
|
face_cache,
|
|
198
190
|
chart_registry,
|
|
199
191
|
theme,
|
|
200
|
-
_resolve_jinja=_resolve_jinja,
|
|
201
192
|
resolved_style=resolved_style,
|
|
202
193
|
parent_level=parent_level,
|
|
203
194
|
cache_root=cache_root,
|
|
@@ -257,7 +248,6 @@ def build_unified_layout(
|
|
|
257
248
|
theme,
|
|
258
249
|
used_chart_ids,
|
|
259
250
|
parent_variables,
|
|
260
|
-
_resolve_jinja=_resolve_jinja,
|
|
261
251
|
parent_level=parent_level,
|
|
262
252
|
cache_root=cache_root,
|
|
263
253
|
sources=sources,
|
|
@@ -284,7 +274,6 @@ def _resolve_layout_items(
|
|
|
284
274
|
theme: str | None = None,
|
|
285
275
|
used_chart_ids: set[str] | None = None,
|
|
286
276
|
parent_variables: dict[str, Any] | None = None,
|
|
287
|
-
_resolve_jinja: bool = False,
|
|
288
277
|
parent_level: int = 0,
|
|
289
278
|
*,
|
|
290
279
|
sources: dict[str, Any],
|
|
@@ -320,50 +309,26 @@ def _resolve_layout_items(
|
|
|
320
309
|
local_chart_ids = local_chart_ids or set()
|
|
321
310
|
|
|
322
311
|
for idx, item in enumerate(items):
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
)
|
|
344
|
-
resolved.extend(foreach_items)
|
|
345
|
-
else:
|
|
346
|
-
layout_item = _resolve_single_item(
|
|
347
|
-
item,
|
|
348
|
-
charts,
|
|
349
|
-
query_registry,
|
|
350
|
-
face_id,
|
|
351
|
-
depth,
|
|
352
|
-
f"{prefix}{idx}",
|
|
353
|
-
base_dir,
|
|
354
|
-
default_source,
|
|
355
|
-
face_cache,
|
|
356
|
-
chart_registry,
|
|
357
|
-
theme,
|
|
358
|
-
used_chart_ids,
|
|
359
|
-
parent_variables,
|
|
360
|
-
_resolve_jinja=_resolve_jinja,
|
|
361
|
-
parent_level=parent_level,
|
|
362
|
-
cache_root=cache_root,
|
|
363
|
-
sources=sources,
|
|
364
|
-
local_chart_ids=local_chart_ids,
|
|
365
|
-
)
|
|
366
|
-
resolved.append(layout_item)
|
|
312
|
+
layout_item = _resolve_single_item(
|
|
313
|
+
item,
|
|
314
|
+
charts,
|
|
315
|
+
query_registry,
|
|
316
|
+
face_id,
|
|
317
|
+
depth,
|
|
318
|
+
f"{prefix}{idx}",
|
|
319
|
+
base_dir,
|
|
320
|
+
default_source,
|
|
321
|
+
face_cache,
|
|
322
|
+
chart_registry,
|
|
323
|
+
theme,
|
|
324
|
+
used_chart_ids,
|
|
325
|
+
parent_variables,
|
|
326
|
+
parent_level=parent_level,
|
|
327
|
+
cache_root=cache_root,
|
|
328
|
+
sources=sources,
|
|
329
|
+
local_chart_ids=local_chart_ids,
|
|
330
|
+
)
|
|
331
|
+
resolved.append(layout_item)
|
|
367
332
|
|
|
368
333
|
return resolved
|
|
369
334
|
|
|
@@ -382,7 +347,6 @@ def _resolve_single_item(
|
|
|
382
347
|
theme: str | None = None,
|
|
383
348
|
used_chart_ids: set[str] | None = None,
|
|
384
349
|
parent_variables: dict[str, Any] | None = None,
|
|
385
|
-
_resolve_jinja: bool = False,
|
|
386
350
|
parent_level: int = 0,
|
|
387
351
|
*,
|
|
388
352
|
sources: dict[str, Any],
|
|
@@ -426,7 +390,6 @@ def _resolve_single_item(
|
|
|
426
390
|
chart_registry,
|
|
427
391
|
theme,
|
|
428
392
|
parent_variables,
|
|
429
|
-
_resolve_jinja=_resolve_jinja,
|
|
430
393
|
parent_level=parent_level,
|
|
431
394
|
cache_root=cache_root,
|
|
432
395
|
sources=sources,
|
|
@@ -466,13 +429,6 @@ def _resolve_single_item(
|
|
|
466
429
|
if isinstance(item, AuthoredFace):
|
|
467
430
|
from dataface.core.compile.normalizer import normalize_face
|
|
468
431
|
|
|
469
|
-
# In foreach context, resolve Jinja templates baked into the typed face.
|
|
470
|
-
# Pydantic parsed templates as literal strings; dump to dict, resolve, re-validate.
|
|
471
|
-
if _resolve_jinja and parent_variables:
|
|
472
|
-
face_dict = item.model_dump(exclude_none=True, by_alias=False)
|
|
473
|
-
face_dict = _resolve_dict_templates(face_dict, parent_variables)
|
|
474
|
-
item = AuthoredFace.model_validate(face_dict)
|
|
475
|
-
|
|
476
432
|
details = item.details
|
|
477
433
|
user_width = str(item.width) if item.width is not None else None
|
|
478
434
|
layout_height = str(item.height) if item.height is not None else None
|
|
@@ -491,7 +447,6 @@ def _resolve_single_item(
|
|
|
491
447
|
"sources": sources,
|
|
492
448
|
"theme": theme,
|
|
493
449
|
"variables": parent_variables,
|
|
494
|
-
"_resolve_jinja": _resolve_jinja,
|
|
495
450
|
},
|
|
496
451
|
query_registry=query_registry,
|
|
497
452
|
chart_registry=chart_registry,
|
|
@@ -550,9 +505,6 @@ def _resolve_single_item(
|
|
|
550
505
|
|
|
551
506
|
|
|
552
507
|
# Layout keys that should not have templates resolved (processed by layout resolution)
|
|
553
|
-
_LAYOUT_KEYS = frozenset({"rows", "cols", "grid", "tabs"})
|
|
554
|
-
|
|
555
|
-
|
|
556
508
|
def _layout_source_path(item_id: str) -> str:
|
|
557
509
|
match = re.fullmatch(r"(row|col|grid)(\d+)", item_id)
|
|
558
510
|
if not match:
|
|
@@ -561,54 +513,6 @@ def _layout_source_path(item_id: str) -> str:
|
|
|
561
513
|
return f"{key}[{match.group(2)}]"
|
|
562
514
|
|
|
563
515
|
|
|
564
|
-
def _resolve_dict_templates(
|
|
565
|
-
data: dict[str, Any],
|
|
566
|
-
variables: dict[str, Any],
|
|
567
|
-
) -> dict[str, Any]:
|
|
568
|
-
"""Resolve Jinja templates recursively in dict values.
|
|
569
|
-
|
|
570
|
-
Used to resolve loop variables and inherited variables in nested face
|
|
571
|
-
definitions created by foreach (compile-time static expansion).
|
|
572
|
-
|
|
573
|
-
Args:
|
|
574
|
-
data: Dict with potentially templated string values
|
|
575
|
-
variables: Variables for Jinja resolution
|
|
576
|
-
|
|
577
|
-
Returns:
|
|
578
|
-
Dict with resolved string values
|
|
579
|
-
"""
|
|
580
|
-
from dataface.core.compile.jinja import resolve_jinja_template
|
|
581
|
-
|
|
582
|
-
result: dict[str, Any] = {}
|
|
583
|
-
for key, value in data.items():
|
|
584
|
-
if isinstance(value, str):
|
|
585
|
-
# Resolve Jinja templates in strings
|
|
586
|
-
result[key] = resolve_jinja_template(value, variables, strict=False)
|
|
587
|
-
elif isinstance(value, dict):
|
|
588
|
-
# Recurse into nested dicts
|
|
589
|
-
result[key] = _resolve_dict_templates(value, variables)
|
|
590
|
-
elif isinstance(value, list):
|
|
591
|
-
# Don't recurse into layout items - those are processed by _resolve_layout_items
|
|
592
|
-
if key in _LAYOUT_KEYS:
|
|
593
|
-
result[key] = value
|
|
594
|
-
else:
|
|
595
|
-
result[key] = [
|
|
596
|
-
(
|
|
597
|
-
_resolve_dict_templates(v, variables)
|
|
598
|
-
if isinstance(v, dict)
|
|
599
|
-
else (
|
|
600
|
-
resolve_jinja_template(v, variables, strict=False)
|
|
601
|
-
if isinstance(v, str)
|
|
602
|
-
else v
|
|
603
|
-
)
|
|
604
|
-
)
|
|
605
|
-
for v in value
|
|
606
|
-
]
|
|
607
|
-
else:
|
|
608
|
-
result[key] = value
|
|
609
|
-
return result
|
|
610
|
-
|
|
611
|
-
|
|
612
516
|
def _resolve_board_file_import(
|
|
613
517
|
file_path: str,
|
|
614
518
|
query_registry: dict[str, AnyQuery],
|
|
@@ -621,7 +525,6 @@ def _resolve_board_file_import(
|
|
|
621
525
|
chart_registry: dict[str, Any] | None = None,
|
|
622
526
|
theme: str | None = None,
|
|
623
527
|
parent_variables: dict[str, Any] | None = None,
|
|
624
|
-
_resolve_jinja: bool = False,
|
|
625
528
|
parent_level: int = 0,
|
|
626
529
|
*,
|
|
627
530
|
sources: dict[str, Any],
|
|
@@ -647,8 +550,6 @@ def _resolve_board_file_import(
|
|
|
647
550
|
theme: Vega-Lite theme to inherit
|
|
648
551
|
used_chart_ids: Set of already-used chart IDs for uniqueness
|
|
649
552
|
parent_variables: Variables from parent scope for template resolution
|
|
650
|
-
_resolve_jinja: If True, resolve Jinja templates in the YAML content
|
|
651
|
-
(foreach creates static faces; all templates baked at compile time).
|
|
652
553
|
If False, skip YAML content resolution so interactive variables
|
|
653
554
|
remain as templates and are resolved at render time.
|
|
654
555
|
|
|
@@ -686,14 +587,6 @@ def _resolve_board_file_import(
|
|
|
686
587
|
# Load and parse the YAML file
|
|
687
588
|
try:
|
|
688
589
|
yaml_content = nested_path.read_text()
|
|
689
|
-
# Only resolve Jinja templates in the YAML content when inside a foreach.
|
|
690
|
-
# Foreach creates static compile-time faces, so all templates (loop vars +
|
|
691
|
-
# interactive defaults) must be baked in. For regular imports, leave
|
|
692
|
-
# templates intact so they are resolved dynamically at render time.
|
|
693
|
-
if _resolve_jinja:
|
|
694
|
-
yaml_content = resolve_jinja_template(
|
|
695
|
-
yaml_content, parent_variables, strict=False
|
|
696
|
-
)
|
|
697
590
|
face_data = yaml.load(yaml_content, Loader=UniqueKeyLoader)
|
|
698
591
|
except yaml.YAMLError as e:
|
|
699
592
|
raise CompilationError(
|
|
@@ -723,7 +616,6 @@ def _resolve_board_file_import(
|
|
|
723
616
|
"sources": sources,
|
|
724
617
|
"theme": theme,
|
|
725
618
|
"variables": parent_variables, # Pass variables to child
|
|
726
|
-
"_resolve_jinja": _resolve_jinja, # Propagate foreach context to children
|
|
727
619
|
}
|
|
728
620
|
|
|
729
621
|
# Compile the nested face
|
|
@@ -741,158 +633,6 @@ def _resolve_board_file_import(
|
|
|
741
633
|
return LayoutItem(type="face", face=compiled_nested)
|
|
742
634
|
|
|
743
635
|
|
|
744
|
-
def _resolve_foreach_item(
|
|
745
|
-
foreach_config: ForeachConfig,
|
|
746
|
-
charts: dict[str, Chart],
|
|
747
|
-
query_registry: dict[str, AnyQuery],
|
|
748
|
-
face_id: str,
|
|
749
|
-
depth: int,
|
|
750
|
-
item_id: str,
|
|
751
|
-
base_dir: ProjectDirectory | None = None,
|
|
752
|
-
default_source: str | None = None,
|
|
753
|
-
face_cache: CachePatch = INHERIT_CACHE,
|
|
754
|
-
chart_registry: dict[str, Any] | None = None,
|
|
755
|
-
theme: str | None = None,
|
|
756
|
-
used_chart_ids: set[str] | None = None,
|
|
757
|
-
parent_variables: dict[str, Any] | None = None,
|
|
758
|
-
parent_level: int = 0,
|
|
759
|
-
*,
|
|
760
|
-
sources: dict[str, Any],
|
|
761
|
-
cache_root: CachePatch | None = None,
|
|
762
|
-
local_chart_ids: set[str] | None = None,
|
|
763
|
-
) -> list[LayoutItem]:
|
|
764
|
-
"""Resolve a foreach construct that iterates over inline data.
|
|
765
|
-
|
|
766
|
-
foreach allows dynamically generating layout items at compile time.
|
|
767
|
-
Each row from the inline data becomes available as a loop variable,
|
|
768
|
-
accessible via dot notation (e.g., {{ col.name }}).
|
|
769
|
-
|
|
770
|
-
Example YAML:
|
|
771
|
-
rows:
|
|
772
|
-
- foreach:
|
|
773
|
-
query:
|
|
774
|
-
data:
|
|
775
|
-
- name: "revenue"
|
|
776
|
-
type: "numeric"
|
|
777
|
-
- name: "date"
|
|
778
|
-
type: "date"
|
|
779
|
-
as: col
|
|
780
|
-
items:
|
|
781
|
-
- 'partials/{{ col.type }}.yml'
|
|
782
|
-
|
|
783
|
-
Note: At compile time, foreach only works with inline data (query.data).
|
|
784
|
-
Query references are not executed during compilation.
|
|
785
|
-
|
|
786
|
-
Args:
|
|
787
|
-
foreach_config: Validated ForeachConfig with query, as_, and items.
|
|
788
|
-
charts: Available charts
|
|
789
|
-
query_registry: Query registry
|
|
790
|
-
face_id: Parent face ID
|
|
791
|
-
depth: Nesting depth
|
|
792
|
-
item_id: ID prefix for generated items
|
|
793
|
-
base_dir: ProjectDirectory handle for resolving external file references
|
|
794
|
-
default_source: Default source for inline queries
|
|
795
|
-
face_cache: The declaring dashboard's `cache:` layer, inherited
|
|
796
|
-
by every query normalized below it
|
|
797
|
-
chart_registry: Raw chart definitions for nested face normalization
|
|
798
|
-
theme: Vega-Lite theme to inherit
|
|
799
|
-
used_chart_ids: Set of already-used chart IDs for uniqueness
|
|
800
|
-
parent_variables: Variables from parent scope
|
|
801
|
-
|
|
802
|
-
Returns:
|
|
803
|
-
List of LayoutItems generated from the foreach iteration
|
|
804
|
-
"""
|
|
805
|
-
query_config = foreach_config.query
|
|
806
|
-
loop_var = foreach_config.as_
|
|
807
|
-
item_templates = foreach_config.items
|
|
808
|
-
parent_variables = parent_variables or {}
|
|
809
|
-
|
|
810
|
-
# Extract inline data from query config
|
|
811
|
-
# At compile time, foreach only works with inline data
|
|
812
|
-
static_data = _get_foreach_data(query_config)
|
|
813
|
-
if not static_data:
|
|
814
|
-
return []
|
|
815
|
-
|
|
816
|
-
# Generate layout items for each row
|
|
817
|
-
resolved_items: list[LayoutItem] = []
|
|
818
|
-
for idx, row in enumerate(static_data):
|
|
819
|
-
loop_context = _build_loop_context(row, loop_var, parent_variables)
|
|
820
|
-
|
|
821
|
-
for template_idx, template_item in enumerate(item_templates):
|
|
822
|
-
layout_item = _resolve_single_item(
|
|
823
|
-
template_item,
|
|
824
|
-
charts,
|
|
825
|
-
query_registry,
|
|
826
|
-
face_id,
|
|
827
|
-
depth,
|
|
828
|
-
f"{item_id}_foreach{idx}_{template_idx}",
|
|
829
|
-
base_dir,
|
|
830
|
-
default_source,
|
|
831
|
-
face_cache,
|
|
832
|
-
chart_registry,
|
|
833
|
-
theme,
|
|
834
|
-
used_chart_ids,
|
|
835
|
-
loop_context,
|
|
836
|
-
_resolve_jinja=True,
|
|
837
|
-
parent_level=parent_level,
|
|
838
|
-
cache_root=cache_root,
|
|
839
|
-
sources=sources,
|
|
840
|
-
local_chart_ids=local_chart_ids,
|
|
841
|
-
)
|
|
842
|
-
resolved_items.append(layout_item)
|
|
843
|
-
|
|
844
|
-
return resolved_items
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
def _get_foreach_data(query_config: ForeachQuery) -> list[dict[str, Any]] | None:
|
|
848
|
-
"""Extract data for foreach iteration from a ForeachQuery.
|
|
849
|
-
|
|
850
|
-
Args:
|
|
851
|
-
query_config: Validated ForeachQuery with optional data, static_data,
|
|
852
|
-
or palette.
|
|
853
|
-
|
|
854
|
-
Returns:
|
|
855
|
-
List of row dicts for iteration, or None if no data.
|
|
856
|
-
"""
|
|
857
|
-
if query_config.palette is not None:
|
|
858
|
-
stops = resolve_palette(query_config.palette)
|
|
859
|
-
return [{"n": i, "hex": hex_value} for i, hex_value in enumerate(stops, 1)]
|
|
860
|
-
data = query_config.data or query_config.static_data
|
|
861
|
-
if isinstance(data, list):
|
|
862
|
-
return data
|
|
863
|
-
return None
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
def _build_loop_context(
|
|
867
|
-
row: Any,
|
|
868
|
-
loop_var: str,
|
|
869
|
-
parent_variables: dict[str, Any],
|
|
870
|
-
) -> dict[str, Any]:
|
|
871
|
-
"""Build the variable context for a foreach iteration.
|
|
872
|
-
|
|
873
|
-
The loop variable is accessible via dot notation: {{ col.field }}
|
|
874
|
-
This keeps variable scoping explicit and avoids shadowing parent variables.
|
|
875
|
-
|
|
876
|
-
Args:
|
|
877
|
-
row: Current row data (dict or scalar)
|
|
878
|
-
loop_var: Name of the loop variable
|
|
879
|
-
parent_variables: Variables inherited from parent scope
|
|
880
|
-
|
|
881
|
-
Returns:
|
|
882
|
-
Combined context dict for Jinja resolution
|
|
883
|
-
"""
|
|
884
|
-
loop_context = dict(parent_variables)
|
|
885
|
-
|
|
886
|
-
if isinstance(row, dict):
|
|
887
|
-
# Row is a dict - accessible as {{ loop_var.field }}
|
|
888
|
-
loop_context[loop_var] = row
|
|
889
|
-
else:
|
|
890
|
-
# Scalar value - wrap in dict with 'value' key
|
|
891
|
-
loop_context[loop_var] = {"value": row}
|
|
892
|
-
|
|
893
|
-
return loop_context
|
|
894
|
-
|
|
895
|
-
|
|
896
636
|
def _resolve_grid_items(
|
|
897
637
|
grid: GridLayout,
|
|
898
638
|
charts: dict[str, Chart],
|
|
@@ -906,7 +646,6 @@ def _resolve_grid_items(
|
|
|
906
646
|
theme: str | None = None,
|
|
907
647
|
used_chart_ids: set[str] | None = None,
|
|
908
648
|
parent_variables: dict[str, Any] | None = None,
|
|
909
|
-
_resolve_jinja: bool = False,
|
|
910
649
|
parent_level: int = 0,
|
|
911
650
|
*,
|
|
912
651
|
sources: dict[str, Any],
|
|
@@ -960,7 +699,6 @@ def _resolve_grid_items(
|
|
|
960
699
|
theme,
|
|
961
700
|
used_chart_ids,
|
|
962
701
|
parent_variables,
|
|
963
|
-
_resolve_jinja=_resolve_jinja,
|
|
964
702
|
parent_level=parent_level,
|
|
965
703
|
cache_root=cache_root,
|
|
966
704
|
sources=sources,
|
|
@@ -1011,7 +749,6 @@ def _resolve_tab_items(
|
|
|
1011
749
|
chart_registry: dict[str, Any] | None = None,
|
|
1012
750
|
theme: str | None = None,
|
|
1013
751
|
*,
|
|
1014
|
-
_resolve_jinja: bool = False,
|
|
1015
752
|
resolved_style: ResolvedStyle,
|
|
1016
753
|
parent_level: int = 0,
|
|
1017
754
|
sources: dict[str, Any],
|
|
@@ -1061,7 +798,6 @@ def _resolve_tab_items(
|
|
|
1061
798
|
"face_cache": face_cache,
|
|
1062
799
|
"sources": sources,
|
|
1063
800
|
"theme": theme,
|
|
1064
|
-
"_resolve_jinja": _resolve_jinja,
|
|
1065
801
|
},
|
|
1066
802
|
query_registry=query_registry,
|
|
1067
803
|
chart_registry=chart_registry,
|