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,297 @@
|
|
|
1
|
+
"""Query normalization and external query resolution."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import yaml
|
|
8
|
+
from pydantic import ValidationError as PydanticValidationError
|
|
9
|
+
|
|
10
|
+
from dataface.core.compile.errors import CompilationError
|
|
11
|
+
from dataface.core.compile.filter_injection import extract_filter_variable_deps
|
|
12
|
+
from dataface.core.compile.jinja import extract_variable_dependencies
|
|
13
|
+
from dataface.core.compile.models.query.authored import AuthoredQuery
|
|
14
|
+
from dataface.core.compile.models.query.compiled import (
|
|
15
|
+
AnyQuery,
|
|
16
|
+
CsvQuery,
|
|
17
|
+
DbtModelQuery,
|
|
18
|
+
HttpQuery,
|
|
19
|
+
MetricFlowQuery,
|
|
20
|
+
SchemaResolverQuery,
|
|
21
|
+
SqlQuery,
|
|
22
|
+
ValuesQuery,
|
|
23
|
+
is_sql_query,
|
|
24
|
+
)
|
|
25
|
+
from dataface.core.compile.models.refs import infer_query_type_from_keys
|
|
26
|
+
from dataface.core.compile.sql_authoring_lint import has_literal_escaped_newlines
|
|
27
|
+
from dataface.core.errors.codes_compile import DF_COMPILE_SQL_LITERAL_NEWLINES
|
|
28
|
+
from dataface.core.execute.errors import MutatingSqlError, UnparseableSqlError
|
|
29
|
+
from dataface.core.execute.sql_guard import validate_select_only, validate_setup_sql
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def normalize_query(
|
|
35
|
+
name: str,
|
|
36
|
+
query_def: Any,
|
|
37
|
+
default_source: str | None = None,
|
|
38
|
+
) -> AnyQuery:
|
|
39
|
+
"""Normalize a query definition to AnyQuery.
|
|
40
|
+
|
|
41
|
+
Creates the appropriate query type (SqlQuery, CsvQuery, etc.)
|
|
42
|
+
based on the query definition.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
name: Query name
|
|
46
|
+
query_def: AuthoredQuery definition (AuthoredQuery, dict, or bare SQL string shorthand)
|
|
47
|
+
default_source: Default source to apply if query has no explicit source
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Query object (SqlQuery, CsvQuery, etc.)
|
|
51
|
+
"""
|
|
52
|
+
# Non-SQL pre-built query types need no guard — return immediately.
|
|
53
|
+
if isinstance(
|
|
54
|
+
query_def,
|
|
55
|
+
(
|
|
56
|
+
CsvQuery,
|
|
57
|
+
MetricFlowQuery,
|
|
58
|
+
HttpQuery,
|
|
59
|
+
DbtModelQuery,
|
|
60
|
+
ValuesQuery,
|
|
61
|
+
SchemaResolverQuery,
|
|
62
|
+
),
|
|
63
|
+
):
|
|
64
|
+
return query_def
|
|
65
|
+
|
|
66
|
+
# Pre-built SqlQuery: skip reconstruction but still run guard + dep-extraction below.
|
|
67
|
+
if isinstance(query_def, SqlQuery):
|
|
68
|
+
query: AnyQuery = query_def
|
|
69
|
+
else:
|
|
70
|
+
# Convert to dict
|
|
71
|
+
if isinstance(query_def, AuthoredQuery):
|
|
72
|
+
query_dict = query_def.model_dump(exclude_none=True)
|
|
73
|
+
elif isinstance(query_def, dict):
|
|
74
|
+
query_dict = dict(query_def)
|
|
75
|
+
elif isinstance(query_def, str):
|
|
76
|
+
query_dict = {"sql": query_def}
|
|
77
|
+
else:
|
|
78
|
+
raise CompilationError(
|
|
79
|
+
f"Query '{name}': Invalid query definition. Expected dict with 'sql' and 'source' fields for SQL queries."
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Ensure type field
|
|
83
|
+
if "type" not in query_dict:
|
|
84
|
+
query_dict["type"] = infer_query_type_from_keys(query_dict)
|
|
85
|
+
|
|
86
|
+
query_type = query_dict.pop("type")
|
|
87
|
+
|
|
88
|
+
# Apply default source if query doesn't have one.
|
|
89
|
+
# ValuesQuery is inline data; SchemaResolverQuery's source is a dbt source name,
|
|
90
|
+
# not a connection reference; HttpQuery uses url, not source — all three are excluded.
|
|
91
|
+
has_source = query_dict.get("source") is not None
|
|
92
|
+
if (
|
|
93
|
+
not has_source
|
|
94
|
+
and default_source
|
|
95
|
+
and query_type not in {"values", "dbt_model", "schema_resolver", "http"}
|
|
96
|
+
):
|
|
97
|
+
query_dict["source"] = default_source
|
|
98
|
+
|
|
99
|
+
# Create the appropriate query type
|
|
100
|
+
if query_type == "sql":
|
|
101
|
+
# Ensure sql is present
|
|
102
|
+
if "sql" not in query_dict:
|
|
103
|
+
raise CompilationError(
|
|
104
|
+
f"Query '{name}': SQL queries must have 'sql' field"
|
|
105
|
+
)
|
|
106
|
+
# Check for source
|
|
107
|
+
if "source" not in query_dict:
|
|
108
|
+
raise CompilationError(
|
|
109
|
+
f"Query '{name}': SQL queries must have 'source' field "
|
|
110
|
+
"to specify which database connection to use. "
|
|
111
|
+
"You can also set a default source at the face level."
|
|
112
|
+
)
|
|
113
|
+
query = SqlQuery(**query_dict)
|
|
114
|
+
elif query_type == "csv":
|
|
115
|
+
# CSV queries need either file or source with file config
|
|
116
|
+
if "file" not in query_dict and "source" not in query_dict:
|
|
117
|
+
raise CompilationError(
|
|
118
|
+
f"Query '{name}': CSV queries must have 'file' field or 'source' reference"
|
|
119
|
+
)
|
|
120
|
+
query = CsvQuery(**query_dict)
|
|
121
|
+
elif query_type == "metricflow":
|
|
122
|
+
query = MetricFlowQuery(**query_dict)
|
|
123
|
+
elif query_type == "http":
|
|
124
|
+
if "url" not in query_dict:
|
|
125
|
+
raise CompilationError(
|
|
126
|
+
f"Query '{name}': HTTP queries require a 'url' field"
|
|
127
|
+
)
|
|
128
|
+
try:
|
|
129
|
+
query = HttpQuery(**query_dict)
|
|
130
|
+
except PydanticValidationError as e:
|
|
131
|
+
fields = ", ".join(
|
|
132
|
+
str(err["loc"][0]) for err in e.errors() if err["loc"]
|
|
133
|
+
)
|
|
134
|
+
raise CompilationError(
|
|
135
|
+
f"Query '{name}': invalid field(s) for HTTP query: {fields}"
|
|
136
|
+
) from e
|
|
137
|
+
elif query_type == "dbt_model":
|
|
138
|
+
query = DbtModelQuery(**query_dict)
|
|
139
|
+
elif query_type == "values":
|
|
140
|
+
query = ValuesQuery(**query_dict)
|
|
141
|
+
elif query_type == "schema_resolver":
|
|
142
|
+
query = SchemaResolverQuery(**query_dict)
|
|
143
|
+
else:
|
|
144
|
+
# Default to SQL
|
|
145
|
+
query = SqlQuery(**query_dict)
|
|
146
|
+
|
|
147
|
+
# Validate setup_sql doesn't contain query references (non-nestable by design)
|
|
148
|
+
if is_sql_query(query) and query.setup_sql and "{{ queries." in query.setup_sql:
|
|
149
|
+
raise CompilationError(
|
|
150
|
+
f"Query '{name}': setup_sql must not contain {{{{ queries.X }}}} references. "
|
|
151
|
+
"setup_sql is for non-nestable setup statements (CREATE TEMP FUNCTION, etc.)."
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Compile-time SQL guard + variable-dep extraction for SQL queries.
|
|
155
|
+
# UnparseableSqlError is silently deferred (compile lacks the dbt manifest for
|
|
156
|
+
# {{ ref() }} resolution and must not reject faces with complex Jinja macros).
|
|
157
|
+
# MutatingSqlError is fatal at compile time — wrap in CompilationError with query name.
|
|
158
|
+
deps: set = set()
|
|
159
|
+
if is_sql_query(query):
|
|
160
|
+
dialect = query.source.get("type") if isinstance(query.source, dict) else None
|
|
161
|
+
|
|
162
|
+
# Authoring lint: detect literal \n (backslash + n) from single-quoted YAML.
|
|
163
|
+
# Must run before validate_select_only because literal \n causes parse failure
|
|
164
|
+
# that would otherwise be silently deferred as UnparseableSqlError.
|
|
165
|
+
if has_literal_escaped_newlines(query.sql, dialect=dialect):
|
|
166
|
+
raise CompilationError.from_code(
|
|
167
|
+
DF_COMPILE_SQL_LITERAL_NEWLINES, query_name=name, field_label="sql"
|
|
168
|
+
)
|
|
169
|
+
if query.setup_sql and has_literal_escaped_newlines(
|
|
170
|
+
query.setup_sql, dialect=dialect
|
|
171
|
+
):
|
|
172
|
+
raise CompilationError.from_code(
|
|
173
|
+
DF_COMPILE_SQL_LITERAL_NEWLINES,
|
|
174
|
+
query_name=name,
|
|
175
|
+
field_label="setup_sql",
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
validate_select_only(query.sql, dialect=dialect)
|
|
180
|
+
except UnparseableSqlError:
|
|
181
|
+
logger.debug("compile-time SQL validation deferred to runtime: %s", name)
|
|
182
|
+
except MutatingSqlError as e:
|
|
183
|
+
raise CompilationError(f"Query '{name}': {e}") from e
|
|
184
|
+
|
|
185
|
+
if query.setup_sql:
|
|
186
|
+
try:
|
|
187
|
+
validate_setup_sql(query.setup_sql, dialect=dialect)
|
|
188
|
+
except UnparseableSqlError:
|
|
189
|
+
logger.debug(
|
|
190
|
+
"compile-time setup_sql validation deferred to runtime: %s", name
|
|
191
|
+
)
|
|
192
|
+
except MutatingSqlError as e:
|
|
193
|
+
raise CompilationError(f"Query '{name}' setup_sql: {e}") from e
|
|
194
|
+
|
|
195
|
+
if query.sql:
|
|
196
|
+
deps |= extract_variable_dependencies(query.sql)
|
|
197
|
+
if query.setup_sql:
|
|
198
|
+
deps |= extract_variable_dependencies(query.setup_sql)
|
|
199
|
+
# Declarative filters: variable names are direct values, not Jinja templates
|
|
200
|
+
if query.filters:
|
|
201
|
+
deps |= extract_filter_variable_deps(query.filters)
|
|
202
|
+
query.variable_dependencies = deps
|
|
203
|
+
|
|
204
|
+
return query
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# Cache for loaded external query files
|
|
208
|
+
_external_query_cache: dict[str, dict[str, AnyQuery]] = {}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def resolve_external_query(
|
|
212
|
+
query_ref: str,
|
|
213
|
+
query_registry: dict[str, AnyQuery],
|
|
214
|
+
base_path: Path | None = None,
|
|
215
|
+
) -> tuple[str, dict[str, AnyQuery]]:
|
|
216
|
+
"""Resolve an external query reference.
|
|
217
|
+
|
|
218
|
+
Parses references like `path/to/file.yml#query_name` and loads
|
|
219
|
+
queries from the external file.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
query_ref: Query reference with file path (e.g., "_shared.yml#sales")
|
|
223
|
+
query_registry: Current query registry to merge into
|
|
224
|
+
base_path: Base path for resolving relative file paths
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
Tuple of (resolved_query_name, updated_query_registry)
|
|
228
|
+
|
|
229
|
+
Raises:
|
|
230
|
+
CompilationError: If file not found or query not in file
|
|
231
|
+
"""
|
|
232
|
+
# Parse file path and query name
|
|
233
|
+
file_part, query_name = query_ref.split("#", 1)
|
|
234
|
+
|
|
235
|
+
if not file_part or not query_name:
|
|
236
|
+
raise CompilationError(
|
|
237
|
+
f"Invalid external query reference: '{query_ref}'. "
|
|
238
|
+
"Expected format: 'path/to/file.yml#query_name'"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# Resolve file path
|
|
242
|
+
file_path = base_path / file_part if base_path else Path(file_part)
|
|
243
|
+
|
|
244
|
+
# Create a unique registry key for this file's queries
|
|
245
|
+
file_key = str(file_path.resolve()) if file_path.exists() else str(file_path)
|
|
246
|
+
|
|
247
|
+
# Check cache first
|
|
248
|
+
if file_key not in _external_query_cache:
|
|
249
|
+
# Load and parse the external file
|
|
250
|
+
if not file_path.exists():
|
|
251
|
+
raise CompilationError(
|
|
252
|
+
f"External query file not found: '{file_path}' "
|
|
253
|
+
f"(referenced as '{query_ref}')"
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
try:
|
|
257
|
+
with open(file_path) as f:
|
|
258
|
+
external_data = yaml.safe_load(f)
|
|
259
|
+
except yaml.YAMLError as e:
|
|
260
|
+
raise CompilationError(
|
|
261
|
+
f"Failed to parse external query file '{file_path}': {e}"
|
|
262
|
+
) from e
|
|
263
|
+
|
|
264
|
+
if not isinstance(external_data, dict):
|
|
265
|
+
raise CompilationError(
|
|
266
|
+
f"External query file '{file_path}' must be a YAML dictionary"
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# Extract and normalize queries from the file
|
|
270
|
+
external_queries: dict[str, AnyQuery] = {}
|
|
271
|
+
queries_section = external_data.get("queries", {})
|
|
272
|
+
|
|
273
|
+
for ext_query_name, ext_query_def in queries_section.items():
|
|
274
|
+
compiled_query = normalize_query(ext_query_name, ext_query_def)
|
|
275
|
+
external_queries[ext_query_name] = compiled_query
|
|
276
|
+
|
|
277
|
+
_external_query_cache[file_key] = external_queries
|
|
278
|
+
|
|
279
|
+
# Get cached queries for this file
|
|
280
|
+
file_queries = _external_query_cache[file_key]
|
|
281
|
+
|
|
282
|
+
if query_name not in file_queries:
|
|
283
|
+
available = ", ".join(file_queries.keys()) if file_queries else "none"
|
|
284
|
+
raise CompilationError(
|
|
285
|
+
f"Query '{query_name}' not found in '{file_path}'. "
|
|
286
|
+
f"Available queries: {available}"
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
# Create a unique key for this external query in the registry
|
|
290
|
+
# Use file path + query name to avoid collisions
|
|
291
|
+
registry_key = f"{file_part}#{query_name}"
|
|
292
|
+
|
|
293
|
+
# Add to registry if not already present
|
|
294
|
+
if registry_key not in query_registry:
|
|
295
|
+
query_registry[registry_key] = file_queries[query_name]
|
|
296
|
+
|
|
297
|
+
return registry_key, query_registry
|