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.
Files changed (455) hide show
  1. d3_format/__init__.py +14 -0
  2. d3_format/errors.py +19 -0
  3. d3_format/format.py +551 -0
  4. d3_format/spec.py +159 -0
  5. dataface/DATAFACE_SYNTAX.md +1135 -0
  6. dataface/__init__.py +93 -0
  7. dataface/_docs_site.py +20 -0
  8. dataface/_install_hint.py +26 -0
  9. dataface/agent_api/__init__.py +79 -0
  10. dataface/agent_api/_init_templates/__init__.py +0 -0
  11. dataface/agent_api/_init_templates/agents_dft_snippet.md +26 -0
  12. dataface/agent_api/_init_templates/dataface.yml +15 -0
  13. dataface/agent_api/_init_templates/faces-dataface.yml +144 -0
  14. dataface/agent_api/_init_templates/index.md +24 -0
  15. dataface/agent_api/_paths.py +118 -0
  16. dataface/agent_api/_project_agents_md.py +43 -0
  17. dataface/agent_api/_session_store.py +486 -0
  18. dataface/agent_api/_state.py +28 -0
  19. dataface/agent_api/chat.py +221 -0
  20. dataface/agent_api/dashboards.py +257 -0
  21. dataface/agent_api/describe.py +366 -0
  22. dataface/agent_api/describe_query.py +120 -0
  23. dataface/agent_api/docs/__init__.py +25 -0
  24. dataface/agent_api/docs/_loader.py +292 -0
  25. dataface/agent_api/docs/yaml-reference.md +2757 -0
  26. dataface/agent_api/file_refs.py +118 -0
  27. dataface/agent_api/init.py +126 -0
  28. dataface/agent_api/inspect.py +128 -0
  29. dataface/agent_api/mcp_install.py +170 -0
  30. dataface/agent_api/query.py +274 -0
  31. dataface/agent_api/schema.py +658 -0
  32. dataface/agent_api/schema_search.py +284 -0
  33. dataface/agent_api/search.py +270 -0
  34. dataface/agent_api/skill_install.py +141 -0
  35. dataface/agent_api/skill_render.py +90 -0
  36. dataface/agent_api/skills.py +293 -0
  37. dataface/agent_api/surface_aliases.yaml +128 -0
  38. dataface/agent_api/validate.py +175 -0
  39. dataface/agent_api/validate_query.py +84 -0
  40. dataface/ai/__init__.py +39 -0
  41. dataface/ai/agent.py +139 -0
  42. dataface/ai/context.py +45 -0
  43. dataface/ai/events.py +62 -0
  44. dataface/ai/external_mcp.py +610 -0
  45. dataface/ai/generate_sql.py +96 -0
  46. dataface/ai/llm.py +403 -0
  47. dataface/ai/mcp/__init__.py +51 -0
  48. dataface/ai/mcp/server.py +289 -0
  49. dataface/ai/memories.py +85 -0
  50. dataface/ai/prompts.py +177 -0
  51. dataface/ai/schema_context.py +138 -0
  52. dataface/ai/skills/before-after-comparison/SKILL.md +102 -0
  53. dataface/ai/skills/before-after-comparison/examples/before-after-comparison.yml +24 -0
  54. dataface/ai/skills/dashboard-build/SKILL.md +212 -0
  55. dataface/ai/skills/dashboard-build/examples/_smoke.yml +15 -0
  56. dataface/ai/skills/dashboard-design/SKILL.md +182 -0
  57. dataface/ai/skills/dashboard-review/SKILL.md +113 -0
  58. dataface/ai/skills/dashboard-structural-review/SKILL.md +173 -0
  59. dataface/ai/skills/dashboard-visual-review/SKILL.md +139 -0
  60. dataface/ai/skills/dataface-mcp-setup/SKILL.md +177 -0
  61. dataface/ai/skills/dataface-troubleshooting/SKILL.md +225 -0
  62. dataface/ai/skills/drill-down-link/SKILL.md +112 -0
  63. dataface/ai/skills/drill-down-link/examples/drill-down-link.yml +27 -0
  64. dataface/ai/skills/faceted-small-multiples/SKILL.md +116 -0
  65. dataface/ai/skills/faceted-small-multiples/examples/faceted-small-multiples.yml +33 -0
  66. dataface/ai/skills/filter-bar-with-variables/SKILL.md +105 -0
  67. dataface/ai/skills/filter-bar-with-variables/examples/filter-bar-with-variables.yml +49 -0
  68. dataface/ai/skills/kpi-row/SKILL.md +101 -0
  69. dataface/ai/skills/kpi-row/examples/kpi-row.yml +55 -0
  70. dataface/ai/skills/report-design/SKILL.md +184 -0
  71. dataface/ai/skills/single-metric-bignum/SKILL.md +90 -0
  72. dataface/ai/skills/single-metric-bignum/examples/single-metric-bignum.yml +27 -0
  73. dataface/ai/skills/table-heavy-ops-dashboard/SKILL.md +114 -0
  74. dataface/ai/skills/table-heavy-ops-dashboard/examples/table-heavy-ops-dashboard.yml +48 -0
  75. dataface/ai/skills/time-series-trend/SKILL.md +93 -0
  76. dataface/ai/skills/time-series-trend/examples/time-series-trend.yml +26 -0
  77. dataface/ai/skills/top-n-with-detail/SKILL.md +98 -0
  78. dataface/ai/skills/top-n-with-detail/examples/top-n-with-detail.yml +45 -0
  79. dataface/ai/skills/two-by-two-grid-overview/SKILL.md +78 -0
  80. dataface/ai/skills/two-by-two-grid-overview/examples/two-by-two-grid-overview.yml +64 -0
  81. dataface/ai/tool_schemas.py +132 -0
  82. dataface/ai/tools/__init__.py +312 -0
  83. dataface/ai/yaml_utils.py +57 -0
  84. dataface/cli/__init__.py +3 -0
  85. dataface/cli/_console.py +48 -0
  86. dataface/cli/_error_format.py +83 -0
  87. dataface/cli/_extras.py +190 -0
  88. dataface/cli/_json_output.py +8 -0
  89. dataface/cli/_parsing.py +17 -0
  90. dataface/cli/_version_info.py +56 -0
  91. dataface/cli/commands/__init__.py +3 -0
  92. dataface/cli/commands/_agent_input.py +205 -0
  93. dataface/cli/commands/_agent_server.py +115 -0
  94. dataface/cli/commands/chat.py +645 -0
  95. dataface/cli/commands/describe.py +107 -0
  96. dataface/cli/commands/docs.py +131 -0
  97. dataface/cli/commands/extension.py +179 -0
  98. dataface/cli/commands/init.py +240 -0
  99. dataface/cli/commands/inspect.py +94 -0
  100. dataface/cli/commands/mcp_init.py +167 -0
  101. dataface/cli/commands/query.py +386 -0
  102. dataface/cli/commands/render.py +291 -0
  103. dataface/cli/commands/schema.py +411 -0
  104. dataface/cli/commands/search.py +49 -0
  105. dataface/cli/commands/serve.py +114 -0
  106. dataface/cli/commands/skills.py +133 -0
  107. dataface/cli/commands/skills_init.py +161 -0
  108. dataface/cli/commands/validate.py +63 -0
  109. dataface/cli/main.py +1501 -0
  110. dataface/core/__init__.py +75 -0
  111. dataface/core/compile/__init__.py +244 -0
  112. dataface/core/compile/_jinja_helpers.py +78 -0
  113. dataface/core/compile/channel.py +222 -0
  114. dataface/core/compile/chart_focus.py +101 -0
  115. dataface/core/compile/chart_resolved.py +169 -0
  116. dataface/core/compile/chart_type_detection.py +489 -0
  117. dataface/core/compile/chart_update.py +261 -0
  118. dataface/core/compile/colors.py +64 -0
  119. dataface/core/compile/compiler.py +904 -0
  120. dataface/core/compile/config.py +823 -0
  121. dataface/core/compile/custom_chart_types.py +208 -0
  122. dataface/core/compile/data_table_attachment.py +1287 -0
  123. dataface/core/compile/detect.py +110 -0
  124. dataface/core/compile/errors.py +302 -0
  125. dataface/core/compile/filter_injection.py +319 -0
  126. dataface/core/compile/introspection.py +527 -0
  127. dataface/core/compile/jinja.py +511 -0
  128. dataface/core/compile/labels_env.py +52 -0
  129. dataface/core/compile/markdown.py +154 -0
  130. dataface/core/compile/meta.py +388 -0
  131. dataface/core/compile/models/__init__.py +0 -0
  132. dataface/core/compile/models/chart/__init__.py +0 -0
  133. dataface/core/compile/models/chart/authored.py +2137 -0
  134. dataface/core/compile/models/chart/compiled.py +398 -0
  135. dataface/core/compile/models/config.py +347 -0
  136. dataface/core/compile/models/face/__init__.py +0 -0
  137. dataface/core/compile/models/face/authored.py +659 -0
  138. dataface/core/compile/models/face/compiled.py +522 -0
  139. dataface/core/compile/models/factories.py +201 -0
  140. dataface/core/compile/models/markers.py +40 -0
  141. dataface/core/compile/models/palette.py +36 -0
  142. dataface/core/compile/models/primitives.py +415 -0
  143. dataface/core/compile/models/query/__init__.py +0 -0
  144. dataface/core/compile/models/query/authored.py +246 -0
  145. dataface/core/compile/models/query/compiled.py +710 -0
  146. dataface/core/compile/models/refs.py +137 -0
  147. dataface/core/compile/models/source.py +611 -0
  148. dataface/core/compile/models/style/__init__.py +0 -0
  149. dataface/core/compile/models/style/authored.py +481 -0
  150. dataface/core/compile/models/style/compiled.py +3399 -0
  151. dataface/core/compile/models/style/merged.py +1682 -0
  152. dataface/core/compile/models/theme.py +362 -0
  153. dataface/core/compile/models/variable/__init__.py +0 -0
  154. dataface/core/compile/models/variable/authored.py +254 -0
  155. dataface/core/compile/models/vega_lite/__init__.py +0 -0
  156. dataface/core/compile/models/vega_lite/config.py +510 -0
  157. dataface/core/compile/models/vega_lite/contracts.py +171 -0
  158. dataface/core/compile/normalize_charts.py +494 -0
  159. dataface/core/compile/normalize_layout.py +1000 -0
  160. dataface/core/compile/normalize_queries.py +297 -0
  161. dataface/core/compile/normalize_variables.py +489 -0
  162. dataface/core/compile/normalizer.py +543 -0
  163. dataface/core/compile/palette.py +1100 -0
  164. dataface/core/compile/parameterized.py +658 -0
  165. dataface/core/compile/parser.py +228 -0
  166. dataface/core/compile/schema.py +20 -0
  167. dataface/core/compile/schema_renderers/__init__.py +0 -0
  168. dataface/core/compile/schema_renderers/json_schema.py +163 -0
  169. dataface/core/compile/schema_renderers/prompt.py +152 -0
  170. dataface/core/compile/schema_renderers/vscode_schema.py +301 -0
  171. dataface/core/compile/sizing.py +2126 -0
  172. dataface/core/compile/sources.py +518 -0
  173. dataface/core/compile/sql_authoring_lint.py +56 -0
  174. dataface/core/compile/style_cascade.py +471 -0
  175. dataface/core/compile/typography.py +299 -0
  176. dataface/core/compile/validator.py +301 -0
  177. dataface/core/compile/variables.py +53 -0
  178. dataface/core/compile/vega_config.py +98 -0
  179. dataface/core/compile/vega_lite/__init__.py +6 -0
  180. dataface/core/compile/vega_lite/validation.py +95 -0
  181. dataface/core/compile/yaml_error_formatter.py +838 -0
  182. dataface/core/connections.py +38 -0
  183. dataface/core/dashboard.py +358 -0
  184. dataface/core/defaults/default_config.yml +101 -0
  185. dataface/core/defaults/palettes/categorical/category-10-dark.yml +32 -0
  186. dataface/core/defaults/palettes/categorical/category-10-light.yml +43 -0
  187. dataface/core/defaults/palettes/categorical/category-10.yml +31 -0
  188. dataface/core/defaults/palettes/categorical/category-6-tonal-blue.yml +22 -0
  189. dataface/core/defaults/palettes/categorical/category-6-tonal-brown.yml +29 -0
  190. dataface/core/defaults/palettes/categorical/category-6-tonal-green.yml +20 -0
  191. dataface/core/defaults/palettes/categorical/category-6-tonal-orange.yml +21 -0
  192. dataface/core/defaults/palettes/categorical/category-6-tonal-purple.yml +20 -0
  193. dataface/core/defaults/palettes/categorical/editorial-10-dark.yml +32 -0
  194. dataface/core/defaults/palettes/categorical/editorial-10.yml +40 -0
  195. dataface/core/defaults/palettes/categorical/hero-6.yml +17 -0
  196. dataface/core/defaults/palettes/categorical/single-blue.yml +11 -0
  197. dataface/core/defaults/palettes/categorical/tableau.yml +20 -0
  198. dataface/core/defaults/palettes/data/xkcd_colors.json +3803 -0
  199. dataface/core/defaults/palettes/diverging/blue-red.yml +25 -0
  200. dataface/core/defaults/palettes/diverging/coolwarm.yml +24 -0
  201. dataface/core/defaults/palettes/diverging/crimson-green.yml +23 -0
  202. dataface/core/defaults/palettes/diverging/orange-teal.yml +23 -0
  203. dataface/core/defaults/palettes/diverging/sunset.yml +24 -0
  204. dataface/core/defaults/palettes/scaffold/dft-creams.yml +38 -0
  205. dataface/core/defaults/palettes/scaffold/dft-grays.yml +53 -0
  206. dataface/core/defaults/palettes/sequential/amber.yml +22 -0
  207. dataface/core/defaults/palettes/sequential/blue.yml +22 -0
  208. dataface/core/defaults/palettes/sequential/brown.yml +22 -0
  209. dataface/core/defaults/palettes/sequential/gray.yml +22 -0
  210. dataface/core/defaults/palettes/sequential/green.yml +22 -0
  211. dataface/core/defaults/palettes/sequential/purple.yml +22 -0
  212. dataface/core/defaults/palettes/sequential/rust.yml +22 -0
  213. dataface/core/defaults/palettes/sequential/teal.yml +22 -0
  214. dataface/core/defaults/palettes/tone/negative.yml +32 -0
  215. dataface/core/defaults/palettes/tone/positive.yml +22 -0
  216. dataface/core/defaults/palettes/tone/warning.yml +22 -0
  217. dataface/core/defaults/themes/_base.yaml +786 -0
  218. dataface/core/defaults/themes/bi.yaml +16 -0
  219. dataface/core/defaults/themes/carbong100.yaml +41 -0
  220. dataface/core/defaults/themes/cream.yaml +122 -0
  221. dataface/core/defaults/themes/dark.yaml +40 -0
  222. dataface/core/defaults/themes/diagnostics-title-angle-extreme.yaml +9 -0
  223. dataface/core/defaults/themes/diagnostics-title-baseline-extreme.yaml +9 -0
  224. dataface/core/defaults/themes/diagnostics-title-baseline.yaml +24 -0
  225. dataface/core/defaults/themes/diagnostics-title-center.yaml +8 -0
  226. dataface/core/defaults/themes/diagnostics-title-color-extreme.yaml +24 -0
  227. dataface/core/defaults/themes/diagnostics-title-font-extreme.yaml +25 -0
  228. dataface/core/defaults/themes/diagnostics-title-left.yaml +8 -0
  229. dataface/core/defaults/themes/diagnostics-title-offset-extreme.yaml +9 -0
  230. dataface/core/defaults/themes/diagnostics-title-size-extreme.yaml +24 -0
  231. dataface/core/defaults/themes/diagnostics-title-weight-extreme.yaml +24 -0
  232. dataface/core/defaults/themes/editorial.yaml +147 -0
  233. dataface/core/defaults/themes/light.yaml +30 -0
  234. dataface/core/defaults/themes/looker.yaml +17 -0
  235. dataface/core/defaults/themes/stark.yaml +134 -0
  236. dataface/core/errors/__init__.py +67 -0
  237. dataface/core/errors/codes_compile.py +56 -0
  238. dataface/core/errors/codes_execute.py +177 -0
  239. dataface/core/errors/codes_render.py +106 -0
  240. dataface/core/errors/codes_unknown.py +15 -0
  241. dataface/core/errors/hints.py +74 -0
  242. dataface/core/errors/registry.py +42 -0
  243. dataface/core/errors/structured.py +92 -0
  244. dataface/core/execute/__init__.py +91 -0
  245. dataface/core/execute/adapters/__init__.py +49 -0
  246. dataface/core/execute/adapters/adapter_registry.py +400 -0
  247. dataface/core/execute/adapters/base.py +245 -0
  248. dataface/core/execute/adapters/csv_adapter.py +239 -0
  249. dataface/core/execute/adapters/dbt_adapter.py +283 -0
  250. dataface/core/execute/adapters/dbt_adapter_factory.py +212 -0
  251. dataface/core/execute/adapters/dbt_macro_loader.py +95 -0
  252. dataface/core/execute/adapters/dbt_utils.py +150 -0
  253. dataface/core/execute/adapters/http_adapter.py +224 -0
  254. dataface/core/execute/adapters/metricflow_adapter.py +94 -0
  255. dataface/core/execute/adapters/schema_resolver_adapter.py +144 -0
  256. dataface/core/execute/adapters/sql_adapter.py +710 -0
  257. dataface/core/execute/adapters/values_adapter.py +58 -0
  258. dataface/core/execute/batch.py +744 -0
  259. dataface/core/execute/cache_backend.py +135 -0
  260. dataface/core/execute/cache_keys.py +66 -0
  261. dataface/core/execute/dbt_jinja.py +21 -0
  262. dataface/core/execute/dialects/__init__.py +121 -0
  263. dataface/core/execute/dialects/athena.py +75 -0
  264. dataface/core/execute/dialects/base.py +302 -0
  265. dataface/core/execute/dialects/bigquery.py +38 -0
  266. dataface/core/execute/dialects/databricks.py +68 -0
  267. dataface/core/execute/dialects/duckdb.py +35 -0
  268. dataface/core/execute/dialects/mysql.py +68 -0
  269. dataface/core/execute/dialects/postgres.py +39 -0
  270. dataface/core/execute/dialects/redshift.py +12 -0
  271. dataface/core/execute/dialects/snowflake.py +51 -0
  272. dataface/core/execute/dialects/sqlserver.py +92 -0
  273. dataface/core/execute/duckdb_cache.py +712 -0
  274. dataface/core/execute/duckdb_config.py +26 -0
  275. dataface/core/execute/errors.py +213 -0
  276. dataface/core/execute/executor.py +1249 -0
  277. dataface/core/execute/parallel.py +162 -0
  278. dataface/core/execute/setup_sql.py +58 -0
  279. dataface/core/execute/source_registry.py +72 -0
  280. dataface/core/execute/source_resolver.py +255 -0
  281. dataface/core/execute/sql_guard.py +387 -0
  282. dataface/core/execute/sql_literals.py +199 -0
  283. dataface/core/fonts.py +52 -0
  284. dataface/core/inspect/__init__.py +32 -0
  285. dataface/core/inspect/cache_factory.py +98 -0
  286. dataface/core/inspect/db_types.py +162 -0
  287. dataface/core/inspect/dbt_schema.py +96 -0
  288. dataface/core/inspect/defaults.yml +37 -0
  289. dataface/core/inspect/fanout_risk.py +109 -0
  290. dataface/core/inspect/manifest_utils.py +77 -0
  291. dataface/core/inspect/partials/categorical.yml +40 -0
  292. dataface/core/inspect/partials/date.yml +40 -0
  293. dataface/core/inspect/partials/numeric.yml +55 -0
  294. dataface/core/inspect/partition_types.py +38 -0
  295. dataface/core/inspect/query_validator.py +975 -0
  296. dataface/core/inspect/renderer.py +354 -0
  297. dataface/core/inspect/resolver.py +808 -0
  298. dataface/core/inspect/search.py +461 -0
  299. dataface/core/inspect/sources/__init__.py +32 -0
  300. dataface/core/inspect/sources/dbt.py +738 -0
  301. dataface/core/inspect/sources/duckdb_utils.py +66 -0
  302. dataface/core/inspect/templates/__init__.py +1 -0
  303. dataface/core/inspect/templates/categorical_column.yml +196 -0
  304. dataface/core/inspect/templates/charts.yml +109 -0
  305. dataface/core/inspect/templates/date_column.yml +248 -0
  306. dataface/core/inspect/templates/model.yml +138 -0
  307. dataface/core/inspect/templates/numeric_column.yml +261 -0
  308. dataface/core/inspect/templates/quality.yml +80 -0
  309. dataface/core/inspect/templates/string_column.yml +263 -0
  310. dataface/core/project_roots.py +165 -0
  311. dataface/core/render/__init__.py +87 -0
  312. dataface/core/render/board_links.py +176 -0
  313. dataface/core/render/chart/__init__.py +27 -0
  314. dataface/core/render/chart/arc_attached_table.py +251 -0
  315. dataface/core/render/chart/artifacts.py +16 -0
  316. dataface/core/render/chart/callout.py +225 -0
  317. dataface/core/render/chart/decisions.py +358 -0
  318. dataface/core/render/chart/geo.py +700 -0
  319. dataface/core/render/chart/kpi.py +916 -0
  320. dataface/core/render/chart/labels.py +76 -0
  321. dataface/core/render/chart/pipeline.py +818 -0
  322. dataface/core/render/chart/presentation.py +36 -0
  323. dataface/core/render/chart/profile.py +3438 -0
  324. dataface/core/render/chart/render_single.py +347 -0
  325. dataface/core/render/chart/renderers.py +193 -0
  326. dataface/core/render/chart/rendering.py +565 -0
  327. dataface/core/render/chart/serialization.py +90 -0
  328. dataface/core/render/chart/spark.py +496 -0
  329. dataface/core/render/chart/spark_bar.py +370 -0
  330. dataface/core/render/chart/spec_builders.py +154 -0
  331. dataface/core/render/chart/standard_renderer.py +2645 -0
  332. dataface/core/render/chart/table.py +2957 -0
  333. dataface/core/render/chart/table_support.py +1452 -0
  334. dataface/core/render/chart/tick_values.py +66 -0
  335. dataface/core/render/chart/time_unit_detect.py +809 -0
  336. dataface/core/render/chart/title_overflow.py +157 -0
  337. dataface/core/render/chart/type_inference.py +122 -0
  338. dataface/core/render/chart/validation.py +99 -0
  339. dataface/core/render/chart/vega_lite.py +125 -0
  340. dataface/core/render/chart/vega_lite_types.py +268 -0
  341. dataface/core/render/chart/vl_field_maps.py +346 -0
  342. dataface/core/render/chart_interactivity.py +24 -0
  343. dataface/core/render/control_registry.py +287 -0
  344. dataface/core/render/converters/__init__.py +24 -0
  345. dataface/core/render/converters/chart.py +276 -0
  346. dataface/core/render/converters/html.py +98 -0
  347. dataface/core/render/converters/pdf.py +40 -0
  348. dataface/core/render/converters/png.py +41 -0
  349. dataface/core/render/errors.py +144 -0
  350. dataface/core/render/face_api.py +160 -0
  351. dataface/core/render/faces.py +1194 -0
  352. dataface/core/render/font_measurement.py +48 -0
  353. dataface/core/render/font_support.py +197 -0
  354. dataface/core/render/fonts/DFTSansTabular-Regular.ttf +0 -0
  355. dataface/core/render/fonts/DFTSansTabular-Regular.woff2 +0 -0
  356. dataface/core/render/fonts/DFTSerifOldstyleProportional-Regular.ttf +0 -0
  357. dataface/core/render/fonts/DFTSerifOldstyleTabular-Regular.ttf +0 -0
  358. dataface/core/render/fonts/InterVariable.ttf +0 -0
  359. dataface/core/render/fonts/InterVariable.woff2 +0 -0
  360. dataface/core/render/fonts/NOTO_COLOR_EMOJI_LICENSE.txt +93 -0
  361. dataface/core/render/fonts/NOTO_EMOJI_LICENSE.txt +93 -0
  362. dataface/core/render/fonts/NotoColorEmoji-Regular.ttf +0 -0
  363. dataface/core/render/fonts/NotoColorEmoji-Regular.woff2 +0 -0
  364. dataface/core/render/fonts/NotoEmoji-Regular.ttf +0 -0
  365. dataface/core/render/fonts/NotoEmoji-Regular.woff2 +0 -0
  366. dataface/core/render/fonts/SOURCE_CODE_PRO_LICENSE.txt +93 -0
  367. dataface/core/render/fonts/SOURCE_SERIF_4_LICENSE.txt +98 -0
  368. dataface/core/render/fonts/SourceCodePro-Regular.ttf +0 -0
  369. dataface/core/render/fonts/SourceSerif4-Regular.ttf +0 -0
  370. dataface/core/render/fonts/_emoji_font_face.css +43 -0
  371. dataface/core/render/fonts/source-serif-4-variable-latin.woff2 +0 -0
  372. dataface/core/render/format_utils.py +329 -0
  373. dataface/core/render/geo_defaults.yml +28 -0
  374. dataface/core/render/json_format.py +146 -0
  375. dataface/core/render/layout_sizing.py +865 -0
  376. dataface/core/render/layouts.py +541 -0
  377. dataface/core/render/markdown_defaults.yml +16 -0
  378. dataface/core/render/missing_vars_prompt.py +79 -0
  379. dataface/core/render/placeholder.py +389 -0
  380. dataface/core/render/render_result.py +14 -0
  381. dataface/core/render/renderer.py +467 -0
  382. dataface/core/render/script_embedding.py +16 -0
  383. dataface/core/render/svg_utils.py +212 -0
  384. dataface/core/render/template_loader.py +69 -0
  385. dataface/core/render/templates/controls/_styles.css +606 -0
  386. dataface/core/render/templates/controls/checkbox.html +16 -0
  387. dataface/core/render/templates/controls/date.html +16 -0
  388. dataface/core/render/templates/controls/number.html +19 -0
  389. dataface/core/render/templates/controls/readonly.html +9 -0
  390. dataface/core/render/templates/controls/select.html +21 -0
  391. dataface/core/render/templates/controls/slider.html +22 -0
  392. dataface/core/render/templates/controls/text.html +16 -0
  393. dataface/core/render/templates/scripts/chart_interactivity.js +191 -0
  394. dataface/core/render/templates/scripts/variables.js +976 -0
  395. dataface/core/render/templates/svg/grid_pattern.svg +3 -0
  396. dataface/core/render/templates/svg/styles.css +51 -0
  397. dataface/core/render/terminal.py +311 -0
  398. dataface/core/render/terminal_charts.py +563 -0
  399. dataface/core/render/terminal_defaults.yml +2 -0
  400. dataface/core/render/terminal_layouts.py +299 -0
  401. dataface/core/render/terminal_text.py +31 -0
  402. dataface/core/render/text/__init__.py +1 -0
  403. dataface/core/render/text/case.py +113 -0
  404. dataface/core/render/text_format.py +129 -0
  405. dataface/core/render/utils.py +106 -0
  406. dataface/core/render/variable_controls.py +946 -0
  407. dataface/core/render/variable_input_refinement.py +140 -0
  408. dataface/core/render/warnings/__init__.py +15 -0
  409. dataface/core/render/warnings/bar_color_1_to_1_with_x.py +80 -0
  410. dataface/core/render/warnings/base.py +44 -0
  411. dataface/core/render/warnings/fanout_risk.py +15 -0
  412. dataface/core/render/warnings/from_query_diagnostic.py +56 -0
  413. dataface/core/render/warnings/missing_join_predicate.py +13 -0
  414. dataface/core/render/warnings/query_parse_error.py +14 -0
  415. dataface/core/render/warnings/query_returned_zero_rows.py +42 -0
  416. dataface/core/render/warnings/reaggregation.py +14 -0
  417. dataface/core/render/warnings/registry.py +45 -0
  418. dataface/core/render/warnings/suppression.py +46 -0
  419. dataface/core/render/warnings/temporal_single_point.py +63 -0
  420. dataface/core/render/warnings/unreferenced_chart.py +15 -0
  421. dataface/core/render/warnings/y_encoding_mostly_null.py +76 -0
  422. dataface/core/render/yaml_format.py +167 -0
  423. dataface/core/resolve_face.py +195 -0
  424. dataface/core/schema/__init__.py +0 -0
  425. dataface/core/schema/guidance.py +151 -0
  426. dataface/core/scoped_paths.py +59 -0
  427. dataface/core/serve/__init__.py +14 -0
  428. dataface/core/serve/bootstrap.py +39 -0
  429. dataface/core/serve/embedded.py +57 -0
  430. dataface/core/serve/port.py +129 -0
  431. dataface/core/serve/server.py +938 -0
  432. dataface/core/serve/templates/__init__.py +0 -0
  433. dataface/core/serve/templates/directory.yml +6 -0
  434. dataface/core/serve/templates/error.html.j2 +217 -0
  435. dataface/core/utils.py +121 -0
  436. dataface/core/validate.py +64 -0
  437. dataface/integrations/__init__.py +0 -0
  438. dataface/integrations/highlighting.py +351 -0
  439. dataface/integrations/markdown.py +537 -0
  440. dataface/py.typed +0 -0
  441. dataface-0.1.2.dist-info/METADATA +375 -0
  442. dataface-0.1.2.dist-info/RECORD +455 -0
  443. dataface-0.1.2.dist-info/WHEEL +4 -0
  444. dataface-0.1.2.dist-info/entry_points.txt +2 -0
  445. dataface-0.1.2.dist-info/licenses/LICENSE +202 -0
  446. mdsvg/__init__.py +168 -0
  447. mdsvg/fonts.py +656 -0
  448. mdsvg/images.py +299 -0
  449. mdsvg/parser.py +629 -0
  450. mdsvg/playground.py +284 -0
  451. mdsvg/py.typed +2 -0
  452. mdsvg/renderer.py +1623 -0
  453. mdsvg/style.py +355 -0
  454. mdsvg/types.py +200 -0
  455. mdsvg/utils.py +86 -0
