dataface 0.1.2__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.
- d3_format/__init__.py +14 -0
- d3_format/errors.py +19 -0
- d3_format/format.py +551 -0
- d3_format/spec.py +159 -0
- dataface/DATAFACE_SYNTAX.md +1135 -0
- dataface/__init__.py +93 -0
- dataface/_docs_site.py +20 -0
- dataface/_install_hint.py +26 -0
- dataface/agent_api/__init__.py +79 -0
- dataface/agent_api/_init_templates/__init__.py +0 -0
- dataface/agent_api/_init_templates/agents_dft_snippet.md +26 -0
- dataface/agent_api/_init_templates/dataface.yml +15 -0
- dataface/agent_api/_init_templates/faces-dataface.yml +144 -0
- dataface/agent_api/_init_templates/index.md +24 -0
- dataface/agent_api/_paths.py +118 -0
- dataface/agent_api/_project_agents_md.py +43 -0
- dataface/agent_api/_session_store.py +486 -0
- dataface/agent_api/_state.py +28 -0
- dataface/agent_api/chat.py +221 -0
- dataface/agent_api/dashboards.py +257 -0
- dataface/agent_api/describe.py +366 -0
- dataface/agent_api/describe_query.py +120 -0
- dataface/agent_api/docs/__init__.py +25 -0
- dataface/agent_api/docs/_loader.py +292 -0
- dataface/agent_api/docs/yaml-reference.md +2757 -0
- dataface/agent_api/file_refs.py +118 -0
- dataface/agent_api/init.py +126 -0
- dataface/agent_api/inspect.py +128 -0
- dataface/agent_api/mcp_install.py +170 -0
- dataface/agent_api/query.py +274 -0
- dataface/agent_api/schema.py +658 -0
- dataface/agent_api/schema_search.py +284 -0
- dataface/agent_api/search.py +270 -0
- dataface/agent_api/skill_install.py +141 -0
- dataface/agent_api/skill_render.py +90 -0
- dataface/agent_api/skills.py +293 -0
- dataface/agent_api/surface_aliases.yaml +128 -0
- dataface/agent_api/validate.py +175 -0
- dataface/agent_api/validate_query.py +84 -0
- dataface/ai/__init__.py +39 -0
- dataface/ai/agent.py +139 -0
- dataface/ai/context.py +45 -0
- dataface/ai/events.py +62 -0
- dataface/ai/external_mcp.py +610 -0
- dataface/ai/generate_sql.py +96 -0
- dataface/ai/llm.py +403 -0
- dataface/ai/mcp/__init__.py +51 -0
- dataface/ai/mcp/server.py +289 -0
- dataface/ai/memories.py +85 -0
- dataface/ai/prompts.py +177 -0
- dataface/ai/schema_context.py +138 -0
- dataface/ai/skills/before-after-comparison/SKILL.md +102 -0
- dataface/ai/skills/before-after-comparison/examples/before-after-comparison.yml +24 -0
- dataface/ai/skills/dashboard-build/SKILL.md +212 -0
- dataface/ai/skills/dashboard-build/examples/_smoke.yml +15 -0
- dataface/ai/skills/dashboard-design/SKILL.md +182 -0
- dataface/ai/skills/dashboard-review/SKILL.md +113 -0
- dataface/ai/skills/dashboard-structural-review/SKILL.md +173 -0
- dataface/ai/skills/dashboard-visual-review/SKILL.md +139 -0
- dataface/ai/skills/dataface-mcp-setup/SKILL.md +177 -0
- dataface/ai/skills/dataface-troubleshooting/SKILL.md +225 -0
- dataface/ai/skills/drill-down-link/SKILL.md +112 -0
- dataface/ai/skills/drill-down-link/examples/drill-down-link.yml +27 -0
- dataface/ai/skills/faceted-small-multiples/SKILL.md +116 -0
- dataface/ai/skills/faceted-small-multiples/examples/faceted-small-multiples.yml +33 -0
- dataface/ai/skills/filter-bar-with-variables/SKILL.md +105 -0
- dataface/ai/skills/filter-bar-with-variables/examples/filter-bar-with-variables.yml +49 -0
- dataface/ai/skills/kpi-row/SKILL.md +101 -0
- dataface/ai/skills/kpi-row/examples/kpi-row.yml +55 -0
- dataface/ai/skills/report-design/SKILL.md +184 -0
- dataface/ai/skills/single-metric-bignum/SKILL.md +90 -0
- dataface/ai/skills/single-metric-bignum/examples/single-metric-bignum.yml +27 -0
- dataface/ai/skills/table-heavy-ops-dashboard/SKILL.md +114 -0
- dataface/ai/skills/table-heavy-ops-dashboard/examples/table-heavy-ops-dashboard.yml +48 -0
- dataface/ai/skills/time-series-trend/SKILL.md +93 -0
- dataface/ai/skills/time-series-trend/examples/time-series-trend.yml +26 -0
- dataface/ai/skills/top-n-with-detail/SKILL.md +98 -0
- dataface/ai/skills/top-n-with-detail/examples/top-n-with-detail.yml +45 -0
- dataface/ai/skills/two-by-two-grid-overview/SKILL.md +78 -0
- dataface/ai/skills/two-by-two-grid-overview/examples/two-by-two-grid-overview.yml +64 -0
- dataface/ai/tool_schemas.py +132 -0
- dataface/ai/tools/__init__.py +312 -0
- dataface/ai/yaml_utils.py +57 -0
- dataface/cli/__init__.py +3 -0
- dataface/cli/_console.py +48 -0
- dataface/cli/_error_format.py +83 -0
- dataface/cli/_extras.py +190 -0
- dataface/cli/_json_output.py +8 -0
- dataface/cli/_parsing.py +17 -0
- dataface/cli/_version_info.py +56 -0
- dataface/cli/commands/__init__.py +3 -0
- dataface/cli/commands/_agent_input.py +205 -0
- dataface/cli/commands/_agent_server.py +115 -0
- dataface/cli/commands/chat.py +645 -0
- dataface/cli/commands/describe.py +107 -0
- dataface/cli/commands/docs.py +131 -0
- dataface/cli/commands/extension.py +179 -0
- dataface/cli/commands/init.py +240 -0
- dataface/cli/commands/inspect.py +94 -0
- dataface/cli/commands/mcp_init.py +167 -0
- dataface/cli/commands/query.py +386 -0
- dataface/cli/commands/render.py +291 -0
- dataface/cli/commands/schema.py +411 -0
- dataface/cli/commands/search.py +49 -0
- dataface/cli/commands/serve.py +114 -0
- dataface/cli/commands/skills.py +133 -0
- dataface/cli/commands/skills_init.py +161 -0
- dataface/cli/commands/validate.py +63 -0
- dataface/cli/main.py +1501 -0
- dataface/core/__init__.py +75 -0
- dataface/core/compile/__init__.py +244 -0
- dataface/core/compile/_jinja_helpers.py +78 -0
- dataface/core/compile/channel.py +222 -0
- dataface/core/compile/chart_focus.py +101 -0
- dataface/core/compile/chart_resolved.py +169 -0
- dataface/core/compile/chart_type_detection.py +489 -0
- dataface/core/compile/chart_update.py +261 -0
- dataface/core/compile/colors.py +64 -0
- dataface/core/compile/compiler.py +904 -0
- dataface/core/compile/config.py +823 -0
- dataface/core/compile/custom_chart_types.py +208 -0
- dataface/core/compile/data_table_attachment.py +1287 -0
- dataface/core/compile/detect.py +110 -0
- dataface/core/compile/errors.py +302 -0
- dataface/core/compile/filter_injection.py +319 -0
- dataface/core/compile/introspection.py +527 -0
- dataface/core/compile/jinja.py +511 -0
- dataface/core/compile/labels_env.py +52 -0
- dataface/core/compile/markdown.py +154 -0
- dataface/core/compile/meta.py +388 -0
- dataface/core/compile/models/__init__.py +0 -0
- dataface/core/compile/models/chart/__init__.py +0 -0
- dataface/core/compile/models/chart/authored.py +2137 -0
- dataface/core/compile/models/chart/compiled.py +398 -0
- dataface/core/compile/models/config.py +347 -0
- dataface/core/compile/models/face/__init__.py +0 -0
- dataface/core/compile/models/face/authored.py +659 -0
- dataface/core/compile/models/face/compiled.py +522 -0
- dataface/core/compile/models/factories.py +201 -0
- dataface/core/compile/models/markers.py +40 -0
- dataface/core/compile/models/palette.py +36 -0
- dataface/core/compile/models/primitives.py +415 -0
- dataface/core/compile/models/query/__init__.py +0 -0
- dataface/core/compile/models/query/authored.py +246 -0
- dataface/core/compile/models/query/compiled.py +710 -0
- dataface/core/compile/models/refs.py +137 -0
- dataface/core/compile/models/source.py +611 -0
- dataface/core/compile/models/style/__init__.py +0 -0
- dataface/core/compile/models/style/authored.py +481 -0
- dataface/core/compile/models/style/compiled.py +3399 -0
- dataface/core/compile/models/style/merged.py +1682 -0
- dataface/core/compile/models/theme.py +362 -0
- dataface/core/compile/models/variable/__init__.py +0 -0
- dataface/core/compile/models/variable/authored.py +254 -0
- dataface/core/compile/models/vega_lite/__init__.py +0 -0
- dataface/core/compile/models/vega_lite/config.py +510 -0
- dataface/core/compile/models/vega_lite/contracts.py +171 -0
- dataface/core/compile/normalize_charts.py +494 -0
- dataface/core/compile/normalize_layout.py +1000 -0
- dataface/core/compile/normalize_queries.py +297 -0
- dataface/core/compile/normalize_variables.py +489 -0
- dataface/core/compile/normalizer.py +543 -0
- dataface/core/compile/palette.py +1100 -0
- dataface/core/compile/parameterized.py +658 -0
- dataface/core/compile/parser.py +228 -0
- dataface/core/compile/schema.py +20 -0
- dataface/core/compile/schema_renderers/__init__.py +0 -0
- dataface/core/compile/schema_renderers/json_schema.py +163 -0
- dataface/core/compile/schema_renderers/prompt.py +152 -0
- dataface/core/compile/schema_renderers/vscode_schema.py +301 -0
- dataface/core/compile/sizing.py +2126 -0
- dataface/core/compile/sources.py +518 -0
- dataface/core/compile/sql_authoring_lint.py +56 -0
- dataface/core/compile/style_cascade.py +471 -0
- dataface/core/compile/typography.py +299 -0
- dataface/core/compile/validator.py +301 -0
- dataface/core/compile/variables.py +53 -0
- dataface/core/compile/vega_config.py +98 -0
- dataface/core/compile/vega_lite/__init__.py +6 -0
- dataface/core/compile/vega_lite/validation.py +95 -0
- dataface/core/compile/yaml_error_formatter.py +838 -0
- dataface/core/connections.py +38 -0
- dataface/core/dashboard.py +358 -0
- dataface/core/defaults/default_config.yml +101 -0
- dataface/core/defaults/palettes/categorical/category-10-dark.yml +32 -0
- dataface/core/defaults/palettes/categorical/category-10-light.yml +43 -0
- dataface/core/defaults/palettes/categorical/category-10.yml +31 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-blue.yml +22 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-brown.yml +29 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-green.yml +20 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-orange.yml +21 -0
- dataface/core/defaults/palettes/categorical/category-6-tonal-purple.yml +20 -0
- dataface/core/defaults/palettes/categorical/editorial-10-dark.yml +32 -0
- dataface/core/defaults/palettes/categorical/editorial-10.yml +40 -0
- dataface/core/defaults/palettes/categorical/hero-6.yml +17 -0
- dataface/core/defaults/palettes/categorical/single-blue.yml +11 -0
- dataface/core/defaults/palettes/categorical/tableau.yml +20 -0
- dataface/core/defaults/palettes/data/xkcd_colors.json +3803 -0
- dataface/core/defaults/palettes/diverging/blue-red.yml +25 -0
- dataface/core/defaults/palettes/diverging/coolwarm.yml +24 -0
- dataface/core/defaults/palettes/diverging/crimson-green.yml +23 -0
- dataface/core/defaults/palettes/diverging/orange-teal.yml +23 -0
- dataface/core/defaults/palettes/diverging/sunset.yml +24 -0
- dataface/core/defaults/palettes/scaffold/dft-creams.yml +38 -0
- dataface/core/defaults/palettes/scaffold/dft-grays.yml +53 -0
- dataface/core/defaults/palettes/sequential/amber.yml +22 -0
- dataface/core/defaults/palettes/sequential/blue.yml +22 -0
- dataface/core/defaults/palettes/sequential/brown.yml +22 -0
- dataface/core/defaults/palettes/sequential/gray.yml +22 -0
- dataface/core/defaults/palettes/sequential/green.yml +22 -0
- dataface/core/defaults/palettes/sequential/purple.yml +22 -0
- dataface/core/defaults/palettes/sequential/rust.yml +22 -0
- dataface/core/defaults/palettes/sequential/teal.yml +22 -0
- dataface/core/defaults/palettes/tone/negative.yml +32 -0
- dataface/core/defaults/palettes/tone/positive.yml +22 -0
- dataface/core/defaults/palettes/tone/warning.yml +22 -0
- dataface/core/defaults/themes/_base.yaml +786 -0
- dataface/core/defaults/themes/bi.yaml +16 -0
- dataface/core/defaults/themes/carbong100.yaml +41 -0
- dataface/core/defaults/themes/cream.yaml +122 -0
- dataface/core/defaults/themes/dark.yaml +40 -0
- dataface/core/defaults/themes/diagnostics-title-angle-extreme.yaml +9 -0
- dataface/core/defaults/themes/diagnostics-title-baseline-extreme.yaml +9 -0
- dataface/core/defaults/themes/diagnostics-title-baseline.yaml +24 -0
- dataface/core/defaults/themes/diagnostics-title-center.yaml +8 -0
- dataface/core/defaults/themes/diagnostics-title-color-extreme.yaml +24 -0
- dataface/core/defaults/themes/diagnostics-title-font-extreme.yaml +25 -0
- dataface/core/defaults/themes/diagnostics-title-left.yaml +8 -0
- dataface/core/defaults/themes/diagnostics-title-offset-extreme.yaml +9 -0
- dataface/core/defaults/themes/diagnostics-title-size-extreme.yaml +24 -0
- dataface/core/defaults/themes/diagnostics-title-weight-extreme.yaml +24 -0
- dataface/core/defaults/themes/editorial.yaml +147 -0
- dataface/core/defaults/themes/light.yaml +30 -0
- dataface/core/defaults/themes/looker.yaml +17 -0
- dataface/core/defaults/themes/stark.yaml +134 -0
- dataface/core/errors/__init__.py +67 -0
- dataface/core/errors/codes_compile.py +56 -0
- dataface/core/errors/codes_execute.py +177 -0
- dataface/core/errors/codes_render.py +106 -0
- dataface/core/errors/codes_unknown.py +15 -0
- dataface/core/errors/hints.py +74 -0
- dataface/core/errors/registry.py +42 -0
- dataface/core/errors/structured.py +92 -0
- dataface/core/execute/__init__.py +91 -0
- dataface/core/execute/adapters/__init__.py +49 -0
- dataface/core/execute/adapters/adapter_registry.py +400 -0
- dataface/core/execute/adapters/base.py +245 -0
- dataface/core/execute/adapters/csv_adapter.py +239 -0
- dataface/core/execute/adapters/dbt_adapter.py +283 -0
- dataface/core/execute/adapters/dbt_adapter_factory.py +212 -0
- dataface/core/execute/adapters/dbt_macro_loader.py +95 -0
- dataface/core/execute/adapters/dbt_utils.py +150 -0
- dataface/core/execute/adapters/http_adapter.py +224 -0
- dataface/core/execute/adapters/metricflow_adapter.py +94 -0
- dataface/core/execute/adapters/schema_resolver_adapter.py +144 -0
- dataface/core/execute/adapters/sql_adapter.py +710 -0
- dataface/core/execute/adapters/values_adapter.py +58 -0
- dataface/core/execute/batch.py +744 -0
- dataface/core/execute/cache_backend.py +135 -0
- dataface/core/execute/cache_keys.py +66 -0
- dataface/core/execute/dbt_jinja.py +21 -0
- dataface/core/execute/dialects/__init__.py +121 -0
- dataface/core/execute/dialects/athena.py +75 -0
- dataface/core/execute/dialects/base.py +302 -0
- dataface/core/execute/dialects/bigquery.py +38 -0
- dataface/core/execute/dialects/databricks.py +68 -0
- dataface/core/execute/dialects/duckdb.py +35 -0
- dataface/core/execute/dialects/mysql.py +68 -0
- dataface/core/execute/dialects/postgres.py +39 -0
- dataface/core/execute/dialects/redshift.py +12 -0
- dataface/core/execute/dialects/snowflake.py +51 -0
- dataface/core/execute/dialects/sqlserver.py +92 -0
- dataface/core/execute/duckdb_cache.py +712 -0
- dataface/core/execute/duckdb_config.py +26 -0
- dataface/core/execute/errors.py +213 -0
- dataface/core/execute/executor.py +1249 -0
- dataface/core/execute/parallel.py +162 -0
- dataface/core/execute/setup_sql.py +58 -0
- dataface/core/execute/source_registry.py +72 -0
- dataface/core/execute/source_resolver.py +255 -0
- dataface/core/execute/sql_guard.py +387 -0
- dataface/core/execute/sql_literals.py +199 -0
- dataface/core/fonts.py +52 -0
- dataface/core/inspect/__init__.py +32 -0
- dataface/core/inspect/cache_factory.py +98 -0
- dataface/core/inspect/db_types.py +162 -0
- dataface/core/inspect/dbt_schema.py +96 -0
- dataface/core/inspect/defaults.yml +37 -0
- dataface/core/inspect/fanout_risk.py +109 -0
- dataface/core/inspect/manifest_utils.py +77 -0
- dataface/core/inspect/partials/categorical.yml +40 -0
- dataface/core/inspect/partials/date.yml +40 -0
- dataface/core/inspect/partials/numeric.yml +55 -0
- dataface/core/inspect/partition_types.py +38 -0
- dataface/core/inspect/query_validator.py +975 -0
- dataface/core/inspect/renderer.py +354 -0
- dataface/core/inspect/resolver.py +808 -0
- dataface/core/inspect/search.py +461 -0
- dataface/core/inspect/sources/__init__.py +32 -0
- dataface/core/inspect/sources/dbt.py +738 -0
- dataface/core/inspect/sources/duckdb_utils.py +66 -0
- dataface/core/inspect/templates/__init__.py +1 -0
- dataface/core/inspect/templates/categorical_column.yml +196 -0
- dataface/core/inspect/templates/charts.yml +109 -0
- dataface/core/inspect/templates/date_column.yml +248 -0
- dataface/core/inspect/templates/model.yml +138 -0
- dataface/core/inspect/templates/numeric_column.yml +261 -0
- dataface/core/inspect/templates/quality.yml +80 -0
- dataface/core/inspect/templates/string_column.yml +263 -0
- dataface/core/project_roots.py +165 -0
- dataface/core/render/__init__.py +87 -0
- dataface/core/render/board_links.py +176 -0
- dataface/core/render/chart/__init__.py +27 -0
- dataface/core/render/chart/arc_attached_table.py +251 -0
- dataface/core/render/chart/artifacts.py +16 -0
- dataface/core/render/chart/callout.py +225 -0
- dataface/core/render/chart/decisions.py +358 -0
- dataface/core/render/chart/geo.py +700 -0
- dataface/core/render/chart/kpi.py +916 -0
- dataface/core/render/chart/labels.py +76 -0
- dataface/core/render/chart/pipeline.py +818 -0
- dataface/core/render/chart/presentation.py +36 -0
- dataface/core/render/chart/profile.py +3438 -0
- dataface/core/render/chart/render_single.py +347 -0
- dataface/core/render/chart/renderers.py +193 -0
- dataface/core/render/chart/rendering.py +565 -0
- dataface/core/render/chart/serialization.py +90 -0
- dataface/core/render/chart/spark.py +496 -0
- dataface/core/render/chart/spark_bar.py +370 -0
- dataface/core/render/chart/spec_builders.py +154 -0
- dataface/core/render/chart/standard_renderer.py +2645 -0
- dataface/core/render/chart/table.py +2957 -0
- dataface/core/render/chart/table_support.py +1452 -0
- dataface/core/render/chart/tick_values.py +66 -0
- dataface/core/render/chart/time_unit_detect.py +809 -0
- dataface/core/render/chart/title_overflow.py +157 -0
- dataface/core/render/chart/type_inference.py +122 -0
- dataface/core/render/chart/validation.py +99 -0
- dataface/core/render/chart/vega_lite.py +125 -0
- dataface/core/render/chart/vega_lite_types.py +268 -0
- dataface/core/render/chart/vl_field_maps.py +346 -0
- dataface/core/render/chart_interactivity.py +24 -0
- dataface/core/render/control_registry.py +287 -0
- dataface/core/render/converters/__init__.py +24 -0
- dataface/core/render/converters/chart.py +276 -0
- dataface/core/render/converters/html.py +98 -0
- dataface/core/render/converters/pdf.py +40 -0
- dataface/core/render/converters/png.py +41 -0
- dataface/core/render/errors.py +144 -0
- dataface/core/render/face_api.py +160 -0
- dataface/core/render/faces.py +1194 -0
- dataface/core/render/font_measurement.py +48 -0
- dataface/core/render/font_support.py +197 -0
- dataface/core/render/fonts/DFTSansTabular-Regular.ttf +0 -0
- dataface/core/render/fonts/DFTSansTabular-Regular.woff2 +0 -0
- dataface/core/render/fonts/DFTSerifOldstyleProportional-Regular.ttf +0 -0
- dataface/core/render/fonts/DFTSerifOldstyleTabular-Regular.ttf +0 -0
- dataface/core/render/fonts/InterVariable.ttf +0 -0
- dataface/core/render/fonts/InterVariable.woff2 +0 -0
- dataface/core/render/fonts/NOTO_COLOR_EMOJI_LICENSE.txt +93 -0
- dataface/core/render/fonts/NOTO_EMOJI_LICENSE.txt +93 -0
- dataface/core/render/fonts/NotoColorEmoji-Regular.ttf +0 -0
- dataface/core/render/fonts/NotoColorEmoji-Regular.woff2 +0 -0
- dataface/core/render/fonts/NotoEmoji-Regular.ttf +0 -0
- dataface/core/render/fonts/NotoEmoji-Regular.woff2 +0 -0
- dataface/core/render/fonts/SOURCE_CODE_PRO_LICENSE.txt +93 -0
- dataface/core/render/fonts/SOURCE_SERIF_4_LICENSE.txt +98 -0
- dataface/core/render/fonts/SourceCodePro-Regular.ttf +0 -0
- dataface/core/render/fonts/SourceSerif4-Regular.ttf +0 -0
- dataface/core/render/fonts/_emoji_font_face.css +43 -0
- dataface/core/render/fonts/source-serif-4-variable-latin.woff2 +0 -0
- dataface/core/render/format_utils.py +329 -0
- dataface/core/render/geo_defaults.yml +28 -0
- dataface/core/render/json_format.py +146 -0
- dataface/core/render/layout_sizing.py +865 -0
- dataface/core/render/layouts.py +541 -0
- dataface/core/render/markdown_defaults.yml +16 -0
- dataface/core/render/missing_vars_prompt.py +79 -0
- dataface/core/render/placeholder.py +389 -0
- dataface/core/render/render_result.py +14 -0
- dataface/core/render/renderer.py +467 -0
- dataface/core/render/script_embedding.py +16 -0
- dataface/core/render/svg_utils.py +212 -0
- dataface/core/render/template_loader.py +69 -0
- dataface/core/render/templates/controls/_styles.css +606 -0
- dataface/core/render/templates/controls/checkbox.html +16 -0
- dataface/core/render/templates/controls/date.html +16 -0
- dataface/core/render/templates/controls/number.html +19 -0
- dataface/core/render/templates/controls/readonly.html +9 -0
- dataface/core/render/templates/controls/select.html +21 -0
- dataface/core/render/templates/controls/slider.html +22 -0
- dataface/core/render/templates/controls/text.html +16 -0
- dataface/core/render/templates/scripts/chart_interactivity.js +191 -0
- dataface/core/render/templates/scripts/variables.js +976 -0
- dataface/core/render/templates/svg/grid_pattern.svg +3 -0
- dataface/core/render/templates/svg/styles.css +51 -0
- dataface/core/render/terminal.py +311 -0
- dataface/core/render/terminal_charts.py +563 -0
- dataface/core/render/terminal_defaults.yml +2 -0
- dataface/core/render/terminal_layouts.py +299 -0
- dataface/core/render/terminal_text.py +31 -0
- dataface/core/render/text/__init__.py +1 -0
- dataface/core/render/text/case.py +113 -0
- dataface/core/render/text_format.py +129 -0
- dataface/core/render/utils.py +106 -0
- dataface/core/render/variable_controls.py +946 -0
- dataface/core/render/variable_input_refinement.py +140 -0
- dataface/core/render/warnings/__init__.py +15 -0
- dataface/core/render/warnings/bar_color_1_to_1_with_x.py +80 -0
- dataface/core/render/warnings/base.py +44 -0
- dataface/core/render/warnings/fanout_risk.py +15 -0
- dataface/core/render/warnings/from_query_diagnostic.py +56 -0
- dataface/core/render/warnings/missing_join_predicate.py +13 -0
- dataface/core/render/warnings/query_parse_error.py +14 -0
- dataface/core/render/warnings/query_returned_zero_rows.py +42 -0
- dataface/core/render/warnings/reaggregation.py +14 -0
- dataface/core/render/warnings/registry.py +45 -0
- dataface/core/render/warnings/suppression.py +46 -0
- dataface/core/render/warnings/temporal_single_point.py +63 -0
- dataface/core/render/warnings/unreferenced_chart.py +15 -0
- dataface/core/render/warnings/y_encoding_mostly_null.py +76 -0
- dataface/core/render/yaml_format.py +167 -0
- dataface/core/resolve_face.py +195 -0
- dataface/core/schema/__init__.py +0 -0
- dataface/core/schema/guidance.py +151 -0
- dataface/core/scoped_paths.py +59 -0
- dataface/core/serve/__init__.py +14 -0
- dataface/core/serve/bootstrap.py +39 -0
- dataface/core/serve/embedded.py +57 -0
- dataface/core/serve/port.py +129 -0
- dataface/core/serve/server.py +938 -0
- dataface/core/serve/templates/__init__.py +0 -0
- dataface/core/serve/templates/directory.yml +6 -0
- dataface/core/serve/templates/error.html.j2 +217 -0
- dataface/core/utils.py +121 -0
- dataface/core/validate.py +64 -0
- dataface/integrations/__init__.py +0 -0
- dataface/integrations/highlighting.py +351 -0
- dataface/integrations/markdown.py +537 -0
- dataface/py.typed +0 -0
- dataface-0.1.2.dist-info/METADATA +375 -0
- dataface-0.1.2.dist-info/RECORD +455 -0
- dataface-0.1.2.dist-info/WHEEL +4 -0
- dataface-0.1.2.dist-info/entry_points.txt +2 -0
- dataface-0.1.2.dist-info/licenses/LICENSE +202 -0
- mdsvg/__init__.py +168 -0
- mdsvg/fonts.py +656 -0
- mdsvg/images.py +299 -0
- mdsvg/parser.py +629 -0
- mdsvg/playground.py +284 -0
- mdsvg/py.typed +2 -0
- mdsvg/renderer.py +1623 -0
- mdsvg/style.py +355 -0
- mdsvg/types.py +200 -0
- mdsvg/utils.py +86 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
"""Placeholder data generation for charts without queries.
|
|
2
|
+
|
|
3
|
+
Stage: RENDER
|
|
4
|
+
Purpose: Generate appropriate dummy/placeholder data for charts without queries.
|
|
5
|
+
|
|
6
|
+
This module provides:
|
|
7
|
+
- generate_placeholder_data(chart_type, chart): Generate dummy data for a chart type
|
|
8
|
+
- is_placeholder_needed(chart, data): Detect when placeholder should be used
|
|
9
|
+
- add_placeholder_overlay(svg, width, height): Add "add data" overlay to SVG
|
|
10
|
+
|
|
11
|
+
The placeholder feature helps users:
|
|
12
|
+
- Build datafaces iteratively (design first, connect data later)
|
|
13
|
+
- See what charts will look like before writing SQL
|
|
14
|
+
- Use the playground for learning/experimentation
|
|
15
|
+
|
|
16
|
+
Visual Treatment:
|
|
17
|
+
- Placeholder charts render with ~40% opacity (high transparency)
|
|
18
|
+
- "add data" text overlay centered on the chart
|
|
19
|
+
- Makes it obvious this is placeholder state, not real data
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import re
|
|
23
|
+
from typing import TYPE_CHECKING, Any
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from dataface.core.compile.models.chart.compiled import (
|
|
27
|
+
Chart,
|
|
28
|
+
)
|
|
29
|
+
from dataface.core.compile.models.primitives import FontStyle
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def generate_placeholder_data(
|
|
33
|
+
chart_type: str | None,
|
|
34
|
+
chart: "Chart | Any | None" = None,
|
|
35
|
+
) -> list[dict[str, Any]]:
|
|
36
|
+
"""Generate appropriate placeholder/dummy data for a chart type.
|
|
37
|
+
|
|
38
|
+
The data generated depends on the chart type:
|
|
39
|
+
- Bar/Column: Categorical + numeric data
|
|
40
|
+
- Line/Area: Time series-like data with month labels
|
|
41
|
+
- Scatter/Point: Two numeric columns (x, y)
|
|
42
|
+
- Pie: Categorical + numeric proportions
|
|
43
|
+
- Table: Multi-column sample data
|
|
44
|
+
- KPI: Single numeric value
|
|
45
|
+
- Histogram: Numeric values for binning
|
|
46
|
+
- Heatmap: X, Y, Value grid data
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
chart_type: The type of chart (bar, line, table, etc.)
|
|
50
|
+
chart: Optional Chart to extract field names from
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
List of dicts containing placeholder data appropriate for the chart type.
|
|
54
|
+
Data is consistent (not random) for predictable rendering.
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
# Extract field names from chart config if provided
|
|
58
|
+
x_field = "category"
|
|
59
|
+
y_field = "value"
|
|
60
|
+
if chart:
|
|
61
|
+
x_field = chart.x or "category"
|
|
62
|
+
y_raw = chart.y
|
|
63
|
+
if isinstance(y_raw, list):
|
|
64
|
+
y_field = y_raw[0] if y_raw else "value"
|
|
65
|
+
elif y_raw:
|
|
66
|
+
y_field = y_raw
|
|
67
|
+
else:
|
|
68
|
+
y_field = "value"
|
|
69
|
+
|
|
70
|
+
# Normalize chart type to lowercase, handling None, empty, and whitespace
|
|
71
|
+
chart_type = (
|
|
72
|
+
chart_type.strip().lower() if chart_type and chart_type.strip() else "bar"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Bar chart (default) - categorical + numeric
|
|
76
|
+
if chart_type in ("bar", "column"):
|
|
77
|
+
return _generate_bar_placeholder(x_field, y_field)
|
|
78
|
+
|
|
79
|
+
# Line and area charts - time series
|
|
80
|
+
if chart_type in ("line", "area"):
|
|
81
|
+
return _generate_line_placeholder(x_field, y_field)
|
|
82
|
+
|
|
83
|
+
# Scatter and circle charts - two numeric columns
|
|
84
|
+
# Use "x" and "y" as defaults for scatter if not specified
|
|
85
|
+
if chart_type in ("scatter", "circle"):
|
|
86
|
+
scatter_x = x_field if x_field != "category" else "x"
|
|
87
|
+
scatter_y = y_field if y_field != "value" else "y"
|
|
88
|
+
return _generate_scatter_placeholder(scatter_x, scatter_y)
|
|
89
|
+
|
|
90
|
+
# Pie charts - proportional data
|
|
91
|
+
if chart_type in ("pie", "arc"):
|
|
92
|
+
return _generate_pie_placeholder(x_field, y_field)
|
|
93
|
+
|
|
94
|
+
# Table - multi-column sample data
|
|
95
|
+
if chart_type == "table":
|
|
96
|
+
return _generate_table_placeholder()
|
|
97
|
+
|
|
98
|
+
# KPI - single value
|
|
99
|
+
if chart_type == "kpi":
|
|
100
|
+
return _generate_kpi_placeholder(y_field)
|
|
101
|
+
|
|
102
|
+
# Histogram - numeric values for binning
|
|
103
|
+
if chart_type == "histogram":
|
|
104
|
+
return _generate_histogram_placeholder()
|
|
105
|
+
|
|
106
|
+
# Boxplot - grouped numeric values
|
|
107
|
+
if chart_type == "boxplot":
|
|
108
|
+
return _generate_boxplot_placeholder(x_field, y_field)
|
|
109
|
+
|
|
110
|
+
# Heatmap/Rect - grid data
|
|
111
|
+
if chart_type in ("heatmap", "rect"):
|
|
112
|
+
return _generate_heatmap_placeholder()
|
|
113
|
+
|
|
114
|
+
# Spark bar - compact horizontal bars for profiler cards
|
|
115
|
+
if chart_type == "spark_bar":
|
|
116
|
+
return _generate_spark_bar_placeholder(x_field, y_field)
|
|
117
|
+
|
|
118
|
+
# Default fallback to bar chart data
|
|
119
|
+
return _generate_bar_placeholder(x_field, y_field)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _generate_bar_placeholder(x_field: str, y_field: str) -> list[dict[str, Any]]:
|
|
123
|
+
"""Generate placeholder data for bar charts."""
|
|
124
|
+
return [
|
|
125
|
+
{x_field: "Category A", y_field: 100},
|
|
126
|
+
{x_field: "Category B", y_field: 75},
|
|
127
|
+
{x_field: "Category C", y_field: 50},
|
|
128
|
+
{x_field: "Category D", y_field: 85},
|
|
129
|
+
{x_field: "Category E", y_field: 60},
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _generate_line_placeholder(x_field: str, y_field: str) -> list[dict[str, Any]]:
|
|
134
|
+
"""Generate placeholder data for line/area charts."""
|
|
135
|
+
# Use month names for time-like x axis
|
|
136
|
+
time_field = x_field if x_field != "category" else "month"
|
|
137
|
+
return [
|
|
138
|
+
{time_field: "Jan", y_field: 10},
|
|
139
|
+
{time_field: "Feb", y_field: 25},
|
|
140
|
+
{time_field: "Mar", y_field: 40},
|
|
141
|
+
{time_field: "Apr", y_field: 35},
|
|
142
|
+
{time_field: "May", y_field: 50},
|
|
143
|
+
{time_field: "Jun", y_field: 45},
|
|
144
|
+
{time_field: "Jul", y_field: 60},
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _generate_scatter_placeholder(
|
|
149
|
+
x_field: str = "x",
|
|
150
|
+
y_field: str = "y",
|
|
151
|
+
) -> list[dict[str, Any]]:
|
|
152
|
+
"""Generate placeholder data for scatter/point charts."""
|
|
153
|
+
# Generate a pattern of points
|
|
154
|
+
return [
|
|
155
|
+
{x_field: 10, y_field: 20},
|
|
156
|
+
{x_field: 25, y_field: 45},
|
|
157
|
+
{x_field: 35, y_field: 30},
|
|
158
|
+
{x_field: 50, y_field: 60},
|
|
159
|
+
{x_field: 65, y_field: 55},
|
|
160
|
+
{x_field: 75, y_field: 80},
|
|
161
|
+
{x_field: 90, y_field: 70},
|
|
162
|
+
{x_field: 40, y_field: 50},
|
|
163
|
+
{x_field: 55, y_field: 40},
|
|
164
|
+
{x_field: 80, y_field: 90},
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _generate_pie_placeholder(x_field: str, y_field: str) -> list[dict[str, Any]]:
|
|
169
|
+
"""Generate placeholder data for pie charts."""
|
|
170
|
+
cat_field = x_field if x_field != "category" else "category"
|
|
171
|
+
return [
|
|
172
|
+
{cat_field: "Segment A", y_field: 40},
|
|
173
|
+
{cat_field: "Segment B", y_field: 30},
|
|
174
|
+
{cat_field: "Segment C", y_field: 20},
|
|
175
|
+
{cat_field: "Segment D", y_field: 10},
|
|
176
|
+
]
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _generate_table_placeholder() -> list[dict[str, Any]]:
|
|
180
|
+
"""Generate placeholder data for tables."""
|
|
181
|
+
return [
|
|
182
|
+
{"name": "Sample Item 1", "value": 123, "status": "Active"},
|
|
183
|
+
{"name": "Sample Item 2", "value": 456, "status": "Pending"},
|
|
184
|
+
{"name": "Sample Item 3", "value": 789, "status": "Active"},
|
|
185
|
+
{"name": "Sample Item 4", "value": 234, "status": "Inactive"},
|
|
186
|
+
{"name": "Sample Item 5", "value": 567, "status": "Active"},
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _generate_kpi_placeholder(value_field: str) -> list[dict[str, Any]]:
|
|
191
|
+
"""Generate placeholder data for KPI charts."""
|
|
192
|
+
return [{value_field: 1234}]
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _generate_histogram_placeholder() -> list[dict[str, Any]]:
|
|
196
|
+
"""Generate placeholder data for histograms."""
|
|
197
|
+
# Generate values that will bin nicely
|
|
198
|
+
|
|
199
|
+
values = []
|
|
200
|
+
# Create a distribution-like pattern
|
|
201
|
+
for i in range(50):
|
|
202
|
+
# Bell curve-ish distribution centered around 50
|
|
203
|
+
val = 50 + (i % 10 - 5) * 5 + (i // 10 - 2) * 3
|
|
204
|
+
values.append({"value": max(0, min(100, val))})
|
|
205
|
+
return values
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _generate_boxplot_placeholder(x_field: str, y_field: str) -> list[dict[str, Any]]:
|
|
209
|
+
"""Generate placeholder data for boxplots."""
|
|
210
|
+
cat_field = x_field if x_field != "category" else "category"
|
|
211
|
+
data = []
|
|
212
|
+
# Generate data for 3 categories with different distributions
|
|
213
|
+
for cat, base in [("Group A", 50), ("Group B", 70), ("Group C", 40)]:
|
|
214
|
+
for offset in [-20, -10, -5, 0, 5, 10, 20, 25, -15, 15]:
|
|
215
|
+
data.append({cat_field: cat, y_field: base + offset})
|
|
216
|
+
return data
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _generate_heatmap_placeholder() -> list[dict[str, Any]]:
|
|
220
|
+
"""Generate placeholder data for heatmaps."""
|
|
221
|
+
data = []
|
|
222
|
+
rows = ["Row A", "Row B", "Row C", "Row D"]
|
|
223
|
+
cols = ["Col 1", "Col 2", "Col 3", "Col 4"]
|
|
224
|
+
# Generate a pattern of values
|
|
225
|
+
values = [
|
|
226
|
+
[80, 60, 40, 20],
|
|
227
|
+
[70, 90, 50, 30],
|
|
228
|
+
[40, 50, 80, 60],
|
|
229
|
+
[30, 40, 60, 90],
|
|
230
|
+
]
|
|
231
|
+
for i, row in enumerate(rows):
|
|
232
|
+
for j, col in enumerate(cols):
|
|
233
|
+
data.append({"y": row, "x": col, "value": values[i][j]})
|
|
234
|
+
return data
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _generate_spark_bar_placeholder(x_field: str, y_field: str) -> list[dict[str, Any]]:
|
|
238
|
+
"""Generate placeholder data for spark bar charts."""
|
|
239
|
+
# Use appropriate field names - y is category, x is frequency
|
|
240
|
+
cat_field = y_field if y_field != "value" else "value"
|
|
241
|
+
freq_field = x_field if x_field != "category" else "frequency"
|
|
242
|
+
return [
|
|
243
|
+
{cat_field: "Category A", freq_field: 100},
|
|
244
|
+
{cat_field: "Category B", freq_field: 75},
|
|
245
|
+
{cat_field: "Category C", freq_field: 50},
|
|
246
|
+
{cat_field: "Category D", freq_field: 35},
|
|
247
|
+
{cat_field: "Category E", freq_field: 20},
|
|
248
|
+
]
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def is_placeholder_needed(
|
|
252
|
+
chart: "Chart",
|
|
253
|
+
data: list[dict[str, Any]] | None = None,
|
|
254
|
+
) -> bool:
|
|
255
|
+
"""Determine if a chart needs placeholder data.
|
|
256
|
+
|
|
257
|
+
A chart needs placeholder data when:
|
|
258
|
+
- It has no query defined (chart.query is None)
|
|
259
|
+
|
|
260
|
+
Note: If a chart HAS a query but returns empty results, we do NOT use
|
|
261
|
+
placeholder data - instead, the renderer should show "No data" message.
|
|
262
|
+
This distinguishes between:
|
|
263
|
+
- Design mode (no query yet) → show placeholder
|
|
264
|
+
- Query ran but found nothing → show "No data" message
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
chart: Chart to check
|
|
268
|
+
data: Query results (if already executed) - unused, kept for API compatibility
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
True if placeholder should be used (no query defined), False otherwise
|
|
272
|
+
|
|
273
|
+
"""
|
|
274
|
+
# Only use placeholder when chart has no query defined
|
|
275
|
+
# If a query exists but returns empty results, that's a "no data" case, not placeholder
|
|
276
|
+
if chart.type == "callout":
|
|
277
|
+
return False
|
|
278
|
+
return chart.query is None
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def add_placeholder_overlay(
|
|
282
|
+
svg: str,
|
|
283
|
+
width: float,
|
|
284
|
+
height: float,
|
|
285
|
+
font: "FontStyle",
|
|
286
|
+
text: str | None = None,
|
|
287
|
+
) -> str:
|
|
288
|
+
"""Add placeholder overlay to an SVG chart.
|
|
289
|
+
|
|
290
|
+
Adds:
|
|
291
|
+
1. A semi-transparent white overlay rectangle
|
|
292
|
+
2. "add data" text centered on the chart
|
|
293
|
+
|
|
294
|
+
The overlay makes it clear the chart is showing placeholder data.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
svg: The SVG string to add overlay to
|
|
298
|
+
width: Chart width in pixels
|
|
299
|
+
height: Chart height in pixels
|
|
300
|
+
font: FontStyle for the overlay text (reads .family)
|
|
301
|
+
text: Text to display (default: "add data")
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
SVG string with overlay added
|
|
305
|
+
|
|
306
|
+
"""
|
|
307
|
+
import html as html_module
|
|
308
|
+
|
|
309
|
+
from dataface.core.compile.config import get_config
|
|
310
|
+
|
|
311
|
+
overlay = get_config().style.placeholder.overlay
|
|
312
|
+
font_family = html_module.escape(font.family or "")
|
|
313
|
+
display_text = text if text is not None else overlay.text
|
|
314
|
+
_overlay_case = font.case
|
|
315
|
+
if _overlay_case is not None and _overlay_case != "none":
|
|
316
|
+
from dataface.core.render.text.case import apply_case
|
|
317
|
+
|
|
318
|
+
display_text = apply_case(display_text, _overlay_case)
|
|
319
|
+
|
|
320
|
+
# Calculate center position
|
|
321
|
+
center_x = width / 2
|
|
322
|
+
center_y = height / 2
|
|
323
|
+
|
|
324
|
+
# Escape text for safety
|
|
325
|
+
escaped_text = html_module.escape(display_text)
|
|
326
|
+
|
|
327
|
+
# Create overlay elements
|
|
328
|
+
# Semi-transparent overlay rectangle
|
|
329
|
+
overlay_rect = (
|
|
330
|
+
f'<rect x="0" y="0" width="{width}" height="{height}" '
|
|
331
|
+
f'fill="{overlay.background}" pointer-events="none"/>'
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
# Text element centered on chart
|
|
335
|
+
overlay_text = (
|
|
336
|
+
f'<text x="{center_x}" y="{center_y}" '
|
|
337
|
+
f'text-anchor="middle" dominant-baseline="middle" '
|
|
338
|
+
f'font-family="{font_family}" '
|
|
339
|
+
f'font-size="{overlay.font.size}" font-weight="{overlay.font.weight}" fill="{overlay.font.color}" '
|
|
340
|
+
f'pointer-events="none">'
|
|
341
|
+
f"{escaped_text}"
|
|
342
|
+
f"</text>"
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
# Create overlay group
|
|
346
|
+
overlay_group = f'<g class="placeholder-overlay">{overlay_rect}{overlay_text}</g>'
|
|
347
|
+
|
|
348
|
+
# Insert overlay before closing </svg> tag
|
|
349
|
+
# Use rfind to only replace the LAST </svg> (handles nested SVGs correctly)
|
|
350
|
+
if svg.endswith("</svg>"):
|
|
351
|
+
svg = svg[:-6] + overlay_group + "</svg>"
|
|
352
|
+
elif "</svg>" in svg:
|
|
353
|
+
idx = svg.rfind("</svg>")
|
|
354
|
+
svg = svg[:idx] + overlay_group + svg[idx:]
|
|
355
|
+
else:
|
|
356
|
+
# If no closing tag found, append
|
|
357
|
+
svg = svg + overlay_group
|
|
358
|
+
|
|
359
|
+
return svg
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def apply_placeholder_opacity(svg: str, opacity: float | None = None) -> str:
|
|
363
|
+
"""Apply reduced opacity to SVG content for placeholder appearance.
|
|
364
|
+
|
|
365
|
+
Wraps the SVG content in a group with reduced opacity to make it
|
|
366
|
+
appear faded/disabled.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
svg: The SVG string to modify
|
|
370
|
+
opacity: Opacity value (0.0-1.0), defaults to config placeholder opacity
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
SVG string with opacity applied to content
|
|
374
|
+
|
|
375
|
+
"""
|
|
376
|
+
from dataface.core.compile.config import get_config
|
|
377
|
+
|
|
378
|
+
effective_opacity = (
|
|
379
|
+
opacity if opacity is not None else get_config().style.placeholder.opacity
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
# Extract SVG parts directly - typical for Vega-Lite output (flat structure)
|
|
383
|
+
match = re.search(r"(<svg[^>]*>)(.*)(</svg>)", svg, re.DOTALL)
|
|
384
|
+
if not match:
|
|
385
|
+
return svg
|
|
386
|
+
|
|
387
|
+
opening_tag, content, closing_tag = match.groups()
|
|
388
|
+
wrapped_content = f'<g opacity="{effective_opacity}">{content}</g>'
|
|
389
|
+
return f"{opening_tag}{wrapped_content}{closing_tag}"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""RenderResult — the return type of render()."""
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from dataface.core.errors import StructuredError
|
|
6
|
+
from dataface.core.render.warnings.base import RenderWarning
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RenderResult(BaseModel):
|
|
10
|
+
output: str | bytes | None = None
|
|
11
|
+
chart_errors: list[StructuredError] = []
|
|
12
|
+
face_error: StructuredError | None = None
|
|
13
|
+
render_warnings: list[RenderWarning] = []
|
|
14
|
+
suppressed_warnings: list[RenderWarning] = []
|