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,110 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dataface file detection utilities.
|
|
3
|
+
|
|
4
|
+
Determines whether a file is a Dataface YAML (or markdown report) by path
|
|
5
|
+
conventions or content analysis.
|
|
6
|
+
|
|
7
|
+
IMPORTANT: This detection logic is duplicated in the VS Code extension for performance.
|
|
8
|
+
If you update the detection rules here, also update:
|
|
9
|
+
- apps/ide/vscode-extension/src/detection.ts (pathSegmentsIncludeFaces, hasDatafaceKeys)
|
|
10
|
+
- apps/ide/vscode-extension/src/extension.ts (autoDetectDatafaceFile, isDatafaceFile)
|
|
11
|
+
|
|
12
|
+
Detection methods (in order of precedence):
|
|
13
|
+
1. File extension: *.dataface.yml, *.dataface.yaml
|
|
14
|
+
2. Directory convention: faces/*.yml, faces/*.yaml, faces/*.md
|
|
15
|
+
3. Content detection: YAML with (queries: OR charts:) AND (rows: OR cols: OR grid: OR tabs:)
|
|
16
|
+
4. Markdown reports: .md files with Dataface YAML frontmatter
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import re
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def is_dataface_file(path: Path | str) -> bool:
|
|
24
|
+
"""
|
|
25
|
+
Check if a file is a Dataface YAML or markdown report by path or content.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
path: Path to the file to check
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
True if the file is detected as a Dataface file
|
|
32
|
+
"""
|
|
33
|
+
path = Path(path)
|
|
34
|
+
|
|
35
|
+
# Markdown report files
|
|
36
|
+
if path.suffix.lower() == ".md":
|
|
37
|
+
from dataface.core.compile.markdown import is_markdown_face
|
|
38
|
+
|
|
39
|
+
return is_markdown_face(path)
|
|
40
|
+
|
|
41
|
+
# Must be a YAML file
|
|
42
|
+
if path.suffix.lower() not in (".yml", ".yaml"):
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
# Check file extension pattern: *.dataface.yml
|
|
46
|
+
if path.name.endswith(".dataface.yml") or path.name.endswith(".dataface.yaml"):
|
|
47
|
+
return True
|
|
48
|
+
|
|
49
|
+
# Check exact filename: dataface.yml
|
|
50
|
+
if path.name.lower() in ("dataface.yml", "dataface.yaml"):
|
|
51
|
+
return True
|
|
52
|
+
|
|
53
|
+
# Check directory convention: faces/*.yml
|
|
54
|
+
if "faces" in path.parts:
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
# Content detection: check for Dataface-specific keys
|
|
58
|
+
if path.exists():
|
|
59
|
+
try:
|
|
60
|
+
content = path.read_text(encoding="utf-8")
|
|
61
|
+
return has_dataface_keys(content)
|
|
62
|
+
except (OSError, UnicodeDecodeError):
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def has_dataface_keys(content: str) -> bool:
|
|
69
|
+
"""
|
|
70
|
+
Check if YAML content contains Dataface-specific key patterns.
|
|
71
|
+
|
|
72
|
+
A file is considered Dataface if it has:
|
|
73
|
+
- (queries: OR charts:) AND (rows: OR cols: OR grid: OR tabs:)
|
|
74
|
+
|
|
75
|
+
This combination is distinctive enough to avoid false positives with
|
|
76
|
+
other YAML formats (dbt, Kubernetes, Docker Compose, etc.)
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
content: YAML file content as string
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
True if content appears to be a Dataface file
|
|
83
|
+
"""
|
|
84
|
+
# Check for data definition keys
|
|
85
|
+
has_queries = bool(re.search(r"^queries:", content, re.MULTILINE))
|
|
86
|
+
has_charts = bool(re.search(r"^charts:", content, re.MULTILINE))
|
|
87
|
+
|
|
88
|
+
# Check for layout keys
|
|
89
|
+
has_layout = bool(re.search(r"^(rows|cols|grid|tabs):", content, re.MULTILINE))
|
|
90
|
+
|
|
91
|
+
return (has_queries or has_charts) and has_layout
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def find_dataface_files(directory: Path | str, recursive: bool = True) -> list[Path]:
|
|
95
|
+
"""
|
|
96
|
+
Find all Dataface files in a directory.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
directory: Directory to search
|
|
100
|
+
recursive: Whether to search subdirectories (default: True)
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
List of paths to Dataface files
|
|
104
|
+
"""
|
|
105
|
+
directory = Path(directory)
|
|
106
|
+
yaml_pattern = "**/*.y*ml" if recursive else "*.y*ml"
|
|
107
|
+
md_pattern = "**/*.md" if recursive else "*.md"
|
|
108
|
+
|
|
109
|
+
candidates = list(directory.glob(yaml_pattern)) + list(directory.glob(md_pattern))
|
|
110
|
+
return [p for p in candidates if is_dataface_file(p)]
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""Compilation error types.
|
|
2
|
+
|
|
3
|
+
Stage: COMPILE
|
|
4
|
+
Purpose: Define error types for all compilation failures.
|
|
5
|
+
|
|
6
|
+
These errors are raised during:
|
|
7
|
+
- YAML parsing (ParseError, YAMLError)
|
|
8
|
+
- Schema validation (ValidationError)
|
|
9
|
+
- Reference resolution (ReferenceError)
|
|
10
|
+
- Jinja template rendering (JinjaError)
|
|
11
|
+
|
|
12
|
+
All errors inherit from CompilationError for easy catching.
|
|
13
|
+
|
|
14
|
+
Enhanced error messages include:
|
|
15
|
+
- Line numbers where errors occur
|
|
16
|
+
- YAML context showing the problematic snippet
|
|
17
|
+
- Helpful suggestions ("Did you mean 'bar'?")
|
|
18
|
+
|
|
19
|
+
Refs #94
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import sys
|
|
25
|
+
from typing import TYPE_CHECKING, Any
|
|
26
|
+
|
|
27
|
+
if sys.version_info >= (3, 11):
|
|
28
|
+
from typing import Self
|
|
29
|
+
else:
|
|
30
|
+
from typing_extensions import Self
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from dataface.core.errors.registry import ErrorCode
|
|
34
|
+
from dataface.core.errors.structured import StructuredError
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class DatafaceError(Exception):
|
|
38
|
+
"""Base error for all Dataface errors."""
|
|
39
|
+
|
|
40
|
+
code: ErrorCode | None = None
|
|
41
|
+
fields: dict[str, Any]
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def from_code(cls, ec: ErrorCode, **fields: Any) -> Self:
|
|
45
|
+
"""Construct an instance carrying a registry ErrorCode + structured fields.
|
|
46
|
+
|
|
47
|
+
Bypasses the subclass __init__ (and its `_format_message` decoration);
|
|
48
|
+
the rendered message is exactly `ec.message_template.format(**fields)`.
|
|
49
|
+
Reserved field names (`code`, `message`, `fields`) are skipped so the
|
|
50
|
+
registry-set values can't be clobbered by a caller-supplied field.
|
|
51
|
+
"""
|
|
52
|
+
message = ec.message_template.format(**fields)
|
|
53
|
+
inst: Self = cls.__new__(cls)
|
|
54
|
+
Exception.__init__(inst, message)
|
|
55
|
+
inst.message = message # type: ignore[attr-defined]
|
|
56
|
+
inst.code = ec
|
|
57
|
+
inst.fields = dict(fields)
|
|
58
|
+
# Mirror fields onto typed subclass attributes so callers reading
|
|
59
|
+
# e.chart_id / e.chart_type / e.format / e.element get the same value
|
|
60
|
+
# whether the error was raised via legacy __init__ or from_code.
|
|
61
|
+
# Class-level None defaults on every subclass attr make setattr safe.
|
|
62
|
+
_reserved = {"code", "message", "fields"}
|
|
63
|
+
for key, value in fields.items():
|
|
64
|
+
if key in _reserved:
|
|
65
|
+
continue
|
|
66
|
+
setattr(inst, key, value)
|
|
67
|
+
return inst
|
|
68
|
+
|
|
69
|
+
def to_structured(self, *, file: str | None = None) -> StructuredError:
|
|
70
|
+
from dataface.core.errors.structured import build_structured
|
|
71
|
+
|
|
72
|
+
return build_structured(self, file=file)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class CompilationError(DatafaceError):
|
|
76
|
+
"""Base error for all compilation failures.
|
|
77
|
+
|
|
78
|
+
This is the parent class for all compilation-related errors.
|
|
79
|
+
Catch this to handle any compilation error.
|
|
80
|
+
|
|
81
|
+
Attributes:
|
|
82
|
+
message: Human-readable error description
|
|
83
|
+
location: Optional location in source (line number, path, etc.)
|
|
84
|
+
line: Optional line number in the YAML file
|
|
85
|
+
column: Optional column number in the YAML file
|
|
86
|
+
context: Optional YAML snippet showing the error location
|
|
87
|
+
suggestion: Optional helpful suggestion for fixing the error
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
# Class-level None defaults so `from_code`-constructed instances (which
|
|
91
|
+
# bypass __init__) still satisfy `e.line` / `e.column` access without
|
|
92
|
+
# crashing. Mirrors the same pattern on RenderError / ExecutionError
|
|
93
|
+
# subclasses.
|
|
94
|
+
location: str | None = None
|
|
95
|
+
line: int | None = None
|
|
96
|
+
column: int | None = None
|
|
97
|
+
context: str | None = None
|
|
98
|
+
suggestion: str | None = None
|
|
99
|
+
|
|
100
|
+
def __init__(
|
|
101
|
+
self,
|
|
102
|
+
message: str,
|
|
103
|
+
location: str | None = None,
|
|
104
|
+
line: int | None = None,
|
|
105
|
+
column: int | None = None,
|
|
106
|
+
context: str | None = None,
|
|
107
|
+
suggestion: str | None = None,
|
|
108
|
+
):
|
|
109
|
+
self.message = message
|
|
110
|
+
self.location = location
|
|
111
|
+
self.line = line
|
|
112
|
+
self.column = column
|
|
113
|
+
self.context = context
|
|
114
|
+
self.suggestion = suggestion
|
|
115
|
+
self.fields: dict[str, Any] = {}
|
|
116
|
+
super().__init__(self._format_message())
|
|
117
|
+
if self.code is None:
|
|
118
|
+
from dataface.core.errors.codes_unknown import DF_UNKNOWN_INTERNAL
|
|
119
|
+
|
|
120
|
+
self.code = DF_UNKNOWN_INTERNAL
|
|
121
|
+
|
|
122
|
+
def _format_message(self) -> str:
|
|
123
|
+
"""Format error message with location, context, and suggestion."""
|
|
124
|
+
parts = []
|
|
125
|
+
|
|
126
|
+
# Add line/column header if available
|
|
127
|
+
if self.line:
|
|
128
|
+
if self.column:
|
|
129
|
+
parts.append(f"Error at line {self.line}, column {self.column}:")
|
|
130
|
+
else:
|
|
131
|
+
parts.append(f"Error at line {self.line}:")
|
|
132
|
+
elif self.location:
|
|
133
|
+
parts.append(f"Error at {self.location}:")
|
|
134
|
+
|
|
135
|
+
# Add YAML context if available
|
|
136
|
+
if self.context:
|
|
137
|
+
parts.append(self.context)
|
|
138
|
+
parts.append("") # Blank line after context
|
|
139
|
+
|
|
140
|
+
# Add the main message
|
|
141
|
+
parts.append(f" {self.message}" if parts else self.message)
|
|
142
|
+
|
|
143
|
+
# Add suggestion if available
|
|
144
|
+
if self.suggestion:
|
|
145
|
+
parts.append(f"\n {self.suggestion}")
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
"\n".join(parts) if len(parts) > 1 else parts[0] if parts else self.message
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class ParseError(CompilationError):
|
|
153
|
+
"""Error during YAML parsing.
|
|
154
|
+
|
|
155
|
+
Raised when:
|
|
156
|
+
- YAML syntax is invalid
|
|
157
|
+
- YAML structure cannot be parsed
|
|
158
|
+
|
|
159
|
+
Attributes:
|
|
160
|
+
line: Line number where the error occurred
|
|
161
|
+
context: YAML snippet showing the error location
|
|
162
|
+
suggestion: Helpful fix suggestion
|
|
163
|
+
|
|
164
|
+
Example:
|
|
165
|
+
>>> try:
|
|
166
|
+
... compile("invalid: yaml: content")
|
|
167
|
+
... except ParseError as e:
|
|
168
|
+
... print(f"Parse failed at line {e.line}: {e}")
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
def __init__(
|
|
172
|
+
self,
|
|
173
|
+
message: str,
|
|
174
|
+
line: int | None = None,
|
|
175
|
+
context: str | None = None,
|
|
176
|
+
suggestion: str | None = None,
|
|
177
|
+
):
|
|
178
|
+
# Don't double-prefix if message already has "YAML parse error"
|
|
179
|
+
if not message.startswith("YAML parse error"):
|
|
180
|
+
message = f"YAML parse error: {message}"
|
|
181
|
+
super().__init__(
|
|
182
|
+
message,
|
|
183
|
+
location=f"line {line}" if line and not context else None,
|
|
184
|
+
line=line,
|
|
185
|
+
context=context,
|
|
186
|
+
suggestion=suggestion,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class ValidationError(CompilationError):
|
|
191
|
+
"""Error during schema validation.
|
|
192
|
+
|
|
193
|
+
Raised when:
|
|
194
|
+
- Required fields are missing
|
|
195
|
+
- Field values are invalid type
|
|
196
|
+
- Enum values are not recognized
|
|
197
|
+
- Schema constraints are violated
|
|
198
|
+
|
|
199
|
+
Attributes:
|
|
200
|
+
field_path: Path to the field that failed validation
|
|
201
|
+
invalid_value: The value that caused the error
|
|
202
|
+
valid_values: List of valid values (if applicable)
|
|
203
|
+
line: Line number where the error occurred
|
|
204
|
+
context: YAML snippet showing the error location
|
|
205
|
+
suggestion: Helpful fix suggestion
|
|
206
|
+
|
|
207
|
+
Example:
|
|
208
|
+
>>> try:
|
|
209
|
+
... compile("charts:\\n my_chart:\\n type: invalid_type")
|
|
210
|
+
... except ValidationError as e:
|
|
211
|
+
... print(f"Validation failed at line {e.line}: {e}")
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
field_path: str | None = None
|
|
215
|
+
invalid_value: str | None = None
|
|
216
|
+
valid_values: list | None = None
|
|
217
|
+
|
|
218
|
+
def __init__(
|
|
219
|
+
self,
|
|
220
|
+
message: str,
|
|
221
|
+
location: str | None = None,
|
|
222
|
+
line: int | None = None,
|
|
223
|
+
context: str | None = None,
|
|
224
|
+
suggestion: str | None = None,
|
|
225
|
+
field_path: str | None = None,
|
|
226
|
+
invalid_value: str | None = None,
|
|
227
|
+
valid_values: list | None = None,
|
|
228
|
+
):
|
|
229
|
+
self.field_path = field_path
|
|
230
|
+
self.invalid_value = invalid_value
|
|
231
|
+
self.valid_values = valid_values
|
|
232
|
+
|
|
233
|
+
# Don't double-prefix if message already has "Validation error"
|
|
234
|
+
if not message.startswith("Validation error"):
|
|
235
|
+
message = f"Validation error: {message}"
|
|
236
|
+
|
|
237
|
+
super().__init__(
|
|
238
|
+
message,
|
|
239
|
+
location=location if not context else None,
|
|
240
|
+
line=line,
|
|
241
|
+
context=context,
|
|
242
|
+
suggestion=suggestion,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class ReferenceError(CompilationError):
|
|
247
|
+
"""Error resolving a reference.
|
|
248
|
+
|
|
249
|
+
Raised when:
|
|
250
|
+
- Chart references unknown query
|
|
251
|
+
- Layout references unknown chart
|
|
252
|
+
- Remote reference cannot be resolved
|
|
253
|
+
- Partial file not found
|
|
254
|
+
|
|
255
|
+
Attributes:
|
|
256
|
+
ref: The reference that could not be resolved
|
|
257
|
+
context: Where the reference was used
|
|
258
|
+
|
|
259
|
+
Example:
|
|
260
|
+
>>> try:
|
|
261
|
+
... compile("charts:\\n my_chart:\\n query: unknown_query")
|
|
262
|
+
... except ReferenceError as e:
|
|
263
|
+
... print(f"Reference '{e.ref}' not found")
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
ref: str | None = None
|
|
267
|
+
|
|
268
|
+
def __init__(self, ref: str, context: str | None = None):
|
|
269
|
+
self.ref = ref
|
|
270
|
+
message = f"Reference '{ref}' not found"
|
|
271
|
+
location = f"in {context}" if context else None
|
|
272
|
+
super().__init__(message, location)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class JinjaError(CompilationError):
|
|
276
|
+
"""Error during Jinja template resolution.
|
|
277
|
+
|
|
278
|
+
Raised when:
|
|
279
|
+
- Jinja syntax is invalid
|
|
280
|
+
- Variable not found in template context
|
|
281
|
+
- Filter not found
|
|
282
|
+
|
|
283
|
+
Attributes:
|
|
284
|
+
template: The template that caused the error (if available)
|
|
285
|
+
|
|
286
|
+
Example:
|
|
287
|
+
>>> try:
|
|
288
|
+
... compile("queries:\\n q: SELECT * FROM {{ undefined_var }}")
|
|
289
|
+
... except JinjaError as e:
|
|
290
|
+
... print(f"Template error: {e}")
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
template: str | None = None
|
|
294
|
+
|
|
295
|
+
def __init__(self, message: str, template: str | None = None):
|
|
296
|
+
self.template = template
|
|
297
|
+
location = (
|
|
298
|
+
f"template: {template[:50]}..."
|
|
299
|
+
if template and len(template) > 50
|
|
300
|
+
else template
|
|
301
|
+
)
|
|
302
|
+
super().__init__(f"Jinja error: {message}", location)
|