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,347 @@
|
|
|
1
|
+
"""Typed global config contract for compiled runtime defaults.
|
|
2
|
+
|
|
3
|
+
This module mirrors the style-system pattern:
|
|
4
|
+
|
|
5
|
+
- ``Config`` is the authoritative required runtime config object
|
|
6
|
+
- ``ConfigPatch`` is the all-optional overlay shape used for authored/default YAML
|
|
7
|
+
|
|
8
|
+
Dynamic sections such as ``themes`` remain open-ended, but
|
|
9
|
+
they are backed by Pydantic mapping-like nodes that still support mapping access.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from collections.abc import ItemsView, Iterator, KeysView, Mapping, ValuesView
|
|
15
|
+
from functools import cache
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from pydantic import (
|
|
19
|
+
BaseModel,
|
|
20
|
+
ConfigDict,
|
|
21
|
+
Field,
|
|
22
|
+
PrivateAttr,
|
|
23
|
+
create_model,
|
|
24
|
+
model_validator,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
from dataface.core.compile.models.primitives import FontStyle
|
|
28
|
+
from dataface.core.compile.models.style.compiled import Style
|
|
29
|
+
from dataface.core.compile.models.vega_lite.config import VegaLiteConfig
|
|
30
|
+
from dataface.core.compile.vega_lite import VEGA_LITE_SCHEMA_URL
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _normalize_node_value(value: object) -> object:
|
|
34
|
+
"""Recursively normalize nested mapping values into ConfigNode objects."""
|
|
35
|
+
if isinstance(value, BaseModel):
|
|
36
|
+
return value
|
|
37
|
+
if isinstance(value, Mapping):
|
|
38
|
+
return ConfigNode.model_validate(dict(value))
|
|
39
|
+
if isinstance(value, list):
|
|
40
|
+
return [_normalize_node_value(item) for item in value]
|
|
41
|
+
return value
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ConfigMappingBase(BaseModel, Mapping[str, Any]):
|
|
45
|
+
"""Pydantic model with mapping-like helpers for config consumers."""
|
|
46
|
+
|
|
47
|
+
model_config = ConfigDict(extra="forbid")
|
|
48
|
+
|
|
49
|
+
# Mapping access is a migration shim for dynamic config sections; cache the
|
|
50
|
+
# assembled top-level view and invalidate when this model's own fields change.
|
|
51
|
+
_mapping_cache: dict[str, Any] | None = PrivateAttr(default=None)
|
|
52
|
+
|
|
53
|
+
def _mapping_data(self) -> dict[str, Any]:
|
|
54
|
+
mapping_cache = object.__getattribute__(self, "__pydantic_private__").get(
|
|
55
|
+
"_mapping_cache"
|
|
56
|
+
)
|
|
57
|
+
if mapping_cache is not None:
|
|
58
|
+
return mapping_cache
|
|
59
|
+
|
|
60
|
+
data: dict[str, Any] = {}
|
|
61
|
+
for key, field in type(self).model_fields.items():
|
|
62
|
+
value = object.__getattribute__(self, key)
|
|
63
|
+
data[key] = value
|
|
64
|
+
if field.alias and field.alias != key:
|
|
65
|
+
data[field.alias] = value
|
|
66
|
+
extra = object.__getattribute__(self, "__pydantic_extra__") or {}
|
|
67
|
+
for key, value in extra.items():
|
|
68
|
+
data[key] = value
|
|
69
|
+
self._mapping_cache = data
|
|
70
|
+
return data
|
|
71
|
+
|
|
72
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
73
|
+
super().__setattr__(name, value)
|
|
74
|
+
if name != "_mapping_cache":
|
|
75
|
+
self._mapping_cache = None
|
|
76
|
+
|
|
77
|
+
def __delattr__(self, item: str) -> None:
|
|
78
|
+
super().__delattr__(item)
|
|
79
|
+
if item != "_mapping_cache":
|
|
80
|
+
self._mapping_cache = None
|
|
81
|
+
|
|
82
|
+
def __getitem__(self, key: str) -> Any:
|
|
83
|
+
data = self._mapping_data()
|
|
84
|
+
if key not in data:
|
|
85
|
+
raise KeyError(key)
|
|
86
|
+
return data[key]
|
|
87
|
+
|
|
88
|
+
def __iter__(self) -> Iterator[str]: # type: ignore[override]
|
|
89
|
+
return iter(self._mapping_data())
|
|
90
|
+
|
|
91
|
+
def __len__(self) -> int:
|
|
92
|
+
return len(self._mapping_data())
|
|
93
|
+
|
|
94
|
+
def __bool__(self) -> bool:
|
|
95
|
+
return bool(self._mapping_data())
|
|
96
|
+
|
|
97
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
98
|
+
return self._mapping_data().get(key, default)
|
|
99
|
+
|
|
100
|
+
def items(self) -> ItemsView[str, Any]:
|
|
101
|
+
return self._mapping_data().items()
|
|
102
|
+
|
|
103
|
+
def keys(self) -> KeysView[str]:
|
|
104
|
+
return self._mapping_data().keys()
|
|
105
|
+
|
|
106
|
+
def values(self) -> ValuesView[Any]:
|
|
107
|
+
return self._mapping_data().values()
|
|
108
|
+
|
|
109
|
+
def __getattr__(self, name: str) -> Any:
|
|
110
|
+
if name.startswith("_"):
|
|
111
|
+
raise AttributeError(name)
|
|
112
|
+
data = self._mapping_data()
|
|
113
|
+
if name in data:
|
|
114
|
+
return data[name]
|
|
115
|
+
raise AttributeError(name)
|
|
116
|
+
|
|
117
|
+
def to_plain_dict(self, *, exclude_none: bool = True) -> dict[str, Any]:
|
|
118
|
+
"""Dump config models to plain nested Python dicts."""
|
|
119
|
+
return self.model_dump(mode="python", exclude_none=exclude_none, by_alias=True)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class ConfigNode(ConfigMappingBase):
|
|
123
|
+
"""Open-ended config section that still supports attribute and mapping access."""
|
|
124
|
+
|
|
125
|
+
# Accepts arbitrary keys — the config tree is open-ended by design.
|
|
126
|
+
model_config = ConfigDict(extra="allow")
|
|
127
|
+
|
|
128
|
+
@model_validator(mode="before")
|
|
129
|
+
@classmethod
|
|
130
|
+
def _normalize_input(cls, value: object) -> object:
|
|
131
|
+
if isinstance(value, ConfigNode):
|
|
132
|
+
return value
|
|
133
|
+
if isinstance(value, Mapping):
|
|
134
|
+
return {key: _normalize_node_value(item) for key, item in value.items()}
|
|
135
|
+
return value
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class RenderingConfig(ConfigNode):
|
|
139
|
+
class TimestampConfig(ConfigNode):
|
|
140
|
+
font: FontStyle
|
|
141
|
+
y: float
|
|
142
|
+
|
|
143
|
+
@model_validator(mode="after")
|
|
144
|
+
def _require_font_size_and_color(self) -> RenderingConfig.TimestampConfig:
|
|
145
|
+
# The timestamp renderer writes `font-size` and `fill` attributes
|
|
146
|
+
# directly into SVG. Missing values would silently emit the empty
|
|
147
|
+
# string or the literal "None". Require both at config-load time
|
|
148
|
+
# so misconfiguration fails loudly.
|
|
149
|
+
if self.font.size is None:
|
|
150
|
+
raise ValueError("rendering.timestamp.font.size is required (float)")
|
|
151
|
+
if self.font.color is None:
|
|
152
|
+
raise ValueError(
|
|
153
|
+
"rendering.timestamp.font.color is required (color string)"
|
|
154
|
+
)
|
|
155
|
+
return self
|
|
156
|
+
|
|
157
|
+
class FooterConfig(ConfigNode):
|
|
158
|
+
class RuleConfig(ConfigNode):
|
|
159
|
+
color: str
|
|
160
|
+
stroke_width: float
|
|
161
|
+
|
|
162
|
+
font: FontStyle
|
|
163
|
+
y_offset: float
|
|
164
|
+
# None means "no hairline rule above the footer text" — a legitimate
|
|
165
|
+
# theme choice distinct from "rule configured but invisible". Theme YAML
|
|
166
|
+
# supplies a default RuleConfig; users override with `rule: null` to drop it.
|
|
167
|
+
rule: RuleConfig | None = None
|
|
168
|
+
|
|
169
|
+
@model_validator(mode="after")
|
|
170
|
+
def _require_font_size_and_color(self) -> RenderingConfig.FooterConfig:
|
|
171
|
+
if self.font.size is None:
|
|
172
|
+
raise ValueError("rendering.footer.font.size is required (float)")
|
|
173
|
+
if self.font.color is None:
|
|
174
|
+
raise ValueError(
|
|
175
|
+
"rendering.footer.font.color is required (color string)"
|
|
176
|
+
)
|
|
177
|
+
return self
|
|
178
|
+
|
|
179
|
+
class SvgRenderingConfig(ConfigNode):
|
|
180
|
+
preserve_aspect_ratio: str
|
|
181
|
+
background: str | None = None # None = renderer uses theme background
|
|
182
|
+
|
|
183
|
+
class PngRenderingConfig(ConfigNode):
|
|
184
|
+
scale: float
|
|
185
|
+
background: str | None = None # None = renderer uses theme background
|
|
186
|
+
|
|
187
|
+
class PdfRenderingConfig(ConfigNode):
|
|
188
|
+
background: str | None = None # None = renderer uses theme background
|
|
189
|
+
page_size: str
|
|
190
|
+
|
|
191
|
+
class HtmlRenderingConfig(ConfigNode):
|
|
192
|
+
background: str | None = None # None = renderer uses theme background
|
|
193
|
+
|
|
194
|
+
class TerminalRenderingConfig(ConfigNode):
|
|
195
|
+
background: str | None = None # None = renderer uses theme background
|
|
196
|
+
|
|
197
|
+
timestamp_visible: bool
|
|
198
|
+
timestamp_format: str
|
|
199
|
+
timestamp: TimestampConfig
|
|
200
|
+
footer_text: str
|
|
201
|
+
footer: FooterConfig
|
|
202
|
+
svg: SvgRenderingConfig
|
|
203
|
+
png: PngRenderingConfig
|
|
204
|
+
pdf: PdfRenderingConfig
|
|
205
|
+
html: HtmlRenderingConfig
|
|
206
|
+
terminal: TerminalRenderingConfig
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class MarkdownConfig(ConfigNode):
|
|
210
|
+
light: ConfigNode
|
|
211
|
+
dark: ConfigNode
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class VegaRuntimeConfig(ConfigNode):
|
|
215
|
+
default_theme: str
|
|
216
|
+
config: VegaLiteConfig = Field(default_factory=VegaLiteConfig)
|
|
217
|
+
|
|
218
|
+
@property
|
|
219
|
+
def schema(self) -> str: # type: ignore[override]
|
|
220
|
+
return VEGA_LITE_SCHEMA_URL
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class Config(ConfigMappingBase):
|
|
224
|
+
"""Authoritative required runtime config model.
|
|
225
|
+
|
|
226
|
+
Closed top-level fields define the supported global config surface. Some
|
|
227
|
+
nested sections remain intentionally open-ended because they carry dynamic
|
|
228
|
+
named entries such as themes, presets, palettes, and chart-type maps.
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
model_config = ConfigDict(extra="forbid")
|
|
232
|
+
|
|
233
|
+
chart_rendering: ConfigNode
|
|
234
|
+
geo_sources: ConfigNode
|
|
235
|
+
inspector: ConfigNode
|
|
236
|
+
markdown: MarkdownConfig
|
|
237
|
+
rendering: RenderingConfig
|
|
238
|
+
style: Style
|
|
239
|
+
terminal: ConfigNode
|
|
240
|
+
themes: ConfigNode = Field(
|
|
241
|
+
default_factory=ConfigNode
|
|
242
|
+
) # legacy VL-format themes; empty after chart_themes/ deletion
|
|
243
|
+
palettes: ConfigNode
|
|
244
|
+
vega: VegaRuntimeConfig
|
|
245
|
+
dft_grays: ConfigNode
|
|
246
|
+
dft_creams: ConfigNode
|
|
247
|
+
strict: bool | None = None # None = strict mode not configured; defaults to off
|
|
248
|
+
sources: ConfigNode | None = None # None = no explicit sources section in config
|
|
249
|
+
|
|
250
|
+
@model_validator(mode="after")
|
|
251
|
+
def _validate_theme_and_palette_contract(self) -> Config:
|
|
252
|
+
# themes dict may be empty now that chart_themes/ is removed; skip check
|
|
253
|
+
# The unified themes/*.yaml system is the source of truth for theme names.
|
|
254
|
+
category = self.palettes.get("category-10")
|
|
255
|
+
if not isinstance(category, list) or not category:
|
|
256
|
+
raise ValueError("palettes.category-10 must be present and non-empty")
|
|
257
|
+
return self
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class ConfigPatchBase(ConfigMappingBase):
|
|
261
|
+
"""Base class for dynamically-derived config patch models."""
|
|
262
|
+
|
|
263
|
+
model_config = ConfigDict(extra="forbid")
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class ConfigNodePatch(ConfigPatchBase):
|
|
267
|
+
"""Open-ended patch node for dynamic config sections."""
|
|
268
|
+
|
|
269
|
+
# Accepts arbitrary keys — patch nodes mirror the open-ended config tree.
|
|
270
|
+
model_config = ConfigDict(extra="allow")
|
|
271
|
+
|
|
272
|
+
@model_validator(mode="before")
|
|
273
|
+
@classmethod
|
|
274
|
+
def _normalize_input(cls, value: object) -> object:
|
|
275
|
+
if isinstance(value, ConfigNodePatch):
|
|
276
|
+
return value
|
|
277
|
+
if isinstance(value, Mapping):
|
|
278
|
+
return {key: _normalize_node_value(item) for key, item in value.items()}
|
|
279
|
+
return value
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def as_plain_mapping(value: ConfigMappingBase | Mapping[str, Any]) -> dict[str, Any]:
|
|
283
|
+
"""Project a compiled config model or raw mapping into a plain dict."""
|
|
284
|
+
if isinstance(value, ConfigMappingBase):
|
|
285
|
+
return value.to_plain_dict(exclude_none=False)
|
|
286
|
+
return dict(value)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def is_mapping_like(value: object) -> bool:
|
|
290
|
+
"""Return whether a value can be consumed through mapping helpers."""
|
|
291
|
+
return isinstance(value, ConfigMappingBase | Mapping)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _optional_annotation(annotation: Any) -> Any:
|
|
295
|
+
if annotation is Any:
|
|
296
|
+
return Any
|
|
297
|
+
if getattr(annotation, "__args__", ()) and type(None) in annotation.__args__:
|
|
298
|
+
return annotation
|
|
299
|
+
return annotation | None
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _patch_annotation(annotation: Any) -> Any:
|
|
303
|
+
# Style appears as Config.style. In the patch, accept any
|
|
304
|
+
# dict (e.g. {extends: "default"}) — the loader resolves it before
|
|
305
|
+
# Config.model_validate is called.
|
|
306
|
+
if annotation is Style:
|
|
307
|
+
return dict[str, Any]
|
|
308
|
+
if isinstance(annotation, type) and issubclass(annotation, ConfigNode):
|
|
309
|
+
return _build_patch_model(annotation)
|
|
310
|
+
if isinstance(annotation, type) and issubclass(annotation, ConfigMappingBase):
|
|
311
|
+
return _build_patch_model(annotation)
|
|
312
|
+
return annotation
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
@cache
|
|
316
|
+
def _build_patch_model(model_cls: type[ConfigMappingBase]) -> type[ConfigPatchBase]:
|
|
317
|
+
"""Create an all-optional patch model from a compiled config model.
|
|
318
|
+
|
|
319
|
+
Intentionally separate from compile.factories.build_patch_model.
|
|
320
|
+
Three models.config-specific behaviours make a shared factory impractical:
|
|
321
|
+
1. Base class: ConfigPatchBase/ConfigNodePatch (not _PatchBase).
|
|
322
|
+
2. ConfigNode short-circuit: returns ConfigNodePatch directly.
|
|
323
|
+
3. Style replacement: swaps Style → dict[str, Any] so
|
|
324
|
+
authored style: {extends: "..."} dicts pass before loader resolution.
|
|
325
|
+
"""
|
|
326
|
+
if model_cls is ConfigNode:
|
|
327
|
+
return ConfigNodePatch
|
|
328
|
+
|
|
329
|
+
fields: dict[str, tuple[Any, Any]] = {}
|
|
330
|
+
for name, field in model_cls.model_fields.items():
|
|
331
|
+
annotation = _optional_annotation(_patch_annotation(field.annotation))
|
|
332
|
+
field_kwargs: dict[str, Any] = {"default": None}
|
|
333
|
+
if field.alias and field.alias != name:
|
|
334
|
+
field_kwargs["alias"] = field.alias
|
|
335
|
+
fields[name] = (annotation, Field(**field_kwargs))
|
|
336
|
+
|
|
337
|
+
patch_name = "ConfigPatch" if model_cls is Config else f"{model_cls.__name__}Patch"
|
|
338
|
+
base_cls: type[ConfigPatchBase] = ConfigPatchBase
|
|
339
|
+
if issubclass(model_cls, ConfigNode):
|
|
340
|
+
base_cls = ConfigNodePatch
|
|
341
|
+
|
|
342
|
+
return create_model( # type: ignore[call-overload]
|
|
343
|
+
patch_name, __base__=base_cls, **fields
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
ConfigPatch = _build_patch_model(Config)
|
|
File without changes
|