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,245 @@
1
+ """Base adapter interface for query execution.
2
+
3
+ Stage: EXECUTE
4
+ Purpose: Define the base interface and types for query adapters.
5
+
6
+ All adapters inherit from BaseAdapter and implement the unified query interface.
7
+ QueryResult is the standard return type for all adapter executions.
8
+
9
+ The unified interface uses:
10
+ - `supported_types` property: Set of query types this adapter handles
11
+ - `can_execute()`: Uses supported_types for type-based routing
12
+ - `execute()`: Executes the query using type guards for type safety
13
+
14
+ Security:
15
+ - Adapters support parameterized queries via the optional `params` argument
16
+ - When params are provided, values are passed to the database driver separately
17
+ from the SQL, preventing SQL injection
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from abc import ABC, abstractmethod
23
+ from dataclasses import dataclass
24
+ from typing import TYPE_CHECKING, Any, Literal
25
+
26
+ from dataface.core.compile.models.face.compiled import VariableValues
27
+ from dataface.core.compile.models.query.compiled import AnyQuery
28
+
29
+ if TYPE_CHECKING:
30
+ from dataface.core.compile.models.source import SourceConfig
31
+
32
+ # Type alias for query parameters
33
+ QueryParams = list[Any] | None
34
+
35
+ SchemaStatus = Literal["changed", "unchanged", "unknown"]
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class ResolvedRelation:
40
+ """A dbt ref/source resolved during query execution.
41
+
42
+ Tracks which schema each relation resolved to and whether it
43
+ differs from the production baseline (changed vs unchanged).
44
+ """
45
+
46
+ ref_name: str
47
+ schema: str
48
+ status: SchemaStatus
49
+
50
+
51
+ class QueryResult:
52
+ """Result of a query execution.
53
+
54
+ This is the standard return type for all adapter executions, providing
55
+ a consistent interface for data retrieval and error handling.
56
+
57
+ Attributes:
58
+ data: List of dictionaries containing query results (each dict is a row)
59
+ columns: List of column names
60
+ column_descriptions: Full PEP 249 cursor.description tuples keyed by column name.
61
+ Each tuple: (name, type_code, display_size, internal_size, precision, scale, null_ok)
62
+ error: Error message if query failed, None if successful
63
+ """
64
+
65
+ def __init__(
66
+ self,
67
+ data: list[dict[str, Any]],
68
+ columns: list[str] | None = None,
69
+ column_descriptions: dict[str, tuple] | None = None,
70
+ error: str | None = None,
71
+ resolved_relations: list[ResolvedRelation] | None = None,
72
+ ):
73
+ """Initialize query result.
74
+
75
+ Args:
76
+ data: List of dictionaries containing query results (each dict is a row)
77
+ columns: Optional list of column names (inferred from data if not provided)
78
+ column_descriptions: Optional PEP 249 cursor.description tuples keyed by
79
+ column name. Each value is a 7-tuple: (name, type_code, display_size,
80
+ internal_size, precision, scale, null_ok). Populated from
81
+ cursor.description when a database adapter executes the query.
82
+ error: Optional error message if query failed
83
+ resolved_relations: dbt ref/source relations resolved during execution,
84
+ with dev-vs-prod schema status for each.
85
+ """
86
+ self.data = data or []
87
+ if columns is None and self.data:
88
+ self.columns = list(self.data[0].keys())
89
+ else:
90
+ self.columns = columns or []
91
+ self.column_descriptions = column_descriptions
92
+ self.error = error
93
+ self.resolved_relations: list[ResolvedRelation] = resolved_relations or []
94
+
95
+ @property
96
+ def is_success(self) -> bool:
97
+ """Check if query executed successfully."""
98
+ return self.error is None
99
+
100
+
101
+ def handle_adapter_error(operation: str, error: Exception) -> QueryResult:
102
+ """Standard error handling for adapters.
103
+
104
+ Provides consistent error handling across all adapters, ensuring
105
+ uniform error messages and making it easier to add logging/metrics
106
+ in one place.
107
+
108
+ Args:
109
+ operation: Description of the operation that failed (e.g., "SQL execution", "HTTP request")
110
+ error: The exception that occurred
111
+
112
+ Returns:
113
+ QueryResult with error information
114
+ """
115
+ return QueryResult(
116
+ data=[],
117
+ error=f"{operation} failed: {str(error)}",
118
+ )
119
+
120
+
121
+ class BaseAdapter(ABC):
122
+ """Base interface for query adapters.
123
+
124
+ All adapters must implement this interface to execute queries
125
+ against different backends (MetricFlow, SQL, HTTP, CSV, etc.).
126
+
127
+ The unified interface pattern uses:
128
+ - `supported_types`: Property returning set of query types this adapter handles
129
+ - Type guards for type-safe field access in execute methods
130
+
131
+ Subclasses must implement:
132
+ - supported_types: Property returning Set[str] of supported query types
133
+ - _execute(): Perform the actual query execution
134
+
135
+ Optional override:
136
+ - _can_execute(): Override for custom eligibility logic beyond type matching
137
+
138
+ Example:
139
+ >>> class MyAdapter(BaseAdapter):
140
+ ... @property
141
+ ... def supported_types(self) -> Set[str]:
142
+ ... return {"sql"}
143
+ ...
144
+ ... def _execute(self, query, variables):
145
+ ... if is_sql_query(query):
146
+ ... # Type checker knows query.sql exists
147
+ ... return self._run_sql(query.sql)
148
+ """
149
+
150
+ @property
151
+ @abstractmethod
152
+ def supported_types(self) -> set[str]:
153
+ """Query types this adapter can execute.
154
+
155
+ Returns:
156
+ Set of query type strings (e.g., {"sql"}, {"csv", "http"})
157
+
158
+ Example:
159
+ >>> adapter.supported_types
160
+ {"sql"}
161
+ """
162
+ pass
163
+
164
+ def can_execute(self, query: AnyQuery) -> bool:
165
+ """Check if this adapter can execute the given query.
166
+
167
+ Uses supported_types for type-based routing. Override _can_execute()
168
+ for additional custom eligibility logic.
169
+
170
+ Args:
171
+ query: AnyQuery object (guaranteed by compiler)
172
+
173
+ Returns:
174
+ True if this adapter can execute the query, False otherwise
175
+ """
176
+ # First check if type is supported
177
+ if query.query_type not in self.supported_types:
178
+ return False
179
+ # Then check any additional conditions
180
+ return self._can_execute(query)
181
+
182
+ def _can_execute(self, query: AnyQuery) -> bool:
183
+ """Additional eligibility check beyond type matching.
184
+
185
+ Override this method to add custom eligibility logic.
186
+ The base implementation always returns True.
187
+
188
+ Args:
189
+ query: AnyQuery object (guaranteed)
190
+
191
+ Returns:
192
+ True if this adapter can execute the query, False otherwise
193
+ """
194
+ return True
195
+
196
+ def execute(
197
+ self,
198
+ query: AnyQuery,
199
+ variables: VariableValues | None = None,
200
+ params: QueryParams = None,
201
+ source_config: SourceConfig | None = None,
202
+ ) -> QueryResult:
203
+ """Execute a query and return results.
204
+
205
+ Args:
206
+ query: AnyQuery object (guaranteed by compiler)
207
+ variables: Optional dictionary of variable values for query resolution
208
+ params: Optional pre-computed parameter values for parameterized execution.
209
+ When provided, the adapter should use these params directly instead
210
+ of re-processing variables. This is used by batch execution where
211
+ parameterization happens before adapter execution.
212
+ source_config: Typed source config resolved by SourceResolver before
213
+ adapter dispatch. SqlAdapter consumes this; other adapters ignore it.
214
+
215
+ Returns:
216
+ QueryResult containing data or error information
217
+ """
218
+ return self._execute(query, variables, params, source_config)
219
+
220
+ @abstractmethod
221
+ def _execute(
222
+ self,
223
+ query: AnyQuery,
224
+ variables: VariableValues | None = None,
225
+ params: QueryParams = None,
226
+ source_config: SourceConfig | None = None,
227
+ ) -> QueryResult:
228
+ """Internal method to execute query.
229
+
230
+ Use type guards for type-safe field access:
231
+ if is_sql_query(query):
232
+ sql = query.sql # Type checker knows this is str
233
+
234
+ Args:
235
+ query: AnyQuery object (guaranteed)
236
+ variables: Optional dictionary of variable values for query resolution
237
+ params: Optional pre-computed parameter values. When provided, skip
238
+ internal parameterization and use these params directly.
239
+ source_config: Typed source config from SourceResolver; SqlAdapter
240
+ reads it, other adapters accept and ignore.
241
+
242
+ Returns:
243
+ QueryResult containing data or error information
244
+ """
245
+ pass
@@ -0,0 +1,239 @@
1
+ """CSV adapter for executing queries against CSV files.
2
+
3
+ Stage: EXECUTE
4
+ Purpose: Load and query data from CSV files.
5
+
6
+ This adapter allows users to load data from CSV files stored in their
7
+ project's assets/data directory or other specified paths. It supports
8
+ basic filtering and column selection via query parameters.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import csv
14
+ from pathlib import Path
15
+ from typing import TYPE_CHECKING, Any
16
+
17
+ if TYPE_CHECKING:
18
+ from dataface.core.compile.models.source import SourceConfig
19
+
20
+ from dataface.core.compile.jinja import resolve_jinja_template
21
+ from dataface.core.compile.models.face.compiled import VariableValues
22
+ from dataface.core.compile.models.query.compiled import (
23
+ AnyQuery,
24
+ is_csv_query,
25
+ )
26
+ from dataface.core.execute.adapters.base import (
27
+ BaseAdapter,
28
+ QueryParams,
29
+ QueryResult,
30
+ handle_adapter_error,
31
+ )
32
+
33
+
34
+ def _coerce_csv_value(v: str) -> str | int | float:
35
+ """Try to parse a CSV string as int, then float; return the original string on failure."""
36
+ try:
37
+ return int(v)
38
+ except ValueError:
39
+ pass
40
+ try:
41
+ return float(v)
42
+ except ValueError:
43
+ return v
44
+
45
+
46
+ class CsvAdapter(BaseAdapter):
47
+ """Adapter for executing queries against CSV files.
48
+
49
+ Supported query types: csv
50
+
51
+ Loads data from CSV files and supports:
52
+ - Column selection
53
+ - Row filtering (exact match, AND logic)
54
+ - Result limiting
55
+
56
+ Example:
57
+ >>> adapter = CsvAdapter()
58
+ >>> query = CsvQuery(file="data/sales.csv", columns=["date", "amount"])
59
+ >>> result = adapter.execute(query)
60
+ """
61
+
62
+ def __init__(self, project_root: Path | None = None):
63
+ """Initialize CSV adapter.
64
+
65
+ Args:
66
+ project_root: Root directory of the project (for resolving relative paths)
67
+ """
68
+ self.project_root = project_root or Path.cwd()
69
+
70
+ @property
71
+ def supported_types(self) -> set[str]:
72
+ """Return supported query types."""
73
+ return {"csv"}
74
+
75
+ def _resolve_file_path(self, file_path: str) -> Path:
76
+ """Resolve CSV file path relative to project root or assets/data.
77
+
78
+ Args:
79
+ file_path: File path from query (may be relative)
80
+
81
+ Returns:
82
+ Resolved Path object
83
+ """
84
+ # If absolute path, use as-is
85
+ if Path(file_path).is_absolute():
86
+ return Path(file_path)
87
+
88
+ # Try relative to project root first
89
+ project_path = self.project_root / file_path
90
+ if project_path.exists():
91
+ return project_path
92
+
93
+ # Try relative to assets/data
94
+ assets_data_path = self.project_root / "assets" / "data" / file_path
95
+ if assets_data_path.exists():
96
+ return assets_data_path
97
+
98
+ # Try just the filename in assets/data
99
+ filename_path = self.project_root / "assets" / "data" / Path(file_path).name
100
+ if filename_path.exists():
101
+ return filename_path
102
+
103
+ # Fall back to relative path (may not exist, but we'll handle error)
104
+ return self.project_root / file_path
105
+
106
+ def _execute(
107
+ self,
108
+ query: AnyQuery,
109
+ variables: VariableValues | None = None,
110
+ params: QueryParams = None,
111
+ source_config: SourceConfig | None = None,
112
+ ) -> QueryResult:
113
+ """Execute a CSV query.
114
+
115
+ Uses type guard for type-safe field access.
116
+
117
+ Args:
118
+ query: AnyQuery object (CsvQuery expected)
119
+ variables: Variable values for Jinja resolution
120
+ params: Not used for CSV queries (CSV doesn't use SQL parameterization)
121
+
122
+ Returns:
123
+ QueryResult with data or error
124
+ """
125
+ # Type guard ensures query.file is str
126
+ if not is_csv_query(query):
127
+ return QueryResult(
128
+ data=[],
129
+ error=f"Expected CSV query, got {query.query_type}",
130
+ )
131
+
132
+ file_path = query.effective_file
133
+ if not file_path:
134
+ return QueryResult(
135
+ data=[],
136
+ error="CSV query requires a file path",
137
+ )
138
+
139
+ # Resolve Jinja templates in file path
140
+ try:
141
+ resolved_file_path = resolve_jinja_template(file_path, variables)
142
+ except (ValueError, KeyError, TypeError) as e:
143
+ return handle_adapter_error("CSV file path template resolution", e)
144
+
145
+ # Resolve file path
146
+ try:
147
+ csv_path = self._resolve_file_path(resolved_file_path)
148
+ except (OSError, ValueError) as e:
149
+ return handle_adapter_error("CSV file path resolution", e)
150
+
151
+ # Check if file exists
152
+ if not csv_path.exists():
153
+ return QueryResult(
154
+ data=[],
155
+ error=f"CSV file not found: {csv_path}",
156
+ )
157
+
158
+ # Read CSV file using stdlib csv module
159
+ try:
160
+ with open(csv_path, encoding="utf-8") as f:
161
+ reader = csv.DictReader(f)
162
+ raw_rows = list(reader)
163
+ except (OSError, csv.Error, UnicodeDecodeError) as e:
164
+ return handle_adapter_error("CSV file reading", e)
165
+
166
+ # Coerce numeric strings to Python int/float so downstream type inference works.
167
+ rows: list[dict[str, Any]] = [
168
+ {k: _coerce_csv_value(v) for k, v in row.items()} for row in raw_rows
169
+ ]
170
+
171
+ if not rows:
172
+ return QueryResult(data=[])
173
+
174
+ # Get column names from first row
175
+ available_columns = list(rows[0].keys())
176
+
177
+ # Apply column selection if specified
178
+ columns = query.columns
179
+ if columns:
180
+ # Resolve Jinja in column names
181
+ try:
182
+ resolved_columns = [
183
+ resolve_jinja_template(col, variables) for col in columns
184
+ ]
185
+ # Filter to only existing columns
186
+ existing_columns = [
187
+ col for col in resolved_columns if col in available_columns
188
+ ]
189
+ if existing_columns:
190
+ # Keep only selected columns
191
+ rows = [{col: row[col] for col in existing_columns} for row in rows]
192
+ available_columns = existing_columns
193
+ except (ValueError, KeyError, TypeError) as e:
194
+ return handle_adapter_error("CSV column name resolution", e)
195
+
196
+ # Apply filtering if specified (basic exact match, AND logic)
197
+ filter_dict = query.filter
198
+ if filter_dict:
199
+ try:
200
+ # Resolve Jinja in filter values
201
+ resolved_filter: dict[str, Any] = {}
202
+ for key, value in filter_dict.items():
203
+ if isinstance(value, str):
204
+ resolved_value = resolve_jinja_template(value, variables)
205
+ else:
206
+ resolved_value = value
207
+ resolved_filter[key] = resolved_value
208
+
209
+ # Skip filters that resolved to None or empty string (conditional filters)
210
+ active_filters = {
211
+ k: v
212
+ for k, v in resolved_filter.items()
213
+ if v is not None and v != "" and str(v).lower() != "none"
214
+ }
215
+
216
+ if active_filters:
217
+ # Apply filters (exact match, AND logic)
218
+ filtered_rows = []
219
+ for row in rows:
220
+ match = True
221
+ for key, value in active_filters.items():
222
+ if key not in available_columns:
223
+ continue
224
+ # Convert both to string for comparison (CSV reads everything as string)
225
+ if str(row.get(key, "")) != str(value):
226
+ match = False
227
+ break
228
+ if match:
229
+ filtered_rows.append(row)
230
+ rows = filtered_rows
231
+ except (ValueError, KeyError, TypeError) as e:
232
+ return handle_adapter_error("CSV filter application", e)
233
+
234
+ # Apply limit if specified
235
+ limit = query.limit
236
+ if limit is not None and limit > 0:
237
+ rows = rows[:limit]
238
+
239
+ return QueryResult(data=rows)