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,221 @@
1
+ """Chat session API for the Dataface agent."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Generator
6
+ from dataclasses import dataclass, field
7
+ from datetime import datetime, timezone
8
+ from pathlib import Path
9
+ from typing import TYPE_CHECKING, Any
10
+
11
+ from dataface.agent_api._session_store import (
12
+ SessionIndex,
13
+ SessionWriter,
14
+ load_session_for_resume,
15
+ new_session,
16
+ )
17
+ from dataface.ai.agent import run_agent
18
+ from dataface.ai.context import DatafaceAIContext
19
+ from dataface.ai.events import AgentEvent
20
+ from dataface.ai.llm import create_client
21
+
22
+ if TYPE_CHECKING:
23
+ from dataface.ai.external_mcp import ExternalMCPManager
24
+
25
+
26
+ def _now_iso() -> str:
27
+ return datetime.now(tz=timezone.utc).astimezone().isoformat()
28
+
29
+
30
+ @dataclass
31
+ class ChatSession:
32
+ """Runtime handle for an active chat session."""
33
+
34
+ session_id: str
35
+ messages: list[dict[str, Any]]
36
+ context: DatafaceAIContext
37
+ model: str
38
+ created_at: str
39
+ last_used_at: str
40
+ client: Any = field(repr=False)
41
+ writer: SessionWriter = field(repr=False)
42
+
43
+
44
+ @dataclass
45
+ class ChatSessionSummary:
46
+ """Persisted metadata for a saved session."""
47
+
48
+ session_id: str
49
+ cwd: Path
50
+ started_at: str
51
+ model: str = ""
52
+
53
+
54
+ def start_session(
55
+ *,
56
+ model: str | None = None,
57
+ project_dir: Path | None = None,
58
+ server_port: int | None = None,
59
+ ) -> ChatSession:
60
+ """Create a new chat session.
61
+
62
+ Args:
63
+ model: LLM model name, optionally provider-prefixed.
64
+ project_dir: Working directory for the session. Defaults to cwd.
65
+ server_port: Port of the embedded HTTP preview server, if running.
66
+ """
67
+ from dataface.core.execute.adapters import (
68
+ LOCAL_AUTHORING_REGISTRY_KWARGS,
69
+ build_adapter_registry,
70
+ )
71
+
72
+ cwd = (project_dir or Path.cwd()).resolve()
73
+ client = create_client(model=model)
74
+ context = DatafaceAIContext(
75
+ adapter_registry=build_adapter_registry(
76
+ cwd,
77
+ **LOCAL_AUTHORING_REGISTRY_KWARGS,
78
+ ),
79
+ default_project_dir=cwd,
80
+ server_port=server_port,
81
+ )
82
+ writer, _ = new_session(cwd, provider=client.provider, model=client.model)
83
+ return ChatSession(
84
+ session_id=writer.session_id,
85
+ messages=[],
86
+ context=context,
87
+ model=client.model,
88
+ created_at=writer.started_at,
89
+ last_used_at=writer.started_at,
90
+ client=client,
91
+ writer=writer,
92
+ )
93
+
94
+
95
+ def resume_session(
96
+ session_id: str,
97
+ *,
98
+ project_dir: Path | None = None,
99
+ server_port: int | None = None,
100
+ model: str | None = None,
101
+ max_tokens: int = 32_000,
102
+ ) -> ChatSession:
103
+ """Load and resume a previously saved session.
104
+
105
+ Args:
106
+ session_id: The session id to resume.
107
+ project_dir: Working directory for the resumed session. Defaults to cwd.
108
+ server_port: Port of the embedded HTTP preview server, if running.
109
+ model: LLM model to use. Defaults to the same provider as the session.
110
+ max_tokens: Token budget for trimming old messages. 0 disables trimming.
111
+
112
+ Raises:
113
+ ValueError: If session not found, provider mismatch, or context window exceeded.
114
+ """
115
+ from dataface.core.execute.adapters import (
116
+ LOCAL_AUTHORING_REGISTRY_KWARGS,
117
+ build_adapter_registry,
118
+ )
119
+
120
+ cwd = (project_dir or Path.cwd()).resolve()
121
+ client = create_client(model=model)
122
+
123
+ messages, meta, _ = load_session_for_resume(
124
+ session_id,
125
+ expected_provider=client.provider,
126
+ max_tokens=max_tokens or None,
127
+ )
128
+
129
+ if client.provider == "openai" and _has_tool_history(messages):
130
+ raise ValueError(
131
+ f"Cannot resume session {session_id[:8]}: "
132
+ "OpenAI sessions with tool-call history cannot be resumed "
133
+ "(no previous_response_id chain). Start a new session."
134
+ )
135
+
136
+ context = DatafaceAIContext(
137
+ adapter_registry=build_adapter_registry(
138
+ cwd,
139
+ **LOCAL_AUTHORING_REGISTRY_KWARGS,
140
+ ),
141
+ default_project_dir=cwd,
142
+ server_port=server_port,
143
+ )
144
+ writer, _ = new_session(cwd, provider=client.provider, model=client.model)
145
+ return ChatSession(
146
+ session_id=session_id,
147
+ messages=messages,
148
+ context=context,
149
+ model=client.model,
150
+ created_at=meta.get("started_at", _now_iso()),
151
+ last_used_at=_now_iso(),
152
+ client=client,
153
+ writer=writer,
154
+ )
155
+
156
+
157
+ def send_message(
158
+ session: ChatSession,
159
+ prompt: str,
160
+ *,
161
+ tools: list[dict[str, Any]] | None = None,
162
+ external_manager: ExternalMCPManager | None = None,
163
+ ) -> Generator[AgentEvent, None, None]:
164
+ """Send a prompt and stream typed agent events.
165
+
166
+ Mutates ``session.messages`` in place (run_agent appends as it goes).
167
+ Persists the new messages to disk after the turn completes.
168
+
169
+ Yields:
170
+ AgentEvent instances (ContentDelta, ToolCallEvent, ToolResultEvent,
171
+ ThinkingStatus, AgentDone, AgentError).
172
+ """
173
+ msg_count_before = len(session.messages)
174
+ try:
175
+ yield from run_agent(
176
+ prompt,
177
+ client=session.client,
178
+ context=session.context,
179
+ messages=session.messages,
180
+ tools=tools,
181
+ external_manager=external_manager,
182
+ )
183
+ finally:
184
+ session.last_used_at = _now_iso()
185
+ new_msgs = session.messages[msg_count_before:]
186
+ if new_msgs:
187
+ session.writer.write_turn(new_msgs)
188
+
189
+
190
+ def list_sessions(*, owner: Path | None = None) -> list[ChatSessionSummary]:
191
+ """List all saved sessions.
192
+
193
+ A session-index entry missing or empty cwd indicates a corrupt index;
194
+ raise rather than coerce to Path(".") and mask the corruption.
195
+
196
+ Args:
197
+ owner: When set, filter to sessions whose cwd equals this path.
198
+ """
199
+ idx = SessionIndex()
200
+ entries = idx.list_all() if owner is None else idx.list_for_cwd(owner)
201
+ summaries: list[ChatSessionSummary] = []
202
+ for e in entries:
203
+ cwd = e.get("cwd", "")
204
+ if not cwd:
205
+ raise ValueError(
206
+ f"Session index entry {e.get('session_id', '?')} has no cwd; "
207
+ "the index is corrupt. Delete ~/.dft/sessions/index.json to rebuild."
208
+ )
209
+ summaries.append(
210
+ ChatSessionSummary(
211
+ session_id=e["session_id"],
212
+ cwd=Path(cwd),
213
+ started_at=e.get("started_at", ""),
214
+ model=e.get("model", ""),
215
+ )
216
+ )
217
+ return summaries
218
+
219
+
220
+ def _has_tool_history(messages: list[dict[str, Any]]) -> bool:
221
+ return any(m.get("role") == "tool" or bool(m.get("tool_calls")) for m in messages)
@@ -0,0 +1,257 @@
1
+ """Typed dashboard verbs for the Dataface agent API.
2
+
3
+ All public functions have concrete typed arguments and typed Pydantic return
4
+ values. No bare dict[str, Any] in any return position. MCP/CLI callers use
5
+ .model_dump() at the wire boundary.
6
+
7
+ `RenderedDashboard` and `render_dashboard` live in `dataface.core.dashboard`
8
+ so the embedded HTTP server can call them without inverting the layer stack; they
9
+ are re-exported here so the agent_api thin-wrapper rule still holds.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from pathlib import Path
15
+ from typing import Any, Literal
16
+
17
+ import yaml
18
+ from pydantic import BaseModel, Field
19
+
20
+ from dataface.agent_api._paths import resolve_scoped_path
21
+ from dataface.core.compile import Face, compile_file
22
+ from dataface.core.compile.errors import DatafaceError
23
+ from dataface.core.dashboard import (
24
+ RenderedDashboard as RenderedDashboard,
25
+ render_dashboard as render_dashboard,
26
+ )
27
+ from dataface.core.errors import DF_UNKNOWN_INTERNAL, StructuredError
28
+ from dataface.core.render.warnings.base import RenderWarning
29
+
30
+ # ---------------------------------------------------------------------------
31
+ # Return-type models
32
+ # ---------------------------------------------------------------------------
33
+
34
+
35
+ class DashboardSummary(BaseModel):
36
+ path: Path
37
+ absolute_path: Path
38
+ title: str
39
+ description: str = ""
40
+ queries: list[str] = []
41
+ charts: list[str] = []
42
+ variables: list[str] = []
43
+
44
+
45
+ class SkippedFile(BaseModel):
46
+ path: Path
47
+ reason: str
48
+
49
+
50
+ class ListDashboardsResult(BaseModel):
51
+ success: bool
52
+ errors: list[StructuredError] = []
53
+ dashboards: list[DashboardSummary] = []
54
+ count: int = 0
55
+ directory: Path
56
+ skipped_files: list[SkippedFile] = []
57
+
58
+
59
+ class CompiledDashboard(BaseModel):
60
+ success: bool
61
+ dashboard: Face | None = None
62
+ errors: list[StructuredError] = []
63
+ warnings: list[RenderWarning] = []
64
+ raw_yaml: str | None = None
65
+
66
+
67
+ class RenderDashboardArgs(BaseModel):
68
+ """Validate, compile, and render a Dataface dashboard, returning resolved chart semantics + executed data for reasoning. Use this to verify YAML is valid, inspect query results, and iterate on a dashboard. When 'path' is provided, the response also includes a localhost URL the user can open in a browser to view the live dashboard (the embedded HTTP server runs alongside `dft mcp serve`). Pass `as_link=true` with a path to skip execution and return only the preview URL."""
69
+
70
+ path: Path | None = Field(
71
+ None, description="Path to dashboard YAML file (use this OR yaml_content)"
72
+ )
73
+ yaml_content: str | None = Field(
74
+ None, description="YAML content to render directly (use this OR path)"
75
+ )
76
+ project_dir: Path | None = Field(
77
+ None, description="Project root for resolving relative paths"
78
+ )
79
+ variables: dict[str, Any] | None = Field(
80
+ None, description="Variable values to apply to the dashboard"
81
+ )
82
+ format: Literal["json", "text", "yaml", "svg"] | None = Field(
83
+ None,
84
+ description=(
85
+ "Output format. 'json' (default) returns resolved chart "
86
+ "semantics and executed data as structured JSON. 'text' "
87
+ "returns a compact markdown summary of charts and data "
88
+ "(most token-efficient). 'yaml' returns resolved Dataface "
89
+ "YAML with inline data — valid input for re-compilation, "
90
+ "ideal for round-trip editing. 'svg' returns the rendered "
91
+ "dashboard as inline SVG (under result['data']) for hosts "
92
+ "that embed the rendered output directly."
93
+ ),
94
+ )
95
+ as_link: bool = Field(
96
+ False,
97
+ description=(
98
+ "When true and 'path' is provided, skip query execution and return only "
99
+ "the preview URL. Use this to surface an existing dashboard in the browser "
100
+ "without paying the render cost — replaces the old view_dashboard tool."
101
+ ),
102
+ )
103
+
104
+
105
+ # ---------------------------------------------------------------------------
106
+ # Public verbs
107
+ # ---------------------------------------------------------------------------
108
+
109
+
110
+ def list_dashboards(
111
+ directory: Path = Path("."),
112
+ recursive: bool = True,
113
+ ) -> ListDashboardsResult:
114
+ """List all available dashboards in a directory."""
115
+ dir_path = directory.resolve()
116
+
117
+ if not dir_path.exists():
118
+ return ListDashboardsResult(
119
+ success=False,
120
+ errors=[
121
+ DatafaceError.from_code(
122
+ DF_UNKNOWN_INTERNAL,
123
+ message=f"Directory not found: {directory}",
124
+ ).to_structured()
125
+ ],
126
+ directory=dir_path,
127
+ )
128
+ if not dir_path.is_dir():
129
+ return ListDashboardsResult(
130
+ success=False,
131
+ errors=[
132
+ DatafaceError.from_code(
133
+ DF_UNKNOWN_INTERNAL,
134
+ message=f"Not a directory: {directory}",
135
+ ).to_structured()
136
+ ],
137
+ directory=dir_path,
138
+ )
139
+
140
+ pattern = "**/*.yml" if recursive else "*.yml"
141
+ yaml_files = list(dir_path.glob(pattern))
142
+ yaml_files.extend(dir_path.glob(pattern.replace(".yml", ".yaml")))
143
+
144
+ dashboards: list[DashboardSummary] = []
145
+ skipped: list[SkippedFile] = []
146
+
147
+ for yaml_file in sorted(yaml_files):
148
+ if yaml_file.name.startswith("_"):
149
+ continue
150
+ try:
151
+ content = yaml.safe_load(yaml_file.read_text())
152
+ if not isinstance(content, dict):
153
+ skipped.append(
154
+ SkippedFile(
155
+ path=yaml_file.relative_to(dir_path),
156
+ reason="Not a YAML mapping",
157
+ )
158
+ )
159
+ continue
160
+ dashboard_keys = {"queries", "charts", "rows", "cols", "grid", "tabs"}
161
+ if not any(key in content for key in dashboard_keys):
162
+ continue
163
+ dashboards.append(
164
+ DashboardSummary(
165
+ path=yaml_file.relative_to(dir_path),
166
+ absolute_path=yaml_file,
167
+ title=content.get("title", yaml_file.stem),
168
+ description=content.get("description", ""),
169
+ queries=list(content.get("queries", {}).keys()),
170
+ charts=list(content.get("charts", {}).keys()),
171
+ variables=list(content.get("variables", {}).keys()),
172
+ )
173
+ )
174
+ except yaml.YAMLError as e:
175
+ skipped.append(
176
+ SkippedFile(
177
+ path=yaml_file.relative_to(dir_path),
178
+ reason=f"YAML parse error: {e}",
179
+ )
180
+ )
181
+ except OSError as e:
182
+ skipped.append(
183
+ SkippedFile(
184
+ path=yaml_file.relative_to(dir_path),
185
+ reason=f"Read error: {e}",
186
+ )
187
+ )
188
+
189
+ return ListDashboardsResult(
190
+ success=True,
191
+ dashboards=dashboards,
192
+ count=len(dashboards),
193
+ directory=dir_path,
194
+ skipped_files=skipped,
195
+ )
196
+
197
+
198
+ def get_dashboard(
199
+ path: Path,
200
+ include_raw: bool = False,
201
+ project_dir: Path | None = None,
202
+ ) -> CompiledDashboard:
203
+ """Get the compiled structure of a dashboard."""
204
+ try:
205
+ file_path = resolve_scoped_path(path, project_dir)
206
+ except ValueError as exc:
207
+ return CompiledDashboard(
208
+ success=False,
209
+ errors=[
210
+ DatafaceError.from_code(
211
+ DF_UNKNOWN_INTERNAL, message=str(exc)
212
+ ).to_structured()
213
+ ],
214
+ )
215
+
216
+ if not file_path.exists():
217
+ return CompiledDashboard(
218
+ success=False,
219
+ errors=[
220
+ DatafaceError.from_code(
221
+ DF_UNKNOWN_INTERNAL,
222
+ message=f"File not found: {path}",
223
+ ).to_structured(file=str(file_path))
224
+ ],
225
+ )
226
+ if not file_path.is_file():
227
+ return CompiledDashboard(
228
+ success=False,
229
+ errors=[
230
+ DatafaceError.from_code(
231
+ DF_UNKNOWN_INTERNAL,
232
+ message=f"Not a file: {path}",
233
+ ).to_structured(file=str(file_path))
234
+ ],
235
+ )
236
+
237
+ try:
238
+ raw_yaml = file_path.read_text()
239
+ except OSError as e:
240
+ return CompiledDashboard(
241
+ success=False,
242
+ errors=[
243
+ DatafaceError.from_code(
244
+ DF_UNKNOWN_INTERNAL,
245
+ message=f"Failed to read file: {e}",
246
+ ).to_structured(file=str(file_path))
247
+ ],
248
+ )
249
+
250
+ result = compile_file(file_path)
251
+ return CompiledDashboard(
252
+ success=result.success,
253
+ dashboard=result.face if result.success else None,
254
+ errors=list(result.errors),
255
+ warnings=result.warnings,
256
+ raw_yaml=raw_yaml if include_raw else None,
257
+ )