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,354 @@
1
+ """Profile rendering module.
2
+
3
+ Stage: INSPECT
4
+ Purpose: Shared rendering logic for inspect dashboards.
5
+
6
+ This module provides the core rendering function used by both:
7
+ - CLI: `dft inspect <table> --format html`
8
+ - Server: `dft serve` (via core/serve/server.py)
9
+
10
+ The renderer substitutes string {{ }} vars in the template YAML, then
11
+ compiles and renders it as HTML. Schema-shaped panels query the
12
+ LayeredSchemaResolver in-process via the `schema_resolver` face query type.
13
+
14
+ M2 contract: templates contain only string {{ }} vars — no document-level
15
+ {% %} Jinja. Substitution uses simple string replacement for the declared
16
+ set of inspect vars; the schema_resolver compile validator enforces that no
17
+ {{ }} remain after substitution.
18
+ """
19
+
20
+ import re
21
+ from pathlib import Path
22
+ from typing import Any
23
+
24
+ from dataface.core.compile import CompileResult, compile
25
+ from dataface.core.execute import Executor
26
+ from dataface.core.execute.adapters import build_adapter_registry
27
+ from dataface.core.execute.adapters.sql_adapter import SqlAdapter
28
+ from dataface.core.inspect.cache_factory import make_cache_source_for_project
29
+ from dataface.core.inspect.resolver import LayeredSchemaResolver
30
+ from dataface.core.render import render
31
+
32
+ # Valid identifier pattern for SQL safety
33
+ _VALID_IDENTIFIER = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")
34
+ _PATH_VAR_KEYS = {"connection"}
35
+
36
+ # Source name the renderer registers when no project _sources.yaml exists.
37
+ # Templates reference this name through the `source_name` Jinja var; an
38
+ # explicit project source by the same name wins (register_source uses
39
+ # set-if-absent semantics).
40
+ _DEFAULT_SOURCE_NAME = "warehouse"
41
+
42
+ # The vars the renderer substitutes directly into the template YAML before
43
+ # compile(). schema_resolver fields reject {{ }} Jinja, so these must be
44
+ # literal strings in the compiled YAML. The set is fixed and declared here;
45
+ # adding a new schema_resolver field requires adding it here.
46
+ _SCHEMA_RESOLVER_VARS = ("model", "column", "connection", "source_name", "schema_name")
47
+
48
+
49
+ class InspectProfileCompileError(Exception):
50
+ """Inspect template failed compilation."""
51
+
52
+ def __init__(self, result: CompileResult) -> None:
53
+ self.result = result
54
+ error_msg = (
55
+ "; ".join(e.message for e in result.errors)
56
+ if result.errors
57
+ else "Unknown error"
58
+ )
59
+ super().__init__(f"Failed to compile profile template: {error_msg}")
60
+
61
+
62
+ def validate_inspect_variables(variables: dict[str, Any]) -> dict[str, Any]:
63
+ """Validate and sanitize profile variables.
64
+
65
+ Ensures variables are safe to use in SQL queries by:
66
+ - Checking that model/column names are valid SQL identifiers
67
+ - Converting all values to strings
68
+ - Rejecting potentially dangerous inputs
69
+
70
+ Args:
71
+ variables: Raw variables from URL params or CLI
72
+
73
+ Returns:
74
+ Sanitized variables (all string values)
75
+
76
+ Raises:
77
+ ValueError: If variables contain invalid values
78
+ """
79
+ sanitized: dict[str, Any] = {}
80
+
81
+ for key, value in variables.items():
82
+ # Convert to string
83
+ str_value = str(value) if value is not None else ""
84
+
85
+ # Validate SQL identifiers (model, column names)
86
+ if (
87
+ key in ("model", "column")
88
+ and str_value
89
+ and not _VALID_IDENTIFIER.match(str_value)
90
+ ):
91
+ raise ValueError(
92
+ f"Invalid {key} name: '{str_value}'. "
93
+ "Must be a valid SQL identifier (letters, numbers, underscores)."
94
+ )
95
+
96
+ # Validate file path variables — no shell metacharacters or traversal
97
+ if key in _PATH_VAR_KEYS and str_value and str_value != ":memory:":
98
+ if re.search(r"[;&|`$(){}]", str_value):
99
+ raise ValueError(
100
+ f"Invalid {key}: '{str_value}'. Contains disallowed characters."
101
+ )
102
+ if ".." in str_value:
103
+ raise ValueError(
104
+ f"Invalid {key}: '{str_value}'. Path traversal is not allowed."
105
+ )
106
+
107
+ sanitized[key] = str_value
108
+
109
+ # The renderer always overrides ``source_name`` / ``schema_name`` from
110
+ # project-root below. Drop any caller-supplied values so a URL like
111
+ # ``?schema_name=anything-goes`` can't smuggle a string into the rendered YAML.
112
+ for stripped_key in ("source_name", "schema_name"):
113
+ sanitized.pop(stripped_key, None)
114
+
115
+ return sanitized
116
+
117
+
118
+ def _substitute_template_vars(template_yaml: str, vars: dict[str, str]) -> str:
119
+ """Substitute declared inspect vars into the template YAML.
120
+
121
+ Only substitutes the vars named in ``_SCHEMA_RESOLVER_VARS``; the
122
+ schema_resolver compile validator rejects any remaining ``{{ }}`` Jinja
123
+ in its fields, so unknown vars cause a compile error rather than silent
124
+ pass-through.
125
+
126
+ Args:
127
+ template_yaml: Raw template YAML with ``{{ var_name }}`` placeholders.
128
+ vars: Resolved variable values (all string).
129
+
130
+ Returns:
131
+ Template YAML with placeholders replaced by literal values.
132
+ """
133
+ result = template_yaml
134
+ for key in _SCHEMA_RESOLVER_VARS:
135
+ value = vars.get(key, "")
136
+ result = result.replace("{{ " + key + " }}", value)
137
+ result = result.replace("{{" + key + "}}", value)
138
+ return result
139
+
140
+
141
+ def _resolve_table_schema(
142
+ resolver: LayeredSchemaResolver,
143
+ source_name: str,
144
+ model_name: str,
145
+ ) -> str:
146
+ """Return the schema containing ``model_name``.
147
+
148
+ Two-pass strategy that keeps the render path safe for every dialect:
149
+
150
+ Pass 1 — cache only (via ``resolver.cache``): no adapter calls, works for
151
+ every dialect including non-DuckDB warehouses where the adapter may refuse
152
+ to connect. Returns immediately when the cache has the answer.
153
+
154
+ Pass 2 — full resolver walk (via ``resolver.list_schemas`` /
155
+ ``list_tables``): runs only when the cache pass found nothing. The resolver
156
+ uses cache-first per-target logic, so cached tables are still served without
157
+ a second adapter round-trip. Adapter calls happen here for cold-start DuckDB
158
+ tables that were never profiled.
159
+
160
+ First-match semantics: cache iteration order, then dbt-schema order.
161
+
162
+ Args:
163
+ resolver: LayeredSchemaResolver that owns both the cache and the adapter.
164
+ source_name: Named source registered with the adapter registry.
165
+ model_name: Bare table/model name to look up.
166
+
167
+ Returns:
168
+ Schema name string, or ``""`` when no match is found or the source is
169
+ unreachable.
170
+ """
171
+ if not source_name:
172
+ return ""
173
+
174
+ def _safe_schema(name: str) -> str:
175
+ """Return ``name`` only when it's a valid SQL identifier, else ``""``."""
176
+ return name if name and _VALID_IDENTIFIER.match(name) else ""
177
+
178
+ # Cache-first pass: when a warm SuperSchemaSource is available, look up the
179
+ # schema without adapter calls. This path is only hit when the caller injects
180
+ # a cache (e.g. Cloud/IDE with dataface-super-schema). The OSS renderer builds
181
+ # without a cache (cache=None), so this block is skipped in the OSS path.
182
+ if resolver.cache is not None:
183
+ cache_schemas = resolver.cache.list_schemas()
184
+ if cache_schemas is not None:
185
+ for schema in cache_schemas.get("schemas", {}):
186
+ cache_tables = resolver.cache.list_tables(schema)
187
+ if cache_tables is not None and model_name in cache_tables.get(
188
+ "tables", {}
189
+ ):
190
+ return _safe_schema(schema)
191
+
192
+ # Adapter walk: needed for cold start or when no cache is present.
193
+ try:
194
+ schemas_result = resolver.list_schemas(source_name)
195
+ except Exception: # noqa: BLE001 — renderer best-effort; fall back to ""
196
+ return ""
197
+ schema_names = list(
198
+ schemas_result.get("sources", {}).get(source_name, {}).get("schemas", {})
199
+ )
200
+ for schema in schema_names:
201
+ try:
202
+ tables_result = resolver.list_tables(source_name, schema)
203
+ except Exception: # noqa: BLE001 — renderer best-effort; per-schema
204
+ continue
205
+ tables = (
206
+ tables_result.get("sources", {})
207
+ .get(source_name, {})
208
+ .get("schemas", {})
209
+ .get(schema, {})
210
+ .get("tables", {})
211
+ )
212
+ if model_name in tables:
213
+ return _safe_schema(schema)
214
+ return ""
215
+
216
+
217
+ def _ensure_default_source(
218
+ adapter_registry: Any,
219
+ connection: str | None,
220
+ dialect: str,
221
+ ) -> None:
222
+ """Register a synthetic ``warehouse`` source when none are configured.
223
+
224
+ The schema_resolver query type requires a named source registered with
225
+ the adapter registry. Inspect-server projects often have no
226
+ ``_sources.yaml`` — they're spun up against a single connection. To
227
+ keep the rewire working for that case we synthesize a default named
228
+ source from the active connection. An explicit project-source named
229
+ ``warehouse`` always wins (``register_source`` is idempotent on name).
230
+
231
+ Only DuckDB connections are synthesized here — other dialects require
232
+ credentials that cannot be derived from a bare connection URL; callers
233
+ that need schema_resolver on non-DuckDB must configure the source in
234
+ ``_sources.yaml``.
235
+ """
236
+ if adapter_registry.list_sql_sources():
237
+ return
238
+ # Only DuckDB connection URLs are self-contained enough to synthesize a
239
+ # valid source config from. Non-DuckDB dialects (Snowflake, Postgres, etc.)
240
+ # require credentials not present in the URL; callers that need
241
+ # schema_resolver on non-DuckDB must configure the source in _sources.yaml.
242
+ if dialect != "duckdb":
243
+ return
244
+ fallback_connection: str | None = connection
245
+ if fallback_connection is None:
246
+ for adapter in adapter_registry.adapters:
247
+ if isinstance(adapter, SqlAdapter):
248
+ fallback_connection = adapter.connection_string
249
+ break
250
+ if fallback_connection is None:
251
+ return
252
+ # source_config_from_url lives in the private package — use a minimal
253
+ # inline DuckDB config so the renderer works without the profiler.
254
+ adapter_registry.register_source(
255
+ _DEFAULT_SOURCE_NAME,
256
+ {"type": "duckdb", "path": fallback_connection},
257
+ )
258
+
259
+
260
+ def _resolve_source_name(adapter_registry: Any) -> str:
261
+ """Pick the source the inspect templates query for schema-shaped data."""
262
+ sources = adapter_registry.list_sql_sources()
263
+ if not sources:
264
+ return ""
265
+ for entry in sources:
266
+ if entry["name"] == _DEFAULT_SOURCE_NAME:
267
+ return _DEFAULT_SOURCE_NAME
268
+ return str(sources[0]["name"])
269
+
270
+
271
+ def render_inspect_dashboard(
272
+ template_yaml: str,
273
+ variables: dict[str, Any],
274
+ project_root: Path | None = None,
275
+ connection: str | None = None,
276
+ dialect: str = "duckdb",
277
+ ) -> str:
278
+ """Render a profile template to HTML.
279
+
280
+ Substitutes string {{ }} vars into the template YAML (M2: no block-tag
281
+ Jinja), compiles it, and renders it as HTML. ``source_name`` and
282
+ ``schema_name`` are resolved from the LayeredSchemaResolver (which uses
283
+ the cache when present, falls through to dbt/adapter when absent);
284
+ caller-supplied values for those keys are silently dropped to prevent URL
285
+ parameter injection.
286
+
287
+ Args:
288
+ template_yaml: YAML template content with string {{ }} placeholders
289
+ variables: Variables to substitute in the template
290
+ project_root: Project root for resolving relative paths
291
+ connection: Database connection string override
292
+ dialect: Database dialect for the registered SQL adapter — also
293
+ picked up by the synthetic ``warehouse`` source when no
294
+ project sources are configured.
295
+
296
+ Returns:
297
+ Rendered HTML string
298
+
299
+ Raises:
300
+ InspectProfileCompileError: If compilation fails
301
+ """
302
+ safe_vars = validate_inspect_variables(variables)
303
+
304
+ resolved_project_root = project_root or Path.cwd()
305
+ registry_kwargs: dict[str, Any] = {"read_only": True}
306
+ if connection:
307
+ registry_kwargs["connection_string"] = connection
308
+ registry_kwargs["profile_type"] = dialect
309
+ adapter_registry = build_adapter_registry(resolved_project_root, **registry_kwargs)
310
+ _ensure_default_source(adapter_registry, connection, dialect)
311
+ safe_vars["source_name"] = _resolve_source_name(adapter_registry)
312
+
313
+ # Use warm cache when dataface-super-schema is installed; fall back to
314
+ # dbt-only resolver (cache=None) when it is not. The cache enriches
315
+ # schema_resolver panels for non-DuckDB warehouses where the adapter
316
+ # can't connect; without the private package, those panels degrade.
317
+ cache = make_cache_source_for_project(resolved_project_root)
318
+ resolver = LayeredSchemaResolver(
319
+ cache=cache,
320
+ adapter_registry=adapter_registry,
321
+ project_root=resolved_project_root,
322
+ )
323
+ model_name = safe_vars.get("model", "")
324
+ safe_vars["schema_name"] = (
325
+ _resolve_table_schema(resolver, safe_vars["source_name"], model_name)
326
+ if model_name
327
+ else ""
328
+ )
329
+
330
+ # Substitute the schema_resolver vars into the YAML before compile().
331
+ # schema_resolver fields reject {{ }} Jinja — they must be literal strings.
332
+ safe_vars.setdefault("connection", ":memory:")
333
+ substituted_yaml = _substitute_template_vars(template_yaml, safe_vars)
334
+
335
+ result = compile(substituted_yaml, project_dir=project_root)
336
+ if result.errors or not result.face:
337
+ raise InspectProfileCompileError(result=result)
338
+
339
+ executor = Executor(
340
+ result.face,
341
+ adapter_registry=adapter_registry,
342
+ query_registry=result.query_registry,
343
+ project_root=project_root,
344
+ )
345
+
346
+ html_output = render(
347
+ result.face, executor, format="html", variables=safe_vars
348
+ ).output
349
+
350
+ if html_output is None:
351
+ return ""
352
+ if isinstance(html_output, bytes):
353
+ return html_output.decode("utf-8")
354
+ return html_output