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,292 @@
|
|
|
1
|
+
"""Docs verb for the agent API — slices the single DATAFACE_SYNTAX.md file.
|
|
2
|
+
|
|
3
|
+
`DATAFACE_SYNTAX.md` is the only source. H2 headings define topics; topic IDs
|
|
4
|
+
are slugified headings. Bare `docs()` returns the topic index (slug + one-line
|
|
5
|
+
description per H2). `docs(topic="<slug>")` returns one slice.
|
|
6
|
+
`docs(topic="all")` returns the whole file. `docs(topic="reference")` returns
|
|
7
|
+
the auto-generated field spec from yaml-reference.md.
|
|
8
|
+
`docs(search=...)` substring-matches across topics.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import difflib
|
|
14
|
+
import importlib.resources
|
|
15
|
+
import re
|
|
16
|
+
from typing import Literal
|
|
17
|
+
|
|
18
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
19
|
+
|
|
20
|
+
_SYNTAX_FILE = importlib.resources.files("dataface") / "DATAFACE_SYNTAX.md"
|
|
21
|
+
|
|
22
|
+
# Generated field spec ships inside the wheel at dataface/agent_api/docs/yaml-reference.md.
|
|
23
|
+
# Use importlib.resources so pip-installed users get the same file as editable installs.
|
|
24
|
+
_REFERENCE_FILE = (
|
|
25
|
+
importlib.resources.files("dataface.agent_api.docs") / "yaml-reference.md"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
_TOPIC_RE = re.compile(r"^[a-z0-9-]+$")
|
|
29
|
+
_ALL_TOPIC = "all"
|
|
30
|
+
_REFERENCE_TOPIC = "reference"
|
|
31
|
+
|
|
32
|
+
DocsMode = Literal["index", "topic", "search"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class DocsCorpusMissingError(RuntimeError):
|
|
36
|
+
"""`dataface/DATAFACE_SYNTAX.md` is unreachable. Indicates a broken wheel install."""
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class Topic(BaseModel):
|
|
40
|
+
id: str
|
|
41
|
+
title: str
|
|
42
|
+
content: str = ""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TopicEntry(BaseModel):
|
|
46
|
+
"""One row in the docs topic index: slug + heading + first-line description."""
|
|
47
|
+
|
|
48
|
+
id: str
|
|
49
|
+
title: str
|
|
50
|
+
description: str = ""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class DocsSearchHit(BaseModel):
|
|
54
|
+
topic: str
|
|
55
|
+
title: str
|
|
56
|
+
score: float = 0.0
|
|
57
|
+
snippet: str
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class DocsArgs(BaseModel):
|
|
61
|
+
"""Input model for agent_api.docs — drives MCP inputSchema."""
|
|
62
|
+
|
|
63
|
+
topic: str | None = Field(
|
|
64
|
+
None,
|
|
65
|
+
description="Topic slug from the `dft docs` topic index (e.g. 'face', 'charts', 'all', 'reference')",
|
|
66
|
+
)
|
|
67
|
+
search: str | None = Field(
|
|
68
|
+
None, description="Full-text query — runs substring search across all topics"
|
|
69
|
+
)
|
|
70
|
+
limit: int = Field(5, ge=1, le=50, description="Max search hits to return")
|
|
71
|
+
|
|
72
|
+
model_config = ConfigDict(extra="forbid")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class DocsResult(BaseModel):
|
|
76
|
+
success: bool = True
|
|
77
|
+
mode: DocsMode
|
|
78
|
+
topic: Topic | None = None
|
|
79
|
+
search: list[DocsSearchHit] = []
|
|
80
|
+
topics: list[TopicEntry] = []
|
|
81
|
+
errors: list[str] = []
|
|
82
|
+
hints: list[str] = []
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def docs(
|
|
86
|
+
topic: str | None = None,
|
|
87
|
+
search: str | None = None,
|
|
88
|
+
limit: int = 5,
|
|
89
|
+
) -> DocsResult:
|
|
90
|
+
"""Look up a docs topic, fetch the whole file, or search the corpus.
|
|
91
|
+
|
|
92
|
+
- ``docs()`` — index mode: returns one entry per H2 with first-line description.
|
|
93
|
+
- ``docs(topic="face")`` — return content for one H2 section.
|
|
94
|
+
- ``docs(topic="all")`` — return the full ``DATAFACE_SYNTAX.md`` unsliced.
|
|
95
|
+
- ``docs(topic="reference")`` — return the auto-generated field spec.
|
|
96
|
+
- ``docs(search="grid")`` — substring search across H2 sections.
|
|
97
|
+
"""
|
|
98
|
+
if topic is not None and search is not None:
|
|
99
|
+
return DocsResult(
|
|
100
|
+
success=False,
|
|
101
|
+
mode="topic",
|
|
102
|
+
errors=["topic and --search are mutually exclusive; use one"],
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
if search is not None:
|
|
106
|
+
sections = _load_sections()
|
|
107
|
+
return DocsResult(mode="search", search=_search(search, sections, limit=limit))
|
|
108
|
+
|
|
109
|
+
if topic is None:
|
|
110
|
+
return DocsResult(mode="index", topics=_topic_index())
|
|
111
|
+
|
|
112
|
+
if topic == _ALL_TOPIC:
|
|
113
|
+
return DocsResult(
|
|
114
|
+
mode="topic",
|
|
115
|
+
topic=Topic(
|
|
116
|
+
id=_ALL_TOPIC, title="Dataface YAML Syntax", content=read_full_text()
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if topic == _REFERENCE_TOPIC:
|
|
121
|
+
try:
|
|
122
|
+
content = _REFERENCE_FILE.read_text(encoding="utf-8")
|
|
123
|
+
except FileNotFoundError:
|
|
124
|
+
return DocsResult(
|
|
125
|
+
success=False,
|
|
126
|
+
mode="topic",
|
|
127
|
+
errors=[
|
|
128
|
+
"yaml-reference.md not found inside the dataface package. Run `just gen-yaml-reference` and commit the result."
|
|
129
|
+
],
|
|
130
|
+
)
|
|
131
|
+
return DocsResult(
|
|
132
|
+
mode="topic",
|
|
133
|
+
topic=Topic(
|
|
134
|
+
id=_REFERENCE_TOPIC,
|
|
135
|
+
title="Dataface YAML Field Reference (generated)",
|
|
136
|
+
content=content,
|
|
137
|
+
),
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
if not _TOPIC_RE.fullmatch(topic):
|
|
141
|
+
return DocsResult(
|
|
142
|
+
success=False,
|
|
143
|
+
mode="topic",
|
|
144
|
+
errors=[f"Invalid topic id: {topic!r}"],
|
|
145
|
+
hints=[
|
|
146
|
+
"Topic ids match [a-z0-9-]+ (lowercased H2 headings); run `dft docs` for the topic index"
|
|
147
|
+
],
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
sections = _load_sections()
|
|
151
|
+
if topic not in sections:
|
|
152
|
+
all_topics = list(sections.keys())
|
|
153
|
+
close = difflib.get_close_matches(topic, all_topics, n=3, cutoff=0.4)
|
|
154
|
+
hints = (
|
|
155
|
+
[f"Did you mean: {', '.join(close)}"]
|
|
156
|
+
if close
|
|
157
|
+
else ["Run `dft docs` for the topic index"]
|
|
158
|
+
)
|
|
159
|
+
return DocsResult(
|
|
160
|
+
success=False,
|
|
161
|
+
mode="topic",
|
|
162
|
+
errors=[f"Unknown topic: {topic}"],
|
|
163
|
+
hints=hints,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
title, body = sections[topic]
|
|
167
|
+
return DocsResult(mode="topic", topic=Topic(id=topic, title=title, content=body))
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def read_full_text() -> str:
|
|
171
|
+
"""Return the raw ``DATAFACE_SYNTAX.md`` content unsliced.
|
|
172
|
+
|
|
173
|
+
Shared file-load helper for callers that want the whole reference: the agent
|
|
174
|
+
system prompt, the playground AI service, and the ``dataface://docs/all``
|
|
175
|
+
MCP resource.
|
|
176
|
+
"""
|
|
177
|
+
try:
|
|
178
|
+
return _SYNTAX_FILE.read_text(encoding="utf-8")
|
|
179
|
+
except FileNotFoundError as exc:
|
|
180
|
+
raise DocsCorpusMissingError(
|
|
181
|
+
f"Docs source file missing (path={_SYNTAX_FILE}). "
|
|
182
|
+
"The Dataface wheel is broken or the file was monkeypatched away."
|
|
183
|
+
) from exc
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def slugify(heading: str) -> str:
|
|
187
|
+
"""Slugify an H2 heading to a topic ID.
|
|
188
|
+
|
|
189
|
+
Locked-in rule: lowercase, strip leading `#`, trim whitespace, replace
|
|
190
|
+
runs of whitespace with single hyphens, keep ASCII letters/digits/hyphens,
|
|
191
|
+
drop everything else.
|
|
192
|
+
"""
|
|
193
|
+
text = heading.lstrip("#").strip().lower()
|
|
194
|
+
text = re.sub(r"\s+", "-", text)
|
|
195
|
+
return re.sub(r"[^a-z0-9-]+", "", text)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _load_sections() -> dict[str, tuple[str, str]]:
|
|
199
|
+
"""Read DATAFACE_SYNTAX.md and slice on H2 headers.
|
|
200
|
+
|
|
201
|
+
Returns an insertion-ordered mapping ``{slug: (title, body)}`` where body
|
|
202
|
+
starts at the H2 line and runs up to (but not including) the next H2 line.
|
|
203
|
+
Order matches the file — used by the topic index to preserve reading order.
|
|
204
|
+
"""
|
|
205
|
+
text = read_full_text()
|
|
206
|
+
lines = text.splitlines(keepends=True)
|
|
207
|
+
sections: dict[str, tuple[str, str]] = {}
|
|
208
|
+
current_title: str | None = None
|
|
209
|
+
current_lines: list[str] = []
|
|
210
|
+
for line in lines:
|
|
211
|
+
if line.startswith("## "):
|
|
212
|
+
if current_title is not None:
|
|
213
|
+
sections[slugify(current_title)] = (
|
|
214
|
+
current_title,
|
|
215
|
+
"".join(current_lines).rstrip() + "\n",
|
|
216
|
+
)
|
|
217
|
+
current_title = line[3:].strip()
|
|
218
|
+
current_lines = [line]
|
|
219
|
+
elif current_title is not None:
|
|
220
|
+
current_lines.append(line)
|
|
221
|
+
if current_title is not None:
|
|
222
|
+
sections[slugify(current_title)] = (
|
|
223
|
+
current_title,
|
|
224
|
+
"".join(current_lines).rstrip() + "\n",
|
|
225
|
+
)
|
|
226
|
+
return sections
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _first_description_line(body: str) -> str:
|
|
230
|
+
"""Return the first non-empty, non-heading prose line from a section body.
|
|
231
|
+
|
|
232
|
+
The body starts with the H2 line itself. Skip the H2 line, skip blank
|
|
233
|
+
lines, skip sub-headings (lines starting with `#`), and return the first
|
|
234
|
+
real text line with minimal markdown stripping (backticks, bold/italic).
|
|
235
|
+
"""
|
|
236
|
+
for raw in body.splitlines():
|
|
237
|
+
line = raw.strip()
|
|
238
|
+
if not line or line.startswith("#"):
|
|
239
|
+
continue
|
|
240
|
+
return _strip_markdown(line)
|
|
241
|
+
return ""
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
_MD_LINK_RE = re.compile(r"\[([^\]]+)\]\([^)]+\)")
|
|
245
|
+
_MD_INLINE_RE = re.compile(r"[`*_]+")
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _strip_markdown(text: str) -> str:
|
|
249
|
+
text = _MD_LINK_RE.sub(r"\1", text)
|
|
250
|
+
return _MD_INLINE_RE.sub("", text).strip()
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _topic_index() -> list[TopicEntry]:
|
|
254
|
+
"""Return one TopicEntry per H2 section, in file order."""
|
|
255
|
+
return [
|
|
256
|
+
TopicEntry(id=slug, title=title, description=_first_description_line(body))
|
|
257
|
+
for slug, (title, body) in _load_sections().items()
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _search(
|
|
262
|
+
query: str, sections: dict[str, tuple[str, str]], limit: int = 5
|
|
263
|
+
) -> list[DocsSearchHit]:
|
|
264
|
+
"""Substring search across H2 slices with bucketed scoring (1.0 / 0.8 / 0.5)."""
|
|
265
|
+
q = query.lower()
|
|
266
|
+
hits: list[DocsSearchHit] = []
|
|
267
|
+
for slug, (title, body) in sections.items():
|
|
268
|
+
if q in slug:
|
|
269
|
+
snippet = _first_matching_line(body, q) or title
|
|
270
|
+
hits.append(
|
|
271
|
+
DocsSearchHit(topic=slug, title=title, score=1.0, snippet=snippet)
|
|
272
|
+
)
|
|
273
|
+
elif q in title.lower():
|
|
274
|
+
snippet = _first_matching_line(body, q) or title
|
|
275
|
+
hits.append(
|
|
276
|
+
DocsSearchHit(topic=slug, title=title, score=0.8, snippet=snippet)
|
|
277
|
+
)
|
|
278
|
+
else:
|
|
279
|
+
line = _first_matching_line(body, q)
|
|
280
|
+
if line:
|
|
281
|
+
hits.append(
|
|
282
|
+
DocsSearchHit(topic=slug, title=title, score=0.5, snippet=line)
|
|
283
|
+
)
|
|
284
|
+
hits.sort(key=lambda h: h.score, reverse=True)
|
|
285
|
+
return hits[:limit]
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _first_matching_line(content: str, query: str) -> str:
|
|
289
|
+
for line in content.splitlines():
|
|
290
|
+
if query in line.lower():
|
|
291
|
+
return line.strip()
|
|
292
|
+
return ""
|