@@ -0,0 +1,389 @@
1
+ """Placeholder data generation for charts without queries.
2
+
3
+ Stage: RENDER
4
+ Purpose: Generate appropriate dummy/placeholder data for charts without queries.
5
+
6
+ This module provides:
7
+ - generate_placeholder_data(chart_type, chart): Generate dummy data for a chart type
8
+ - is_placeholder_needed(chart, data): Detect when placeholder should be used
9
+ - add_placeholder_overlay(svg, width, height): Add "add data" overlay to SVG
10
+
11
+ The placeholder feature helps users:
12
+ - Build datafaces iteratively (design first, connect data later)
13
+ - See what charts will look like before writing SQL
14
+ - Use the playground for learning/experimentation
15
+
16
+ Visual Treatment:
17
+ - Placeholder charts render with ~40% opacity (high transparency)
18
+ - "add data" text overlay centered on the chart
19
+ - Makes it obvious this is placeholder state, not real data
20
+ """
21
+
22
+ import re
23
+ from typing import TYPE_CHECKING, Any
24
+
25
+ if TYPE_CHECKING:
26
+ from dataface.core.compile.models.chart.compiled import (
27
+ Chart,
28
+ )
29
+ from dataface.core.compile.models.primitives import FontStyle
30
+
31
+
32
+ def generate_placeholder_data(
33
+ chart_type: str | None,
34
+ chart: "Chart | Any | None" = None,
35
+ ) -> list[dict[str, Any]]:
36
+ """Generate appropriate placeholder/dummy data for a chart type.
37
+
38
+ The data generated depends on the chart type:
39
+ - Bar/Column: Categorical + numeric data
40
+ - Line/Area: Time series-like data with month labels
41
+ - Scatter/Point: Two numeric columns (x, y)
42
+ - Pie: Categorical + numeric proportions
43
+ - Table: Multi-column sample data
44
+ - KPI: Single numeric value
45
+ - Histogram: Numeric values for binning
46
+ - Heatmap: X, Y, Value grid data
47
+
48
+ Args:
49
+ chart_type: The type of chart (bar, line, table, etc.)
50
+ chart: Optional Chart to extract field names from
51
+
52
+ Returns:
53
+ List of dicts containing placeholder data appropriate for the chart type.
54
+ Data is consistent (not random) for predictable rendering.
55
+
56
+ """
57
+ # Extract field names from chart config if provided
58
+ x_field = "category"
59
+ y_field = "value"
60
+ if chart:
61
+ x_field = chart.x or "category"
62
+ y_raw = chart.y
63
+ if isinstance(y_raw, list):
64
+ y_field = y_raw[0] if y_raw else "value"
65
+ elif y_raw:
66
+ y_field = y_raw
67
+ else:
68
+ y_field = "value"
69
+
70
+ # Normalize chart type to lowercase, handling None, empty, and whitespace
71
+ chart_type = (
72
+ chart_type.strip().lower() if chart_type and chart_type.strip() else "bar"
73
+ )
74
+
75
+ # Bar chart (default) - categorical + numeric
76
+ if chart_type in ("bar", "column"):
77
+ return _generate_bar_placeholder(x_field, y_field)
78
+
79
+ # Line and area charts - time series
80
+ if chart_type in ("line", "area"):
81
+ return _generate_line_placeholder(x_field, y_field)
82
+
83
+ # Scatter and circle charts - two numeric columns
84
+ # Use "x" and "y" as defaults for scatter if not specified
85
+ if chart_type in ("scatter", "circle"):
86
+ scatter_x = x_field if x_field != "category" else "x"
87
+ scatter_y = y_field if y_field != "value" else "y"
88
+ return _generate_scatter_placeholder(scatter_x, scatter_y)
89
+
90
+ # Pie charts - proportional data
91
+ if chart_type in ("pie", "arc"):
92
+ return _generate_pie_placeholder(x_field, y_field)
93
+
94
+ # Table - multi-column sample data
95
+ if chart_type == "table":
96
+ return _generate_table_placeholder()
97
+
98
+ # KPI - single value
99
+ if chart_type == "kpi":
100
+ return _generate_kpi_placeholder(y_field)
101
+
102
+ # Histogram - numeric values for binning
103
+ if chart_type == "histogram":
104
+ return _generate_histogram_placeholder()
105
+
106
+ # Boxplot - grouped numeric values
107
+ if chart_type == "boxplot":
108
+ return _generate_boxplot_placeholder(x_field, y_field)
109
+
110
+ # Heatmap/Rect - grid data
111
+ if chart_type in ("heatmap", "rect"):
112
+ return _generate_heatmap_placeholder()
113
+
114
+ # Spark bar - compact horizontal bars for profiler cards
115
+ if chart_type == "spark_bar":
116
+ return _generate_spark_bar_placeholder(x_field, y_field)
117
+
118
+ # Default fallback to bar chart data
119
+ return _generate_bar_placeholder(x_field, y_field)
120
+
121
+
122
+ def _generate_bar_placeholder(x_field: str, y_field: str) -> list[dict[str, Any]]:
123
+ """Generate placeholder data for bar charts."""
124
+ return [
125
+ {x_field: "Category A", y_field: 100},
126
+ {x_field: "Category B", y_field: 75},
127
+ {x_field: "Category C", y_field: 50},
128
+ {x_field: "Category D", y_field: 85},
129
+ {x_field: "Category E", y_field: 60},
130
+ ]
131
+
132
+
133
+ def _generate_line_placeholder(x_field: str, y_field: str) -> list[dict[str, Any]]:
134
+ """Generate placeholder data for line/area charts."""
135
+ # Use month names for time-like x axis
136
+ time_field = x_field if x_field != "category" else "month"
137
+ return [
138
+ {time_field: "Jan", y_field: 10},
139
+ {time_field: "Feb", y_field: 25},
140
+ {time_field: "Mar", y_field: 40},
141
+ {time_field: "Apr", y_field: 35},
142
+ {time_field: "May", y_field: 50},
143
+ {time_field: "Jun", y_field: 45},
144
+ {time_field: "Jul", y_field: 60},
145
+ ]
146
+
147
+
148
+ def _generate_scatter_placeholder(
149
+ x_field: str = "x",
150
+ y_field: str = "y",
151
+ ) -> list[dict[str, Any]]:
152
+ """Generate placeholder data for scatter/point charts."""
153
+ # Generate a pattern of points
154
+ return [
155
+ {x_field: 10, y_field: 20},
156
+ {x_field: 25, y_field: 45},
157
+ {x_field: 35, y_field: 30},
158
+ {x_field: 50, y_field: 60},
159
+ {x_field: 65, y_field: 55},
160
+ {x_field: 75, y_field: 80},
161
+ {x_field: 90, y_field: 70},
162
+ {x_field: 40, y_field: 50},
163
+ {x_field: 55, y_field: 40},
164
+ {x_field: 80, y_field: 90},
165
+ ]
166
+
167
+
168
+ def _generate_pie_placeholder(x_field: str, y_field: str) -> list[dict[str, Any]]:
169
+ """Generate placeholder data for pie charts."""
170
+ cat_field = x_field if x_field != "category" else "category"
171
+ return [
172
+ {cat_field: "Segment A", y_field: 40},
173
+ {cat_field: "Segment B", y_field: 30},
174
+ {cat_field: "Segment C", y_field: 20},
175
+ {cat_field: "Segment D", y_field: 10},
176
+ ]
177
+
178
+
179
+ def _generate_table_placeholder() -> list[dict[str, Any]]:
180
+ """Generate placeholder data for tables."""
181
+ return [
182
+ {"name": "Sample Item 1", "value": 123, "status": "Active"},
183
+ {"name": "Sample Item 2", "value": 456, "status": "Pending"},
184
+ {"name": "Sample Item 3", "value": 789, "status": "Active"},
185
+ {"name": "Sample Item 4", "value": 234, "status": "Inactive"},
186
+ {"name": "Sample Item 5", "value": 567, "status": "Active"},
187
+ ]
188
+
189
+
190
+ def _generate_kpi_placeholder(value_field: str) -> list[dict[str, Any]]:
191
+ """Generate placeholder data for KPI charts."""
192
+ return [{value_field: 1234}]
193
+
194
+
195
+ def _generate_histogram_placeholder() -> list[dict[str, Any]]:
196
+ """Generate placeholder data for histograms."""
197
+ # Generate values that will bin nicely
198
+
199
+ values = []
200
+ # Create a distribution-like pattern
201
+ for i in range(50):
202
+ # Bell curve-ish distribution centered around 50
203
+ val = 50 + (i % 10 - 5) * 5 + (i // 10 - 2) * 3
204
+ values.append({"value": max(0, min(100, val))})
205
+ return values
206
+
207
+
208
+ def _generate_boxplot_placeholder(x_field: str, y_field: str) -> list[dict[str, Any]]:
209
+ """Generate placeholder data for boxplots."""
210
+ cat_field = x_field if x_field != "category" else "category"
211
+ data = []
212
+ # Generate data for 3 categories with different distributions
213
+ for cat, base in [("Group A", 50), ("Group B", 70), ("Group C", 40)]:
214
+ for offset in [-20, -10, -5, 0, 5, 10, 20, 25, -15, 15]:
215
+ data.append({cat_field: cat, y_field: base + offset})
216
+ return data
217
+
218
+
219
+ def _generate_heatmap_placeholder() -> list[dict[str, Any]]:
220
+ """Generate placeholder data for heatmaps."""
221
+ data = []
222
+ rows = ["Row A", "Row B", "Row C", "Row D"]
223
+ cols = ["Col 1", "Col 2", "Col 3", "Col 4"]
224
+ # Generate a pattern of values
225
+ values = [
226
+ [80, 60, 40, 20],
227
+ [70, 90, 50, 30],
228
+ [40, 50, 80, 60],
229
+ [30, 40, 60, 90],
230
+ ]
231
+ for i, row in enumerate(rows):
232
+ for j, col in enumerate(cols):
233
+ data.append({"y": row, "x": col, "value": values[i][j]})
234
+ return data
235
+
236
+
237
+ def _generate_spark_bar_placeholder(x_field: str, y_field: str) -> list[dict[str, Any]]:
238
+ """Generate placeholder data for spark bar charts."""
239
+ # Use appropriate field names - y is category, x is frequency
240
+ cat_field = y_field if y_field != "value" else "value"
241
+ freq_field = x_field if x_field != "category" else "frequency"
242
+ return [
243
+ {cat_field: "Category A", freq_field: 100},
244
+ {cat_field: "Category B", freq_field: 75},
245
+ {cat_field: "Category C", freq_field: 50},
246
+ {cat_field: "Category D", freq_field: 35},
247
+ {cat_field: "Category E", freq_field: 20},
248
+ ]
249
+
250
+
251
+ def is_placeholder_needed(
252
+ chart: "Chart",
253
+ data: list[dict[str, Any]] | None = None,
254
+ ) -> bool:
255
+ """Determine if a chart needs placeholder data.
256
+
257
+ A chart needs placeholder data when:
258
+ - It has no query defined (chart.query is None)
259
+
260
+ Note: If a chart HAS a query but returns empty results, we do NOT use
261
+ placeholder data - instead, the renderer should show "No data" message.
262
+ This distinguishes between:
263
+ - Design mode (no query yet) → show placeholder
264
+ - Query ran but found nothing → show "No data" message
265
+
266
+ Args:
267
+ chart: Chart to check
268
+ data: Query results (if already executed) - unused, kept for API compatibility
269
+
270
+ Returns:
271
+ True if placeholder should be used (no query defined), False otherwise
272
+
273
+ """
274
+ # Only use placeholder when chart has no query defined
275
+ # If a query exists but returns empty results, that's a "no data" case, not placeholder
276
+ if chart.type == "callout":
277
+ return False
278
+ return chart.query is None
279
+
280
+
281
+ def add_placeholder_overlay(
282
+ svg: str,
283
+ width: float,
284
+ height: float,
285
+ font: "FontStyle",
286
+ text: str | None = None,
287
+ ) -> str:
288
+ """Add placeholder overlay to an SVG chart.
289
+
290
+ Adds:
291
+ 1. A semi-transparent white overlay rectangle
292
+ 2. "add data" text centered on the chart
293
+
294
+ The overlay makes it clear the chart is showing placeholder data.
295
+
296
+ Args:
297
+ svg: The SVG string to add overlay to
298
+ width: Chart width in pixels
299
+ height: Chart height in pixels
300
+ font: FontStyle for the overlay text (reads .family)
301
+ text: Text to display (default: "add data")
302
+
303
+ Returns:
304
+ SVG string with overlay added
305
+
306
+ """
307
+ import html as html_module
308
+
309
+ from dataface.core.compile.config import get_config
310
+
311
+ overlay = get_config().style.placeholder.overlay
312
+ font_family = html_module.escape(font.family or "")
313
+ display_text = text if text is not None else overlay.text
314
+ _overlay_case = font.case
315
+ if _overlay_case is not None and _overlay_case != "none":
316
+ from dataface.core.render.text.case import apply_case
317
+
318
+ display_text = apply_case(display_text, _overlay_case)
319
+
320
+ # Calculate center position
321
+ center_x = width / 2
322
+ center_y = height / 2
323
+
324
+ # Escape text for safety
325
+ escaped_text = html_module.escape(display_text)
326
+
327
+ # Create overlay elements
328
+ # Semi-transparent overlay rectangle
329
+ overlay_rect = (
330
+ f'<rect x="0" y="0" width="{width}" height="{height}" '
331
+ f'fill="{overlay.background}" pointer-events="none"/>'
332
+ )
333
+
334
+ # Text element centered on chart
335
+ overlay_text = (
336
+ f'<text x="{center_x}" y="{center_y}" '
337
+ f'text-anchor="middle" dominant-baseline="middle" '
338
+ f'font-family="{font_family}" '
339
+ f'font-size="{overlay.font.size}" font-weight="{overlay.font.weight}" fill="{overlay.font.color}" '
340
+ f'pointer-events="none">'
341
+ f"{escaped_text}"
342
+ f"</text>"
343
+ )
344
+
345
+ # Create overlay group
346
+ overlay_group = f'<g class="placeholder-overlay">{overlay_rect}{overlay_text}</g>'
347
+
348
+ # Insert overlay before closing </svg> tag
349
+ # Use rfind to only replace the LAST </svg> (handles nested SVGs correctly)
350
+ if svg.endswith("</svg>"):
351
+ svg = svg[:-6] + overlay_group + "</svg>"
352
+ elif "</svg>" in svg:
353
+ idx = svg.rfind("</svg>")
354
+ svg = svg[:idx] + overlay_group + svg[idx:]
355
+ else:
356
+ # If no closing tag found, append
357
+ svg = svg + overlay_group
358
+
359
+ return svg
360
+
361
+
362
+ def apply_placeholder_opacity(svg: str, opacity: float | None = None) -> str:
363
+ """Apply reduced opacity to SVG content for placeholder appearance.
364
+
365
+ Wraps the SVG content in a group with reduced opacity to make it
366
+ appear faded/disabled.
367
+
368
+ Args:
369
+ svg: The SVG string to modify
370
+ opacity: Opacity value (0.0-1.0), defaults to config placeholder opacity
371
+
372
+ Returns:
373
+ SVG string with opacity applied to content
374
+
375
+ """
376
+ from dataface.core.compile.config import get_config
377
+
378
+ effective_opacity = (
379
+ opacity if opacity is not None else get_config().style.placeholder.opacity
380
+ )
381
+
382
+ # Extract SVG parts directly - typical for Vega-Lite output (flat structure)
383
+ match = re.search(r"(<svg[^>]*>)(.*)(</svg>)", svg, re.DOTALL)
384
+ if not match:
385
+ return svg
386
+
387
+ opening_tag, content, closing_tag = match.groups()
388
+ wrapped_content = f'<g opacity="{effective_opacity}">{content}</g>'
389
+ return f"{opening_tag}{wrapped_content}{closing_tag}"
@@ -0,0 +1,14 @@
1
+ """RenderResult — the return type of render()."""
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from dataface.core.errors import StructuredError
6
+ from dataface.core.render.warnings.base import RenderWarning
7
+
8
+
9
+ class RenderResult(BaseModel):
10
+ output: str | bytes | None = None
11
+ chart_errors: list[StructuredError] = []
12
+ face_error: StructuredError | None = None
13
+ render_warnings: list[RenderWarning] = []
14
+ suppressed_warnings: list[RenderWarning] = []