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,134 @@
|
|
|
1
|
+
# Unified theme: stark
|
|
2
|
+
# Structural root for the built-in theme cascade — every other built-in theme
|
|
3
|
+
# transitively extends this file (`editorial` extends `stark`; `cream` via
|
|
4
|
+
# `editorial`; `carbong100` via `dark`; `dark`/`light`/`bi`/`looker` directly).
|
|
5
|
+
# Stark itself is opt-in for users: "stripped-back / utilitarian / sans-only"
|
|
6
|
+
# — pick it when you want the pre-editorial bones without the refined
|
|
7
|
+
# hierarchy that the shipped `editorial` theme adds on top.
|
|
8
|
+
|
|
9
|
+
extends: _base
|
|
10
|
+
style:
|
|
11
|
+
# ── Colors ─────────────────────────────────────────────────────────────────
|
|
12
|
+
background: '#FFFFFF'
|
|
13
|
+
accent: '#3b82f6'
|
|
14
|
+
muted: '#e5e7eb'
|
|
15
|
+
|
|
16
|
+
font:
|
|
17
|
+
family: &font_sans '''Inter Variable'', Inter, system-ui, sans-serif'
|
|
18
|
+
color: &color_ink dft-grays.heading
|
|
19
|
+
|
|
20
|
+
border:
|
|
21
|
+
color: *color_ink
|
|
22
|
+
|
|
23
|
+
title:
|
|
24
|
+
font:
|
|
25
|
+
family: *font_sans
|
|
26
|
+
color: *color_ink
|
|
27
|
+
subtitle:
|
|
28
|
+
font:
|
|
29
|
+
family: *font_sans
|
|
30
|
+
color: *color_ink
|
|
31
|
+
|
|
32
|
+
charts:
|
|
33
|
+
axis:
|
|
34
|
+
domain:
|
|
35
|
+
color: *color_ink
|
|
36
|
+
ticks:
|
|
37
|
+
color: *color_ink
|
|
38
|
+
grid:
|
|
39
|
+
color: *color_ink
|
|
40
|
+
zero:
|
|
41
|
+
color: *color_ink
|
|
42
|
+
label:
|
|
43
|
+
font:
|
|
44
|
+
color: *color_ink
|
|
45
|
+
title:
|
|
46
|
+
font:
|
|
47
|
+
color: *color_ink
|
|
48
|
+
|
|
49
|
+
legend:
|
|
50
|
+
label:
|
|
51
|
+
font:
|
|
52
|
+
color: *color_ink
|
|
53
|
+
title:
|
|
54
|
+
font:
|
|
55
|
+
color: *color_ink
|
|
56
|
+
|
|
57
|
+
table:
|
|
58
|
+
border:
|
|
59
|
+
color: '#e0e0e0'
|
|
60
|
+
paginator:
|
|
61
|
+
color_active: dft-grays.ink
|
|
62
|
+
color_inactive: dft-grays.inactive
|
|
63
|
+
color_disabled: dft-grays.disabled
|
|
64
|
+
header:
|
|
65
|
+
font:
|
|
66
|
+
color: *color_ink
|
|
67
|
+
spark:
|
|
68
|
+
empty:
|
|
69
|
+
stroke:
|
|
70
|
+
color: '#d1d5db'
|
|
71
|
+
|
|
72
|
+
marks:
|
|
73
|
+
text:
|
|
74
|
+
font:
|
|
75
|
+
family: *font_sans
|
|
76
|
+
color: *color_ink
|
|
77
|
+
rule:
|
|
78
|
+
stroke:
|
|
79
|
+
color: *color_ink
|
|
80
|
+
tick:
|
|
81
|
+
stroke:
|
|
82
|
+
color: *color_ink
|
|
83
|
+
|
|
84
|
+
kpi:
|
|
85
|
+
font:
|
|
86
|
+
family: '''DFT Sans Tabular'', Inter, system-ui, sans-serif'
|
|
87
|
+
|
|
88
|
+
data_table:
|
|
89
|
+
font:
|
|
90
|
+
family: '''DFT Sans Tabular'', Inter, system-ui, sans-serif'
|
|
91
|
+
color: *color_ink
|
|
92
|
+
divider:
|
|
93
|
+
color: *color_ink
|
|
94
|
+
label:
|
|
95
|
+
font:
|
|
96
|
+
color: *color_ink
|
|
97
|
+
|
|
98
|
+
axis_quantitative:
|
|
99
|
+
label:
|
|
100
|
+
font:
|
|
101
|
+
family: '''DFT Sans Tabular'', Inter, system-ui, sans-serif'
|
|
102
|
+
|
|
103
|
+
pie:
|
|
104
|
+
total:
|
|
105
|
+
value:
|
|
106
|
+
font:
|
|
107
|
+
family: '''DFT Sans Tabular'', Inter, system-ui, sans-serif'
|
|
108
|
+
color: *color_ink
|
|
109
|
+
label:
|
|
110
|
+
font:
|
|
111
|
+
color: *color_ink
|
|
112
|
+
|
|
113
|
+
text:
|
|
114
|
+
font:
|
|
115
|
+
family: *font_sans
|
|
116
|
+
color: *color_ink
|
|
117
|
+
|
|
118
|
+
variables:
|
|
119
|
+
font:
|
|
120
|
+
color: *color_ink
|
|
121
|
+
border:
|
|
122
|
+
color: *color_ink
|
|
123
|
+
input:
|
|
124
|
+
border:
|
|
125
|
+
color: *color_ink
|
|
126
|
+
|
|
127
|
+
page:
|
|
128
|
+
background: '#FFFFFF'
|
|
129
|
+
|
|
130
|
+
placeholder:
|
|
131
|
+
overlay:
|
|
132
|
+
background: 'rgba(255, 255, 255, 0.5)'
|
|
133
|
+
font:
|
|
134
|
+
color: '#666666'
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Global error registry: codes, doc pointers, and did-you-mean hints.
|
|
2
|
+
|
|
3
|
+
Importing this package side-effect-registers every code module so a single
|
|
4
|
+
``from dataface.core.errors import REGISTRY`` is enough to look up any code
|
|
5
|
+
by string at runtime.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
# Side-effect imports — required for REGISTRY self-registration.
|
|
11
|
+
from dataface.core.errors.codes_compile import (
|
|
12
|
+
DF_COMPILE_EXTRA_FIELD,
|
|
13
|
+
DF_COMPILE_UNKNOWN_QUERY,
|
|
14
|
+
)
|
|
15
|
+
from dataface.core.errors.codes_execute import (
|
|
16
|
+
DF_EXECUTE_COLUMN_NOT_FOUND,
|
|
17
|
+
DF_EXECUTE_MUTATING_SQL,
|
|
18
|
+
DF_EXECUTE_NO_DEFAULT_SOURCE,
|
|
19
|
+
DF_EXECUTE_SCHEMA_NOT_FOUND,
|
|
20
|
+
DF_EXECUTE_SOURCE_NOT_FOUND,
|
|
21
|
+
DF_EXECUTE_SOURCE_NOT_FOUND_EMPTY,
|
|
22
|
+
DF_EXECUTE_TABLE_NOT_FOUND,
|
|
23
|
+
DF_EXECUTE_UNPARSEABLE_SQL,
|
|
24
|
+
)
|
|
25
|
+
from dataface.core.errors.codes_render import (
|
|
26
|
+
DF_RENDER_BAR_DUPLICATE_ROWS,
|
|
27
|
+
DF_RENDER_FORMAT_UNSUPPORTED,
|
|
28
|
+
DF_RENDER_INPUT_INVALID,
|
|
29
|
+
DF_RENDER_INTERNAL,
|
|
30
|
+
DF_RENDER_KPI_MULTIROW,
|
|
31
|
+
DF_RENDER_NO_LAYOUT,
|
|
32
|
+
DF_RENDER_UNKNOWN_CHART_TYPE,
|
|
33
|
+
)
|
|
34
|
+
from dataface.core.errors.codes_unknown import DF_UNKNOWN_INTERNAL
|
|
35
|
+
from dataface.core.errors.registry import REGISTRY, ErrorCode, build_doc_url
|
|
36
|
+
from dataface.core.errors.structured import (
|
|
37
|
+
NextCommand,
|
|
38
|
+
StructuredError,
|
|
39
|
+
build_structured,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"ErrorCode",
|
|
44
|
+
"REGISTRY",
|
|
45
|
+
"StructuredError",
|
|
46
|
+
"NextCommand",
|
|
47
|
+
"build_structured",
|
|
48
|
+
"build_doc_url",
|
|
49
|
+
"DF_UNKNOWN_INTERNAL",
|
|
50
|
+
"DF_COMPILE_EXTRA_FIELD",
|
|
51
|
+
"DF_COMPILE_UNKNOWN_QUERY",
|
|
52
|
+
"DF_EXECUTE_COLUMN_NOT_FOUND",
|
|
53
|
+
"DF_EXECUTE_MUTATING_SQL",
|
|
54
|
+
"DF_EXECUTE_NO_DEFAULT_SOURCE",
|
|
55
|
+
"DF_EXECUTE_SCHEMA_NOT_FOUND",
|
|
56
|
+
"DF_EXECUTE_SOURCE_NOT_FOUND",
|
|
57
|
+
"DF_EXECUTE_SOURCE_NOT_FOUND_EMPTY",
|
|
58
|
+
"DF_EXECUTE_TABLE_NOT_FOUND",
|
|
59
|
+
"DF_EXECUTE_UNPARSEABLE_SQL",
|
|
60
|
+
"DF_RENDER_BAR_DUPLICATE_ROWS",
|
|
61
|
+
"DF_RENDER_FORMAT_UNSUPPORTED",
|
|
62
|
+
"DF_RENDER_INPUT_INVALID",
|
|
63
|
+
"DF_RENDER_INTERNAL",
|
|
64
|
+
"DF_RENDER_KPI_MULTIROW",
|
|
65
|
+
"DF_RENDER_NO_LAYOUT",
|
|
66
|
+
"DF_RENDER_UNKNOWN_CHART_TYPE",
|
|
67
|
+
]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""DF-COMPILE-* error codes.
|
|
2
|
+
|
|
3
|
+
Covers compile-domain raise sites migrated off DF-UNKNOWN-INTERNAL:
|
|
4
|
+
- DF-COMPILE-UNKNOWN-QUERY: chart references a query name that does not exist
|
|
5
|
+
- DF-COMPILE-EXTRA-FIELD: YAML contains a field not recognised by the schema
|
|
6
|
+
- DF-COMPILE-SQL-LITERAL-NEWLINES: SQL contains literal \\n from single-quoted YAML
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from dataface.core.errors.registry import REGISTRY, ErrorCode, build_doc_url
|
|
12
|
+
|
|
13
|
+
DF_COMPILE_UNKNOWN_QUERY = REGISTRY.register(
|
|
14
|
+
ErrorCode(
|
|
15
|
+
code="DF-COMPILE-UNKNOWN-QUERY",
|
|
16
|
+
domain="compile",
|
|
17
|
+
message_template=(
|
|
18
|
+
"Chart {chart_name!r} references unknown query {query_name!r}. "
|
|
19
|
+
"Declare the query under `queries:` or fix the typo in `query:`."
|
|
20
|
+
),
|
|
21
|
+
doc_url=build_doc_url("DF-COMPILE-UNKNOWN-QUERY"),
|
|
22
|
+
docs_topic="compile.errors",
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
DF_COMPILE_EXTRA_FIELD = REGISTRY.register(
|
|
27
|
+
ErrorCode(
|
|
28
|
+
code="DF-COMPILE-EXTRA-FIELD",
|
|
29
|
+
domain="compile",
|
|
30
|
+
message_template=(
|
|
31
|
+
"Unknown field {field_path!r} in face YAML. "
|
|
32
|
+
"Remove it or check the schema for supported keys."
|
|
33
|
+
),
|
|
34
|
+
doc_url=build_doc_url("DF-COMPILE-EXTRA-FIELD"),
|
|
35
|
+
docs_topic="compile.errors",
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
DF_COMPILE_SQL_LITERAL_NEWLINES = REGISTRY.register(
|
|
40
|
+
ErrorCode(
|
|
41
|
+
code="DF-COMPILE-SQL-LITERAL-NEWLINES",
|
|
42
|
+
domain="compile",
|
|
43
|
+
message_template=(
|
|
44
|
+
"Query {query_name!r} {field_label} contains literal \\n (backslash + n). "
|
|
45
|
+
"Use YAML block scalar `{field_label}: |` to write multiline SQL:\n\n"
|
|
46
|
+
" queries:\n"
|
|
47
|
+
" my_query:\n"
|
|
48
|
+
" {field_label}: |\n"
|
|
49
|
+
" SELECT\n"
|
|
50
|
+
" col\n"
|
|
51
|
+
" FROM t"
|
|
52
|
+
),
|
|
53
|
+
doc_url=build_doc_url("DF-COMPILE-SQL-LITERAL-NEWLINES"),
|
|
54
|
+
docs_topic="compile.errors",
|
|
55
|
+
)
|
|
56
|
+
)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""DF-EXECUTE-* error codes for the execute layer.
|
|
2
|
+
|
|
3
|
+
Covers source-resolution failures in AdapterRegistry — the most common
|
|
4
|
+
class of error agents hit when misconfiguring sources in dataface.yml.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataface.core.errors.hints import (
|
|
10
|
+
suggest_close_column,
|
|
11
|
+
suggest_close_schema,
|
|
12
|
+
suggest_close_source,
|
|
13
|
+
suggest_close_table,
|
|
14
|
+
)
|
|
15
|
+
from dataface.core.errors.registry import REGISTRY, ErrorCode, build_doc_url
|
|
16
|
+
|
|
17
|
+
DF_EXECUTE_SOURCE_NOT_FOUND = REGISTRY.register(
|
|
18
|
+
ErrorCode(
|
|
19
|
+
code="DF-EXECUTE-SOURCE-NOT-FOUND",
|
|
20
|
+
domain="execute",
|
|
21
|
+
message_template=(
|
|
22
|
+
"Source {source!r} not found in configured adapters. "
|
|
23
|
+
"Available sources: {available}. "
|
|
24
|
+
"dft sources are declared under `sources:` in your dataface.yml — "
|
|
25
|
+
"the source name is not the dbt project name."
|
|
26
|
+
),
|
|
27
|
+
doc_url=build_doc_url("DF-EXECUTE-SOURCE-NOT-FOUND"),
|
|
28
|
+
docs_topic="configuration.sources",
|
|
29
|
+
hint_generator=suggest_close_source,
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
DF_EXECUTE_SOURCE_NOT_FOUND_EMPTY = REGISTRY.register(
|
|
34
|
+
ErrorCode(
|
|
35
|
+
code="DF-EXECUTE-SOURCE-NOT-FOUND-EMPTY",
|
|
36
|
+
domain="execute",
|
|
37
|
+
message_template=(
|
|
38
|
+
"Source {source!r} not found. No source profiles are configured. "
|
|
39
|
+
"Declare sources under `sources:` in your dataface.yml."
|
|
40
|
+
),
|
|
41
|
+
doc_url=build_doc_url("DF-EXECUTE-SOURCE-NOT-FOUND"),
|
|
42
|
+
docs_topic="configuration.sources",
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
DF_EXECUTE_NO_DEFAULT_SOURCE = REGISTRY.register(
|
|
47
|
+
ErrorCode(
|
|
48
|
+
code="DF-EXECUTE-NO-DEFAULT-SOURCE",
|
|
49
|
+
domain="execute",
|
|
50
|
+
message_template=(
|
|
51
|
+
"Source name required: no default DuckDB adapter is configured. "
|
|
52
|
+
"Pass an explicit source name from the `sources:` block in your dataface.yml."
|
|
53
|
+
),
|
|
54
|
+
doc_url=build_doc_url("DF-EXECUTE-NO-DEFAULT-SOURCE"),
|
|
55
|
+
docs_topic="configuration.sources",
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
DF_EXECUTE_SOURCE_INLINE_FORBIDDEN = REGISTRY.register(
|
|
60
|
+
ErrorCode(
|
|
61
|
+
code="DF-EXECUTE-SOURCE-INLINE-FORBIDDEN",
|
|
62
|
+
domain="execute",
|
|
63
|
+
message_template=(
|
|
64
|
+
"Inline source definition at {yaml_path!r} is not allowed — "
|
|
65
|
+
"use a named source from the project allowlist. "
|
|
66
|
+
"Inline connection parameters: {offending_value!r}."
|
|
67
|
+
),
|
|
68
|
+
doc_url=build_doc_url("DF-EXECUTE-SOURCE-INLINE-FORBIDDEN"),
|
|
69
|
+
docs_topic="configuration.sources",
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
DF_EXECUTE_SOURCE_CROSS_FILE_FORBIDDEN = REGISTRY.register(
|
|
74
|
+
ErrorCode(
|
|
75
|
+
code="DF-EXECUTE-SOURCE-CROSS-FILE-FORBIDDEN",
|
|
76
|
+
domain="execute",
|
|
77
|
+
message_template=(
|
|
78
|
+
"Cross-file source reference at {yaml_path!r} "
|
|
79
|
+
"(`#` anchor form) is not allowed: {offending_value!r}."
|
|
80
|
+
),
|
|
81
|
+
doc_url=build_doc_url("DF-EXECUTE-SOURCE-CROSS-FILE-FORBIDDEN"),
|
|
82
|
+
docs_topic="configuration.sources",
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
DF_EXECUTE_SOURCE_INVALID_TYPE = REGISTRY.register(
|
|
87
|
+
ErrorCode(
|
|
88
|
+
code="DF-EXECUTE-SOURCE-INVALID-TYPE",
|
|
89
|
+
domain="execute",
|
|
90
|
+
message_template=(
|
|
91
|
+
"Unknown source type {offending_value!r}. Valid types: {available}."
|
|
92
|
+
),
|
|
93
|
+
doc_url=build_doc_url("DF-EXECUTE-SOURCE-INVALID-TYPE"),
|
|
94
|
+
docs_topic="configuration.sources",
|
|
95
|
+
hint_generator=suggest_close_source,
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
DF_EXECUTE_SOURCE_MISSING_TYPE = REGISTRY.register(
|
|
100
|
+
ErrorCode(
|
|
101
|
+
code="DF-EXECUTE-SOURCE-MISSING-TYPE",
|
|
102
|
+
domain="execute",
|
|
103
|
+
message_template=(
|
|
104
|
+
"Source is missing the required `type` field: {offending_value!r}."
|
|
105
|
+
),
|
|
106
|
+
doc_url=build_doc_url("DF-EXECUTE-SOURCE-MISSING-TYPE"),
|
|
107
|
+
docs_topic="configuration.sources",
|
|
108
|
+
)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
DF_EXECUTE_MUTATING_SQL = REGISTRY.register(
|
|
112
|
+
ErrorCode(
|
|
113
|
+
code="DF-EXECUTE-MUTATING-SQL",
|
|
114
|
+
domain="execute",
|
|
115
|
+
message_template=(
|
|
116
|
+
"dft refuses to execute non-read-only SQL. "
|
|
117
|
+
"Statement: {rejected_node_kind}. Preview: {fragment_preview}."
|
|
118
|
+
),
|
|
119
|
+
doc_url=build_doc_url("DF-EXECUTE-MUTATING-SQL"),
|
|
120
|
+
docs_topic="security.sql-guard",
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
DF_EXECUTE_UNPARSEABLE_SQL = REGISTRY.register(
|
|
125
|
+
ErrorCode(
|
|
126
|
+
code="DF-EXECUTE-UNPARSEABLE-SQL",
|
|
127
|
+
domain="execute",
|
|
128
|
+
message_template=(
|
|
129
|
+
"dft could not statically validate this SQL: {cause}. "
|
|
130
|
+
"The caller decides whether to defer to runtime or fail closed."
|
|
131
|
+
),
|
|
132
|
+
doc_url=build_doc_url("DF-EXECUTE-UNPARSEABLE-SQL"),
|
|
133
|
+
docs_topic="security.sql-guard",
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
DF_EXECUTE_SCHEMA_NOT_FOUND = REGISTRY.register(
|
|
138
|
+
ErrorCode(
|
|
139
|
+
code="DF-EXECUTE-SCHEMA-NOT-FOUND",
|
|
140
|
+
domain="execute",
|
|
141
|
+
message_template=(
|
|
142
|
+
"Schema {schema!r} not found in source {source!r}. "
|
|
143
|
+
"Available schemas: {available}."
|
|
144
|
+
),
|
|
145
|
+
doc_url=build_doc_url("DF-EXECUTE-SCHEMA-NOT-FOUND"),
|
|
146
|
+
docs_topic="configuration.sources",
|
|
147
|
+
hint_generator=suggest_close_schema,
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
DF_EXECUTE_TABLE_NOT_FOUND = REGISTRY.register(
|
|
152
|
+
ErrorCode(
|
|
153
|
+
code="DF-EXECUTE-TABLE-NOT-FOUND",
|
|
154
|
+
domain="execute",
|
|
155
|
+
message_template=(
|
|
156
|
+
"Table {table!r} not found in schema {schema!r} "
|
|
157
|
+
"(source {source!r}). Available tables: {available}."
|
|
158
|
+
),
|
|
159
|
+
doc_url=build_doc_url("DF-EXECUTE-TABLE-NOT-FOUND"),
|
|
160
|
+
docs_topic="configuration.sources",
|
|
161
|
+
hint_generator=suggest_close_table,
|
|
162
|
+
)
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
DF_EXECUTE_COLUMN_NOT_FOUND = REGISTRY.register(
|
|
166
|
+
ErrorCode(
|
|
167
|
+
code="DF-EXECUTE-COLUMN-NOT-FOUND",
|
|
168
|
+
domain="execute",
|
|
169
|
+
message_template=(
|
|
170
|
+
"Column {col_name!r} not found in table {schema!r}.{table!r} "
|
|
171
|
+
"(source {source!r}). Available columns: {available}."
|
|
172
|
+
),
|
|
173
|
+
doc_url=build_doc_url("DF-EXECUTE-COLUMN-NOT-FOUND"),
|
|
174
|
+
docs_topic="configuration.sources",
|
|
175
|
+
hint_generator=suggest_close_column,
|
|
176
|
+
)
|
|
177
|
+
)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""DF-RENDER-* error codes (wave 1 + bar duplicate rows).
|
|
2
|
+
|
|
3
|
+
The render-domain raise sites migrated in this PR cover the registry-shape-
|
|
4
|
+
proving subset:
|
|
5
|
+
- DF-RENDER-NO-LAYOUT, DF-RENDER-INTERNAL, DF-RENDER-FORMAT-UNSUPPORTED
|
|
6
|
+
(renderer.py)
|
|
7
|
+
- DF-RENDER-UNKNOWN-CHART-TYPE (profile.py x2, standard_renderer.py)
|
|
8
|
+
- DF-RENDER-KPI-MULTIROW (kpi.py)
|
|
9
|
+
- DF-RENDER-BAR-DUPLICATE-ROWS (validation.py)
|
|
10
|
+
|
|
11
|
+
Column-missing and type-mismatch codes are deferred to the consumer task
|
|
12
|
+
(unify-render-error-feedback), which already needs to touch every channel-
|
|
13
|
+
validation raise site to thread structured fields (chart_id, available
|
|
14
|
+
columns, field path) through. The consumer task adds those codes alongside
|
|
15
|
+
its raise-site migration so codes don't ship registered-but-unraised here.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from dataface.core.errors.hints import suggest_close_chart_type
|
|
21
|
+
from dataface.core.errors.registry import REGISTRY, ErrorCode, build_doc_url
|
|
22
|
+
|
|
23
|
+
DF_RENDER_KPI_MULTIROW = REGISTRY.register(
|
|
24
|
+
ErrorCode(
|
|
25
|
+
code="DF-RENDER-KPI-MULTIROW",
|
|
26
|
+
domain="render",
|
|
27
|
+
message_template=(
|
|
28
|
+
"KPI chart {chart_id!r} expects exactly 1 row, got {row_count}. "
|
|
29
|
+
"Use a query that returns a single row (e.g. SELECT SUM(...) or LIMIT 1)."
|
|
30
|
+
),
|
|
31
|
+
doc_url=build_doc_url("DF-RENDER-KPI-MULTIROW"),
|
|
32
|
+
docs_topic="charts.kpi",
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
DF_RENDER_BAR_DUPLICATE_ROWS = REGISTRY.register(
|
|
37
|
+
ErrorCode(
|
|
38
|
+
code="DF-RENDER-BAR-DUPLICATE-ROWS",
|
|
39
|
+
domain="render",
|
|
40
|
+
message_template=(
|
|
41
|
+
"{chart_type} chart {chart_id!r} requires pre-aggregated data "
|
|
42
|
+
"with at most one row per plotted key ({field_list}). "
|
|
43
|
+
"Found duplicate rows for {duplicate_preview}. "
|
|
44
|
+
"Aggregate in the query before rendering."
|
|
45
|
+
),
|
|
46
|
+
doc_url=build_doc_url("DF-RENDER-BAR-DUPLICATE-ROWS"),
|
|
47
|
+
docs_topic="charts.bar",
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
DF_RENDER_UNKNOWN_CHART_TYPE = REGISTRY.register(
|
|
52
|
+
ErrorCode(
|
|
53
|
+
code="DF-RENDER-UNKNOWN-CHART-TYPE",
|
|
54
|
+
domain="render",
|
|
55
|
+
message_template="Unknown chart type: {chart_type!r}",
|
|
56
|
+
doc_url=build_doc_url("DF-RENDER-UNKNOWN-CHART-TYPE"),
|
|
57
|
+
docs_topic="charts.types",
|
|
58
|
+
hint_generator=suggest_close_chart_type,
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
DF_RENDER_FORMAT_UNSUPPORTED = REGISTRY.register(
|
|
63
|
+
ErrorCode(
|
|
64
|
+
code="DF-RENDER-FORMAT-UNSUPPORTED",
|
|
65
|
+
domain="render",
|
|
66
|
+
message_template="Unknown format: {format!r}",
|
|
67
|
+
doc_url=build_doc_url("DF-RENDER-FORMAT-UNSUPPORTED"),
|
|
68
|
+
docs_topic="render.formats",
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
DF_RENDER_NO_LAYOUT = REGISTRY.register(
|
|
73
|
+
ErrorCode(
|
|
74
|
+
code="DF-RENDER-NO-LAYOUT",
|
|
75
|
+
domain="render",
|
|
76
|
+
message_template=(
|
|
77
|
+
"Face defines charts ({charts}) but no layout — would render with no visible "
|
|
78
|
+
"charts. Add a `rows:`/`cols:`/`grid:`/`tabs:` block that references them."
|
|
79
|
+
),
|
|
80
|
+
doc_url=build_doc_url("DF-RENDER-NO-LAYOUT"),
|
|
81
|
+
docs_topic="faces.layout",
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
DF_RENDER_INTERNAL = REGISTRY.register(
|
|
86
|
+
ErrorCode(
|
|
87
|
+
code="DF-RENDER-INTERNAL",
|
|
88
|
+
domain="render",
|
|
89
|
+
# Field is named `inner_message` rather than `cause` so it doesn't
|
|
90
|
+
# shadow StructuredError.cause (which is computed independently
|
|
91
|
+
# from __cause__).
|
|
92
|
+
message_template="Failed to render dataface: {inner_message}",
|
|
93
|
+
doc_url=build_doc_url("DF-RENDER-INTERNAL"),
|
|
94
|
+
docs_topic="render.errors",
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
DF_RENDER_INPUT_INVALID = REGISTRY.register(
|
|
99
|
+
ErrorCode(
|
|
100
|
+
code="DF-RENDER-INPUT-INVALID",
|
|
101
|
+
domain="render",
|
|
102
|
+
message_template="{message}",
|
|
103
|
+
doc_url=build_doc_url("DF-RENDER-INPUT-INVALID"),
|
|
104
|
+
docs_topic="render.errors",
|
|
105
|
+
)
|
|
106
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""DF-UNKNOWN-* fallback code for legacy string-message constructors."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataface.core.errors.registry import REGISTRY, ErrorCode, build_doc_url
|
|
6
|
+
|
|
7
|
+
DF_UNKNOWN_INTERNAL = REGISTRY.register(
|
|
8
|
+
ErrorCode(
|
|
9
|
+
code="DF-UNKNOWN-INTERNAL",
|
|
10
|
+
domain="unknown",
|
|
11
|
+
message_template="{message}",
|
|
12
|
+
doc_url=build_doc_url("DF-UNKNOWN-INTERNAL"),
|
|
13
|
+
docs_topic="errors.unknown",
|
|
14
|
+
)
|
|
15
|
+
)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Hint generators for error codes using difflib close-match suggestions.
|
|
2
|
+
|
|
3
|
+
Hint generators are kept generic over a comma-separated `available` string so
|
|
4
|
+
the registry stays a leaf module. The raise site is responsible for passing
|
|
5
|
+
the canonical list (e.g. CHART_TYPE_MAP keys for chart-type hints).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import difflib
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _suggest_close_match(value: str, available: str, cutoff: float) -> str | None:
|
|
14
|
+
candidates = [c.strip() for c in available.split(",") if c.strip()]
|
|
15
|
+
if not candidates:
|
|
16
|
+
return None
|
|
17
|
+
matches = difflib.get_close_matches(value, candidates, n=1, cutoff=cutoff)
|
|
18
|
+
if matches:
|
|
19
|
+
return f"Did you mean {matches[0]!r}?"
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def suggest_close_chart_type(
|
|
24
|
+
chart_type: str,
|
|
25
|
+
available: str = "",
|
|
26
|
+
**_kwargs: object,
|
|
27
|
+
) -> str | None:
|
|
28
|
+
"""Return a 'Did you mean X?' hint for unknown chart types.
|
|
29
|
+
|
|
30
|
+
`available` is a comma-separated list passed by the raise site (typically
|
|
31
|
+
CHART_TYPE_MAP keys); the registry stays decoupled from the chart module.
|
|
32
|
+
Defaults to "" so a raise site that forgets `available=` still produces a
|
|
33
|
+
typed-and-coded error rather than crashing the hint pathway.
|
|
34
|
+
"""
|
|
35
|
+
return _suggest_close_match(chart_type, available, cutoff=0.5)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def suggest_close_source(
|
|
39
|
+
source: str,
|
|
40
|
+
available: str = "",
|
|
41
|
+
**_kwargs: object,
|
|
42
|
+
) -> str | None:
|
|
43
|
+
"""Return a 'Did you mean X?' hint for unknown source names.
|
|
44
|
+
|
|
45
|
+
`available` is a comma-separated list of configured source names.
|
|
46
|
+
"""
|
|
47
|
+
return _suggest_close_match(source, available, cutoff=0.5)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def suggest_close_schema(
|
|
51
|
+
schema: str,
|
|
52
|
+
available: str = "",
|
|
53
|
+
**_kwargs: object,
|
|
54
|
+
) -> str | None:
|
|
55
|
+
"""Return a 'Did you mean X?' hint for an unknown schema name."""
|
|
56
|
+
return _suggest_close_match(schema, available, cutoff=0.5)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def suggest_close_table(
|
|
60
|
+
table: str,
|
|
61
|
+
available: str = "",
|
|
62
|
+
**_kwargs: object,
|
|
63
|
+
) -> str | None:
|
|
64
|
+
"""Return a 'Did you mean X?' hint for an unknown table name."""
|
|
65
|
+
return _suggest_close_match(table, available, cutoff=0.5)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def suggest_close_column(
|
|
69
|
+
col_name: str,
|
|
70
|
+
available: str = "",
|
|
71
|
+
**_kwargs: object,
|
|
72
|
+
) -> str | None:
|
|
73
|
+
"""Return a 'Did you mean X?' hint for an unknown column name."""
|
|
74
|
+
return _suggest_close_match(col_name, available, cutoff=0.5)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Global error registry: ErrorCode definitions and lookup."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ErrorCode(BaseModel):
|
|
11
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
12
|
+
|
|
13
|
+
code: str
|
|
14
|
+
domain: str
|
|
15
|
+
message_template: str
|
|
16
|
+
doc_url: str
|
|
17
|
+
docs_topic: str | None = None
|
|
18
|
+
hint_generator: Callable[..., str | None] | None = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class _Registry:
|
|
22
|
+
def __init__(self) -> None:
|
|
23
|
+
self._by_code: dict[str, ErrorCode] = {}
|
|
24
|
+
|
|
25
|
+
def register(self, ec: ErrorCode) -> ErrorCode:
|
|
26
|
+
if ec.code in self._by_code:
|
|
27
|
+
raise ValueError(f"ErrorCode {ec.code!r} already registered")
|
|
28
|
+
self._by_code[ec.code] = ec
|
|
29
|
+
return ec
|
|
30
|
+
|
|
31
|
+
def get(self, code: str) -> ErrorCode:
|
|
32
|
+
return self._by_code[code]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
REGISTRY = _Registry()
|
|
36
|
+
|
|
37
|
+
DOC_BASE_URL = "https://docs.dataface.dev/errors"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def build_doc_url(code: str) -> str:
|
|
41
|
+
"""Build the canonical doc URL for an error code."""
|
|
42
|
+
return f"{DOC_BASE_URL}/{code}"
|