Compile Stage¶
The compile stage transforms YAML dashboard definitions into normalized, validated CompiledBoard objects ready for execution and rendering.
Entry Points¶
compile¶
The main entry point for compiling YAML content:
compile
¶
compile(yaml_content: str, options: Optional[Dict[str, Any]] = None, base_dir: Optional[Path] = None) -> CompileResult
Compile YAML content to a CompiledBoard.
Stage: COMPILE (Full Pipeline)
This is the main entry point for compilation. It orchestrates: 1. PARSE: YAML string → Board object 2. VALIDATE: Check structure and references 3. NORMALIZE: Resolve references, add metadata 4. SIZE: Calculate layout dimensions
| PARAMETER | DESCRIPTION |
|---|---|
yaml_content
|
YAML string to compile
TYPE:
|
options
|
Optional compilation options
TYPE:
|
base_dir
|
Base directory for resolving file references
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
CompileResult
|
CompileResult with compiled board or errors |
Example
yaml_content = ''' ... title: My Dashboard ... queries: ... users: SELECT * FROM users ... charts: ... user_count: ... query: users ... type: kpi ... metric: count ... rows: ... - user_count ... ''' result = compile(yaml_content) if result.success: ... board = result.board ... print(board.title) # "My Dashboard"
Source code in dataface/compile/compiler.py
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | |
compile_file¶
Compile from a file path:
compile_file
¶
Compile a YAML file to a CompiledBoard.
Convenience function that reads a file and compiles it.
| PARAMETER | DESCRIPTION |
|---|---|
file_path
|
Path to YAML file
TYPE:
|
options
|
Optional compilation options
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
CompileResult
|
CompileResult with compiled board or errors |
| RAISES | DESCRIPTION |
|---|---|
FileNotFoundError
|
If file doesn't exist |
Example
result = compile_file(Path("dashboard.yml")) if result.success: ... print(result.board.title)
Source code in dataface/compile/compiler.py
CompileResult¶
The result object returned by compilation:
CompileResult
dataclass
¶
CompileResult(board: Optional[CompiledBoard] = None, errors: List[CompilationError] = list(), warnings: List[str] = list(), query_registry: Dict[str, CompiledQuery] = dict())
Result of compilation.
Contains the compiled board (if successful), any errors encountered, and warnings that don't prevent compilation.
| ATTRIBUTE | DESCRIPTION |
|---|---|
board |
Compiled board (None if errors occurred)
TYPE:
|
errors |
List of compilation errors
TYPE:
|
warnings |
List of non-fatal warnings
TYPE:
|
query_registry |
All normalized queries (for executor)
TYPE:
|
Example
result = compile(yaml_content) if result.success: ... print(f"Compiled: {result.board.title}") ... else: ... for error in result.errors: ... print(f"Error: {error}")
Compiled Types¶
These types represent the output of compilation, with all fields guaranteed to be present.
CompiledBoard¶
CompiledBoard
¶
Bases: BaseModel
Compiled board ready for execution and rendering.
Stage: COMPILE output / EXECUTE and RENDER input
This is the main output of compilation. It contains: - Resolved definitions (variables, queries, charts) - Unified layout structure - Calculated dimensions - Applied defaults and metadata
Guarantees
- id: Always set
- title: Always set (empty string if not provided)
- layout: Always present (unified structure)
- All charts resolved to CompiledChart objects
- All queries resolved to query objects
| ATTRIBUTE | DESCRIPTION |
|---|---|
id |
Unique identifier for this board
TYPE:
|
title |
Display title
TYPE:
|
description |
Description text
TYPE:
|
variables |
Variable definitions (Dict[str, Variable])
TYPE:
|
queries |
Compiled queries (Dict[str, CompiledQuery])
TYPE:
|
charts |
Compiled charts (Dict[str, CompiledChart])
TYPE:
|
layout |
Unified layout structure
TYPE:
|
variable_defaults |
Resolved default values for variables
TYPE:
|
style |
Board styling
TYPE:
|
depth |
Nesting depth (0 = root)
TYPE:
|
Example
result = compile(yaml_content) board = result.board print(board.id) # "sales-dashboard" print(board.title) # "Sales Dashboard" print(board.layout.type) # "rows" for item in board.layout.items: ... chart = item.chart ... print(f"Chart: {chart.id}, Query: {chart.query_name}")
CompiledChart¶
CompiledChart
¶
Bases: BaseModel
Compiled chart ready for execution and rendering.
Stage: COMPILE output / EXECUTE and RENDER input
This type represents a fully normalized chart where: - All optional fields from Chart have been resolved - The query reference has been resolved to a query object - An ID has been assigned - Title and description have defaults applied
Guarantees vs Chart (input type): | Field | Chart (input) | CompiledChart (compiled) | |-------------|-----------------------|----------------------------| | id | Optional[str] | str (always present) | | title | Optional[str] | str (empty string default) | | description | Optional[str] | str (empty string default) | | query | str (reference) | Query object (resolved) |
Downstream code can access fields directly without checking for None.
| ATTRIBUTE | DESCRIPTION |
|---|---|
id |
Unique identifier within the dashboard.
TYPE:
|
query |
Resolved query object (SqlQuery, CsvQuery, etc.)
TYPE:
|
query_name |
String name for executor lookup.
TYPE:
|
type |
Chart type (line, bar, table, etc.)
TYPE:
|
title |
Display title. Empty string if not provided.
TYPE:
|
description |
Description. Empty string if not provided.
TYPE:
|
validate_kpi
¶
Validate KPI charts have metric field.
Source code in dataface/compile/compiled_types.py
LayoutItem¶
LayoutItem
¶
Bases: BaseModel
A single item in a layout.
Represents either a chart or a nested board in the layout. The unified structure makes iteration simple:
for item in layout.items:
if item.type == "chart":
render_chart(item.chart)
else:
render_board(item.board)
| ATTRIBUTE | DESCRIPTION |
|---|---|
type |
Either "chart" or "board"
TYPE:
|
chart |
CompiledChart if type == "chart"
TYPE:
|
board |
CompiledBoard if type == "board"
TYPE:
|
Grid-specific (optional): row, col: Grid position (0-based) row_span, col_span: Grid span (in grid units)
Calculated dimensions (set by sizing module): width_fraction: What fraction of parent width (0.0-1.0) width: Pixel width height: Pixel height x: X position in pixels y: Y position in pixels
Query Types¶
Dataface supports multiple query types through a unified interface.
SqlQuery¶
SqlQuery
¶
Bases: Query
SQL query against a database.
Executes raw SQL against the configured database connection. Supports Jinja templating for variable substitution.
Required Fields
sql: SQL query string (may contain Jinja templates)
Connection Fields (one required): source: Source name or inline config (new preferred way) profile: dbt profile name (legacy, alias for source)
Optional Fields
target: dbt target name (defaults to 'dev' if not specified)
Example
query = SqlQuery( ... sql="SELECT * FROM users WHERE id = {{ user_id }}", ... source="my_postgres" ... ) query.query_type # "sql" query.source_description # "SQL: SELECT * FROM users WHERE id = {{ user_..."
effective_source
property
¶
Get effective source (source takes precedence over profile).
CsvQuery¶
CsvQuery
¶
Bases: Query
Query data from a CSV file.
Loads and queries data from CSV files. Supports column selection, filtering, and limiting results.
Fields (one required): file: Path to CSV file (relative to project root or absolute) source: Source reference or inline CSV source config
Optional Fields
columns: List of columns to select (default: all) filter: Dict of column->value for exact match filtering
Example
query = CsvQuery(file="data/sales.csv", columns=["date", "amount"]) query.query_type # "csv" query.source_description # "CSV: data/sales.csv"
HttpQuery¶
HttpQuery
¶
Bases: Query
Query data from an HTTP API.
Fetches data from REST API endpoints. Supports various HTTP methods, headers, query parameters, and request bodies.
Fields
url: Full URL of the API endpoint (legacy) source: Source reference or inline HTTP source config (new) path: API path (appended to base URL from source)
Optional Fields
method: HTTP method (default: GET) headers: Request headers (merged with source headers) params: Query parameters body: Request body (for POST/PUT/PATCH) json_path: JSONPath expression to extract data from response
Example
query = HttpQuery( ... source="model_api", ... path="/predict", ... method="POST", ... body={"input": "data"} ... ) query.query_type # "http" query.source_description # "HTTP: POST model_api/predict"
MetricFlowQuery¶
MetricFlowQuery
¶
Bases: Query
Query the dbt Semantic Layer.
Executes queries against dbt's Semantic Layer using MetricFlow. Supports metrics, dimensions, filters, and time grains.
Required Fields
metrics: List of metric names to query
Optional Fields
dimensions: List of dimension names to group by time_grain: Time grain for time-based dimensions (day, week, month, etc.)
Example
query = MetricFlowQuery( ... metrics=["revenue", "orders"], ... dimensions=["date_day", "region"] ... ) query.query_type # "metricflow" query.source_description # "MetricFlow: revenue, orders"
Input Types¶
These types represent the raw YAML structure before normalization.
Board¶
Board
¶
Bases: BaseModel
Board (dashboard) definition from YAML.
This is the top-level input type representing a complete dashboard. A board contains definitions (variables, queries, charts) and a layout.
Example YAML
title: Sales Dashboard description: Overview of sales metrics
sources: default: my_postgres # Default source for all queries
variables: date_range: input: daterange default: ["2024-01-01", "2024-12-31"]
queries: sales: SELECT * FROM sales WHERE date BETWEEN ...
charts: revenue: query: sales type: line x: date y: amount
rows: - revenue
Layout
Exactly one layout type should be present (rows, cols, grid, or tabs). Layout items can be: - Chart name (string reference) - Inline chart definition (dict with query and type) - Nested board (dict with layout keys)
Sources
Optional sources section with: - default: Default source name for all queries in this board - Inline source definitions (source_name: {...config...})
reject_dashboard_key
classmethod
¶
Reject 'dashboard' as a top-level key - it's not valid syntax.
Source code in dataface/compile/types.py
validate_layout
¶
Ensure at least one layout type or content is defined.
Source code in dataface/compile/types.py
get_default_source
¶
Get the default source for this board.
| RETURNS | DESCRIPTION |
|---|---|
Optional[str]
|
Default source name, or None if not set |
Source code in dataface/compile/types.py
Chart¶
Chart
¶
Bases: BaseModel
Chart definition from YAML.
Charts visualize query results. The type determines the visualization.
Example YAML
charts: revenue_trend: query: sales_by_date type: line title: "Revenue Trend" x: date y: amount color: category
| ATTRIBUTE | DESCRIPTION |
|---|---|
query |
Reference to a query name (required)
TYPE:
|
type |
Chart type (line, bar, etc.)
TYPE:
|
title |
Display title (optional, derived from chart name if not set)
TYPE:
|
x, |
Data field mappings for axes
TYPE:
|
color, |
Additional encodings
TYPE:
|
validate_kpi
¶
Validate KPI charts have metric field.
Query¶
Query
¶
Bases: BaseModel
Query definition from YAML.
Queries fetch data from various sources. The type field determines which adapter handles execution.
Supported types: - sql: Raw SQL query (default) - metricflow: dbt Semantic Layer query - dbt_model: Query against a dbt model - http: REST API query - csv: CSV file query
Example YAML
queries: sales_by_date: sql: SELECT date, SUM(amount) FROM sales GROUP BY date source: my_postgres # Source reference
metrics_query: type: metricflow metrics: [revenue, orders] dimensions: [date_day]
api_data: type: http url: https://api.example.com/data
Errors¶
errors
¶
Compilation error types.
Stage: COMPILE Purpose: Define error types for all compilation failures.
These errors are raised during: - YAML parsing (ParseError, YAMLError) - Schema validation (ValidationError) - Reference resolution (ReferenceError) - Jinja template rendering (JinjaError)
All errors inherit from CompilationError for easy catching.
CompilationError
¶
Bases: DatafaceError
Base error for all compilation failures.
This is the parent class for all compilation-related errors. Catch this to handle any compilation error.
| ATTRIBUTE | DESCRIPTION |
|---|---|
message |
Human-readable error description
|
location |
Optional location in source (line number, path, etc.)
|
Source code in dataface/compile/errors.py
ParseError
¶
Bases: CompilationError
Error during YAML parsing.
Raised when: - YAML syntax is invalid - YAML structure cannot be parsed
Example
try: ... compile("invalid: yaml: content") ... except ParseError as e: ... print(f"Parse failed: {e}")
Source code in dataface/compile/errors.py
ValidationError
¶
Bases: CompilationError
Error during schema validation.
Raised when: - Required fields are missing - Field values are invalid type - Enum values are not recognized - Schema constraints are violated
Example
try: ... compile("charts:\n my_chart:\n type: invalid_type") ... except ValidationError as e: ... print(f"Validation failed: {e}")
Source code in dataface/compile/errors.py
ReferenceError
¶
Bases: CompilationError
Error resolving a reference.
Raised when: - Chart references unknown query - Layout references unknown chart - Remote reference cannot be resolved - Partial file not found
| ATTRIBUTE | DESCRIPTION |
|---|---|
ref |
The reference that could not be resolved
|
context |
Where the reference was used
|
Example
try: ... compile("charts:\n my_chart:\n query: unknown_query") ... except ReferenceError as e: ... print(f"Reference '{e.ref}' not found")
Source code in dataface/compile/errors.py
JinjaError
¶
Bases: CompilationError
Error during Jinja template resolution.
Raised when: - Jinja syntax is invalid - Variable not found in template context - Filter not found
| ATTRIBUTE | DESCRIPTION |
|---|---|
template |
The template that caused the error (if available)
|
Example
try: ... compile("queries:\n q: SELECT * FROM {{ undefined_var }}") ... except JinjaError as e: ... print(f"Template error: {e}")
Source code in dataface/compile/errors.py
Internal Modules¶
These are used internally by the compiler. Most users won't need to use them directly.
Parser¶
parse_yaml
¶
Parse YAML content into a Board object.
Stage: COMPILE (Step 1 of 4: Parsing)
This is the first step of compilation. It converts a raw YAML string into a structured Board object. Only basic syntax validation happens here - schema validation is the next step.
| PARAMETER | DESCRIPTION |
|---|---|
content
|
Raw YAML string to parse
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Board
|
Board object with parsed structure |
| RAISES | DESCRIPTION |
|---|---|
ParseError
|
If YAML syntax is invalid or parsing fails |
Example
yaml_content = ''' ... title: My Dashboard ... queries: ... sales: SELECT * FROM sales ... charts: ... revenue: ... query: sales ... type: line ... rows: ... - revenue ... ''' board = parse_yaml(yaml_content) board.title 'My Dashboard'
Source code in dataface/compile/parser.py
Validator¶
validate_board
¶
Validate a Board structure and cross-references.
Stage: COMPILE (Step 2 of 4: Validation)
Performs semantic validation beyond what Pydantic provides: - Chart → Query references exist - Layout items reference existing charts
Note: Pydantic already validates types, required fields, and nested structures during parsing. This function adds cross-reference validation.
| PARAMETER | DESCRIPTION |
|---|---|
board
|
Parsed Board to validate
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
List[ValidationError]
|
List of ValidationError objects (empty if valid) |
Example
board = parse_yaml(yaml_content) errors = validate_board(board) if errors: ... for e in errors: ... print(f"Error: {e}")
Source code in dataface/compile/validator.py
Normalizer¶
normalize_board
¶
normalize_board(board: Board, board_id: Optional[str] = None, parent_context: Optional[Dict[str, Any]] = None, query_registry: Optional[Dict[str, CompiledQuery]] = None, chart_registry: Optional[Dict[str, Any]] = None, depth: int = 0, base_path: Optional[Path] = None) -> CompiledBoard
Normalize a Board into a CompiledBoard with guaranteed structure.
Stage: COMPILE (Step 3 of 4: Normalization)
This is the core transformation from user-provided YAML structure to the internal compiled representation. After this step, all references are resolved, IDs are assigned, and downstream code can rely on guaranteed field presence.
Normalization performs: 1. Resolve all chart references (queries, extends, partials) 2. Generate unique IDs for all entities 3. Apply defaults (title from ID, empty description) 4. Transform input types to compiled types 5. Create unified Layout structure 6. Propagate default source to queries without explicit source
| PARAMETER | DESCRIPTION |
|---|---|
board
|
Input Board from parsing/validation step.
TYPE:
|
board_id
|
Optional explicit ID for this board
TYPE:
|
parent_context
|
Context from parent board (for nested boards)
TYPE:
|
query_registry
|
Complete query registry for reference resolution
TYPE:
|
chart_registry
|
Complete chart registry for reference resolution
TYPE:
|
depth
|
Current nesting depth (for cycle detection)
TYPE:
|
base_path
|
Base path for resolving external file references
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
CompiledBoard
|
CompiledBoard with guarantees: - All fields required by compiled types are present - All references resolved to actual objects - All IDs are unique and deterministic - Layout is unified (rows/cols/grid/tabs → Layout type) |
| RAISES | DESCRIPTION |
|---|---|
ReferenceError
|
When a chart references an undefined query |
CompilationError
|
When normalization fails |
Example
board = parse_yaml(yaml_content) errors = validate_board(board) if not errors: ... compiled = normalize_board(board) ... print(compiled.charts['revenue'].id) # Guaranteed to exist 'revenue'
Source code in dataface/compile/normalizer.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | |
Sizing¶
calculate_layout
¶
Calculate dimensions for all layout items.
Stage: COMPILE (Step 4 of 4: Layout Calculation)
This is the final compilation step. It calculates pixel dimensions for all charts and nested boards based on layout type and nesting.
The sizing is content-aware: - KPIs get smaller heights (~100px) - Charts get standard heights (~300px) - Titles are measured for text wrapping - Nested boards accumulate their content heights
| PARAMETER | DESCRIPTION |
|---|---|
board
|
CompiledBoard with layout structure
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
CompiledBoard
|
CompiledBoard with calculated dimensions on layout items |
Example
board = normalize_board(parsed_board) board = calculate_layout(board) print(board.layout.width, board.layout.height) 1200.0 800.0