twilize 0.13.0__tar.gz
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.
- twilize-0.13.0/.dockerignore +14 -0
- twilize-0.13.0/.gitignore +60 -0
- twilize-0.13.0/CHANGELOG.md +300 -0
- twilize-0.13.0/CONTRIBUTING.md +171 -0
- twilize-0.13.0/Dockerfile +32 -0
- twilize-0.13.0/LICENSE +661 -0
- twilize-0.13.0/PKG-INFO +590 -0
- twilize-0.13.0/Procfile +1 -0
- twilize-0.13.0/README.md +542 -0
- twilize-0.13.0/docs/MCP_SERVER.md +744 -0
- twilize-0.13.0/docs/ROADMAP.md +426 -0
- twilize-0.13.0/docs/tableau_agent.md +1161 -0
- twilize-0.13.0/examples/README.md +71 -0
- twilize-0.13.0/examples/layouts/layout_c1.json +64 -0
- twilize-0.13.0/examples/layouts/layout_c2.json +113 -0
- twilize-0.13.0/examples/layouts/layout_executive.json +80 -0
- twilize-0.13.0/examples/migrate_workflow/5 KPI Design Ideas (2).twb +9850 -0
- twilize-0.13.0/examples/migrate_workflow/README.md +26 -0
- twilize-0.13.0/examples/migrate_workflow/Sample - Superstore.xls +0 -0
- twilize-0.13.0/examples/migrate_workflow/test_migration_workflow.py +63 -0
- twilize-0.13.0/examples/migrate_workflow//347/244/272/344/276/213 - /350/266/205/345/270/202.xls +0 -0
- twilize-0.13.0/examples/prompts/README.md +34 -0
- twilize-0.13.0/examples/prompts/all_supported_charts_showcase_en.md +37 -0
- twilize-0.13.0/examples/prompts/demo_auto_layout4_prompt.md +34 -0
- twilize-0.13.0/examples/prompts/demo_auto_layout_prompt.md +20 -0
- twilize-0.13.0/examples/prompts/demo_c2_layout_prompt.md +19 -0
- twilize-0.13.0/examples/prompts/demo_declarative_layout_prompt.md +34 -0
- twilize-0.13.0/examples/prompts/demo_simple.md +20 -0
- twilize-0.13.0/examples/prompts/overview_business_demo.md +62 -0
- twilize-0.13.0/examples/prompts/overview_natural zh_cn.md +46 -0
- twilize-0.13.0/examples/prompts/overview_natural_en.md +113 -0
- twilize-0.13.0/examples/prompts/test_parameter_prefix_bug.md +18 -0
- twilize-0.13.0/examples/screenshot2layout/dashboard 1.png +0 -0
- twilize-0.13.0/examples/screenshot2layout/dashboard 2.png +0 -0
- twilize-0.13.0/examples/screenshot2layout/layout_dashboard1.json +114 -0
- twilize-0.13.0/examples/screenshot2layout/layout_dashboard2.json +194 -0
- twilize-0.13.0/examples/scripts/demo_all_supported_charts.py +128 -0
- twilize-0.13.0/examples/scripts/demo_all_supported_charts_mcp.py +125 -0
- twilize-0.13.0/examples/scripts/demo_auto_layout4.py +84 -0
- twilize-0.13.0/examples/scripts/demo_connections.py +68 -0
- twilize-0.13.0/examples/scripts/demo_declarative_layout.py +107 -0
- twilize-0.13.0/examples/scripts/demo_e2e_mcp_workflow.py +100 -0
- twilize-0.13.0/examples/scripts/demo_hyper_and_new_charts.py +122 -0
- twilize-0.13.0/examples/superstore_recreated/Exec Overview Recreated.twb +74 -0
- twilize-0.13.0/examples/superstore_recreated/build_exec_overview.py +924 -0
- twilize-0.13.0/examples/superstore_recreated/screenshot.png +0 -0
- twilize-0.13.0/extension/__init__.py +0 -0
- twilize-0.13.0/extension/backend/__init__.py +0 -0
- twilize-0.13.0/extension/backend/app.py +228 -0
- twilize-0.13.0/extension/backend/chart_suggestion.py +1279 -0
- twilize-0.13.0/extension/backend/image_analysis.py +269 -0
- twilize-0.13.0/extension/backend/pipeline.py +558 -0
- twilize-0.13.0/extension/backend/schema_inference.py +131 -0
- twilize-0.13.0/extension/backend/tests/__init__.py +0 -0
- twilize-0.13.0/extension/backend/tests/test_schema_inference.py +30 -0
- twilize-0.13.0/extension/backend/tests/test_suggestion.py +69 -0
- twilize-0.13.0/extension/frontend/index.html +13 -0
- twilize-0.13.0/extension/frontend/package.json +24 -0
- twilize-0.13.0/extension/frontend/public/tableau.extensions.min.js +2 -0
- twilize-0.13.0/extension/frontend/src/App.tsx +152 -0
- twilize-0.13.0/extension/frontend/src/components/ApiKeySettings.tsx +131 -0
- twilize-0.13.0/extension/frontend/src/components/DataPreview.tsx +88 -0
- twilize-0.13.0/extension/frontend/src/components/DownloadPanel.tsx +84 -0
- twilize-0.13.0/extension/frontend/src/components/ImageUpload.tsx +111 -0
- twilize-0.13.0/extension/frontend/src/components/ProgressIndicator.tsx +72 -0
- twilize-0.13.0/extension/frontend/src/components/PromptInput.tsx +40 -0
- twilize-0.13.0/extension/frontend/src/components/SuggestionPreview.tsx +118 -0
- twilize-0.13.0/extension/frontend/src/hooks/useGeneration.ts +55 -0
- twilize-0.13.0/extension/frontend/src/hooks/useTableauData.ts +90 -0
- twilize-0.13.0/extension/frontend/src/main.tsx +9 -0
- twilize-0.13.0/extension/frontend/src/utils/api.ts +98 -0
- twilize-0.13.0/extension/frontend/src/utils/tableauApi.ts +190 -0
- twilize-0.13.0/extension/frontend/src/utils/types.ts +28 -0
- twilize-0.13.0/extension/frontend/tsconfig.json +21 -0
- twilize-0.13.0/extension/frontend/vite.config.ts +19 -0
- twilize-0.13.0/extension/manifest/twilize-extension-production.trex +22 -0
- twilize-0.13.0/extension/manifest/twilize-extension.trex +22 -0
- twilize-0.13.0/extension/scripts/start.py +83 -0
- twilize-0.13.0/mcp-server.json +292 -0
- twilize-0.13.0/pyproject.toml +86 -0
- twilize-0.13.0/requirements.txt +11 -0
- twilize-0.13.0/smithery.yaml +131 -0
- twilize-0.13.0/src/twilize/__init__.py +55 -0
- twilize-0.13.0/src/twilize/__main__.py +5 -0
- twilize-0.13.0/src/twilize/c3_layout.py +555 -0
- twilize-0.13.0/src/twilize/capability_registry.py +509 -0
- twilize-0.13.0/src/twilize/chart_suggester.py +713 -0
- twilize-0.13.0/src/twilize/charts/__init__.py +350 -0
- twilize-0.13.0/src/twilize/charts/builder_base.py +634 -0
- twilize-0.13.0/src/twilize/charts/builder_basic.py +282 -0
- twilize-0.13.0/src/twilize/charts/builder_dual_axis.py +677 -0
- twilize-0.13.0/src/twilize/charts/builder_maps.py +298 -0
- twilize-0.13.0/src/twilize/charts/builder_pie.py +95 -0
- twilize-0.13.0/src/twilize/charts/builder_text.py +180 -0
- twilize-0.13.0/src/twilize/charts/dispatcher.py +215 -0
- twilize-0.13.0/src/twilize/charts/helpers.py +599 -0
- twilize-0.13.0/src/twilize/charts/pattern_mapping.py +57 -0
- twilize-0.13.0/src/twilize/charts/routing_policy.py +91 -0
- twilize-0.13.0/src/twilize/charts/showcase_recipes.py +471 -0
- twilize-0.13.0/src/twilize/config.py +26 -0
- twilize-0.13.0/src/twilize/connections.py +532 -0
- twilize-0.13.0/src/twilize/csv_to_hyper.py +485 -0
- twilize-0.13.0/src/twilize/dashboard_actions.py +184 -0
- twilize-0.13.0/src/twilize/dashboard_dependencies.py +125 -0
- twilize-0.13.0/src/twilize/dashboard_enhancements.py +336 -0
- twilize-0.13.0/src/twilize/dashboard_layouts.py +137 -0
- twilize-0.13.0/src/twilize/dashboards.py +240 -0
- twilize-0.13.0/src/twilize/docapi_bridge.py +220 -0
- twilize-0.13.0/src/twilize/field_registry.py +291 -0
- twilize-0.13.0/src/twilize/layout.py +6 -0
- twilize-0.13.0/src/twilize/layout_model.py +135 -0
- twilize-0.13.0/src/twilize/layout_rendering.py +269 -0
- twilize-0.13.0/src/twilize/layout_templates.py +587 -0
- twilize-0.13.0/src/twilize/mcp/__init__.py +1 -0
- twilize-0.13.0/src/twilize/mcp/app.py +27 -0
- twilize-0.13.0/src/twilize/mcp/resources.py +93 -0
- twilize-0.13.0/src/twilize/mcp/snapshot.py +122 -0
- twilize-0.13.0/src/twilize/mcp/state.py +46 -0
- twilize-0.13.0/src/twilize/mcp/tools_layout.py +70 -0
- twilize-0.13.0/src/twilize/mcp/tools_migration.py +162 -0
- twilize-0.13.0/src/twilize/mcp/tools_pipeline.py +129 -0
- twilize-0.13.0/src/twilize/mcp/tools_support.py +120 -0
- twilize-0.13.0/src/twilize/mcp/tools_workbook.py +672 -0
- twilize-0.13.0/src/twilize/migration.py +1312 -0
- twilize-0.13.0/src/twilize/parameters.py +165 -0
- twilize-0.13.0/src/twilize/pipeline.py +348 -0
- twilize-0.13.0/src/twilize/reference_lines.py +159 -0
- twilize-0.13.0/src/twilize/references/Sample _ Superstore (Simple).xls +0 -0
- twilize-0.13.0/src/twilize/references/empty_template.twb +494 -0
- twilize-0.13.0/src/twilize/references/tableau_all_functions.json +1053 -0
- twilize-0.13.0/src/twilize/server.py +62 -0
- twilize-0.13.0/src/twilize/skills/README.md +41 -0
- twilize-0.13.0/src/twilize/skills/calculation_builder.md +126 -0
- twilize-0.13.0/src/twilize/skills/chart_builder.md +367 -0
- twilize-0.13.0/src/twilize/skills/dashboard_designer.md +256 -0
- twilize-0.13.0/src/twilize/skills/formatting.md +167 -0
- twilize-0.13.0/src/twilize/style_presets.py +187 -0
- twilize-0.13.0/src/twilize/themes.py +153 -0
- twilize-0.13.0/src/twilize/trend_lines.py +107 -0
- twilize-0.13.0/src/twilize/twb_analyzer.py +478 -0
- twilize-0.13.0/src/twilize/twb_editor.py +730 -0
- twilize-0.13.0/src/twilize/validator.py +319 -0
- twilize-0.13.0/src/twilize/viz_best_practices.py +390 -0
- twilize-0.13.0/templates/Sample - Superstore - simple.xls +0 -0
- twilize-0.13.0/templates/Sample - Superstore.xls +0 -0
- twilize-0.13.0/templates/layout/Tableau Dashboard Layout Templates screenshot.png +0 -0
- twilize-0.13.0/templates/layout/Tableau Dashboard Layout Templates.twb +4917 -0
- twilize-0.13.0/templates/migrate/5 KPI Design Ideas (2).twb +9803 -0
- twilize-0.13.0/templates/migrate/Sample - Superstore.xls +0 -0
- twilize-0.13.0/templates/migrate//347/244/272/344/276/213 - /350/266/205/345/270/202.xls +0 -0
- twilize-0.13.0/templates/twb/superstore - localmysql.twb +527 -0
- twilize-0.13.0/templates/twb/superstore copy.twb +495 -0
- twilize-0.13.0/templates/twb/superstore.twb +636 -0
- twilize-0.13.0/templates/viz/Tableau Advent Calendar.twb +5511 -0
- twilize-0.13.0/templates/viz/pie_chart.twb +686 -0
- twilize-0.13.0/tests/README.md +199 -0
- twilize-0.13.0/tests/conftest.py +22 -0
- twilize-0.13.0/tests/parse_twb.py +27 -0
- twilize-0.13.0/tests/test_c2_replica.py +178 -0
- twilize-0.13.0/tests/test_capability_registry.py +41 -0
- twilize-0.13.0/tests/test_chart_routing.py +140 -0
- twilize-0.13.0/tests/test_chart_suggester.py +198 -0
- twilize-0.13.0/tests/test_charts.py +60 -0
- twilize-0.13.0/tests/test_connections.py +139 -0
- twilize-0.13.0/tests/test_csv_schema_inference.py +150 -0
- twilize-0.13.0/tests/test_dashboard_action_types.py +238 -0
- twilize-0.13.0/tests/test_dashboard_actions.py +65 -0
- twilize-0.13.0/tests/test_debug.py +113 -0
- twilize-0.13.0/tests/test_declarative_dashboards.py +139 -0
- twilize-0.13.0/tests/test_diff.py +4 -0
- twilize-0.13.0/tests/test_docapi_bridge.py +41 -0
- twilize-0.13.0/tests/test_dual_axis_advanced.py +265 -0
- twilize-0.13.0/tests/test_dual_axis_basic.py +160 -0
- twilize-0.13.0/tests/test_dual_axis_script.py +5 -0
- twilize-0.13.0/tests/test_e2e.py +120 -0
- twilize-0.13.0/tests/test_empty.twb +471 -0
- twilize-0.13.0/tests/test_error_handling.py +206 -0
- twilize-0.13.0/tests/test_existing_workbook_editing.py +200 -0
- twilize-0.13.0/tests/test_field_registry.py +59 -0
- twilize-0.13.0/tests/test_generate_pie.py +81 -0
- twilize-0.13.0/tests/test_hyper_example.py +25 -0
- twilize-0.13.0/tests/test_interactive_features.py +60 -0
- twilize-0.13.0/tests/test_label_runs.py +234 -0
- twilize-0.13.0/tests/test_layout_ascii.py +48 -0
- twilize-0.13.0/tests/test_level1_features.py +298 -0
- twilize-0.13.0/tests/test_mcp_showcase_workbook.py +291 -0
- twilize-0.13.0/tests/test_mcp_tools.py +194 -0
- twilize-0.13.0/tests/test_migration_workflow.py +240 -0
- twilize-0.13.0/tests/test_overview_full.py +230 -0
- twilize-0.13.0/tests/test_overview_replica.py +200 -0
- twilize-0.13.0/tests/test_phase10_dashboard_polish.py +410 -0
- twilize-0.13.0/tests/test_reference_lines.py +201 -0
- twilize-0.13.0/tests/test_screenshot2layout.py +201 -0
- twilize-0.13.0/tests/test_template_datasource_structure.py +88 -0
- twilize-0.13.0/tests/test_twb_analyzer.py +123 -0
- twilize-0.13.0/tests/test_twb_structure.py +288 -0
- twilize-0.13.0/tests/test_twbx_support.py +247 -0
- twilize-0.13.0/tests/test_worksheet_style.py +274 -0
- twilize-0.13.0/tests/twb_assert.py +200 -0
- twilize-0.13.0/vendor/tableau-document-schemas/.gitignore +5 -0
- twilize-0.13.0/vendor/tableau-document-schemas/CODEOWNERS +3 -0
- twilize-0.13.0/vendor/tableau-document-schemas/CODE_OF_CONDUCT.md +105 -0
- twilize-0.13.0/vendor/tableau-document-schemas/CONTRIBUTING.md +22 -0
- twilize-0.13.0/vendor/tableau-document-schemas/LICENSE.txt +207 -0
- twilize-0.13.0/vendor/tableau-document-schemas/README.md +83 -0
- twilize-0.13.0/vendor/tableau-document-schemas/SECURITY.md +7 -0
- twilize-0.13.0/vendor/tableau-document-schemas/schemas/2026_1/_user_ns_stub.xsd +7 -0
- twilize-0.13.0/vendor/tableau-document-schemas/schemas/2026_1/_xml_ns_stub.xsd +15 -0
- twilize-0.13.0/vendor/tableau-document-schemas/schemas/2026_1/twb_2026.1.0.xsd +7586 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
*.egg
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.whl
|
|
10
|
+
|
|
11
|
+
# Virtual environments
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
env/
|
|
15
|
+
.env
|
|
16
|
+
*.log
|
|
17
|
+
*.logs
|
|
18
|
+
|
|
19
|
+
# IDE
|
|
20
|
+
.vscode/
|
|
21
|
+
.idea/
|
|
22
|
+
*.swp
|
|
23
|
+
*.swo
|
|
24
|
+
*~
|
|
25
|
+
.claude/
|
|
26
|
+
|
|
27
|
+
# OS
|
|
28
|
+
.DS_Store
|
|
29
|
+
Thumbs.db
|
|
30
|
+
desktop.ini
|
|
31
|
+
|
|
32
|
+
# Node
|
|
33
|
+
node_modules/
|
|
34
|
+
package-lock.json
|
|
35
|
+
|
|
36
|
+
# Test output
|
|
37
|
+
output/
|
|
38
|
+
|
|
39
|
+
# Temp files
|
|
40
|
+
temp_template.twb
|
|
41
|
+
test_api.py
|
|
42
|
+
test_env.py
|
|
43
|
+
example_data.csv
|
|
44
|
+
|
|
45
|
+
# Large/binary project files
|
|
46
|
+
backup/
|
|
47
|
+
dashboard/
|
|
48
|
+
*.twbx
|
|
49
|
+
*.hyper
|
|
50
|
+
!src/cwtwb/references/*.hyper
|
|
51
|
+
*.twbr
|
|
52
|
+
tmp/
|
|
53
|
+
templates/migrate/* - migrated to *.twb
|
|
54
|
+
templates/migrate/migration_report.json
|
|
55
|
+
templates/migrate/field_mapping.json
|
|
56
|
+
examples/migrate_workflow/* - migrated to *.twb
|
|
57
|
+
examples/migrate_workflow/* - migrated.twb
|
|
58
|
+
examples/migrate_workflow/migration_report.json
|
|
59
|
+
examples/migrate_workflow/field_mapping.json
|
|
60
|
+
examples/migrate_workflow/prompt.txt
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.16.0] - 2026-03-19
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **`FieldRegistry.remove()` missing**: `TWBEditor.remove_calculated_field()` and its `remove_calculated_field` MCP tool called `self.field_registry.remove()`, but `FieldRegistry` only defined `unregister()`. Added the missing `remove()` method; the MCP tool now works correctly instead of raising `AttributeError`.
|
|
13
|
+
- **Dual-axis pane secondary ID mismatch**: `DualAxisChartBuilder` wrote `id="3"` for the secondary pane in both horizontal and vertical configurations, while all test assertions and internal lookups expected `id="2"`. Changed pane_2 id to `"2"` in both the same-measure (lollipop/donut) and different-measure (combo) branches.
|
|
14
|
+
- **`format_capability_catalog()` missing `level_filter` parameter**: The function signature accepted no arguments, but the capability registry design and test suite expected an optional `level_filter: str` parameter to restrict output to a single level (e.g. `"core"`). Added the parameter; calling without it preserves the existing full-catalog behavior.
|
|
15
|
+
- **`inspect_target_schema` crashes on non-Excel paths**: The MCP tool passed any path directly to `xlrd.open_workbook()`, raising `FileNotFoundError` or `XLRDError` for `.csv`, non-existent files, or unsupported formats. Added an extension check up-front and a `try/except` fallback; both now return a readable `"Unsupported…"` string instead of an exception.
|
|
16
|
+
- **`analyze_twb` missing Capability gap section**: `analyze_twb` returned only `report.to_text()`, omitting the decision-oriented gap summary that `diff_template_gap` produces separately. The tool now appends `report.to_gap_text()` so a single `analyze_twb` call includes both the capability catalog and the gap triage.
|
|
17
|
+
|
|
18
|
+
## [0.15.0] - 2026-03-18
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **XSD schema validation** against the official Tableau TWB XSD (2026.1), vendored at `vendor/tableau-document-schemas/`:
|
|
23
|
+
- `TWBEditor.validate_schema()` — validates the in-memory workbook without saving first; returns a `SchemaValidationResult` with `valid`, `errors`, `schema_available`, and `to_text()` summary.
|
|
24
|
+
- `validate_workbook` MCP tool — validates the current open workbook (in memory) or any `.twb`/`.twbx` file on disk by path. Errors are reported as informational; Tableau itself occasionally generates workbooks that deviate from the schema.
|
|
25
|
+
- `validate_against_schema(root)` — public SDK function in `twilize.validator`, accepts an lxml `_Element` and returns `SchemaValidationResult`.
|
|
26
|
+
- `SchemaValidationResult` exported from the top-level `twilize` package.
|
|
27
|
+
- Two missing XSD imports (`http://www.tableausoftware.com/xml/user` and `http://www.w3.org/XML/1998/namespace`) resolved via local stub XSD files written to `vendor/tableau-document-schemas/schemas/2026_1/` at first use; schema is loaded once and cached for the process lifetime.
|
|
28
|
+
|
|
29
|
+
## [0.14.0] - 2026-03-17
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **`.twbx` (Packaged Workbook) support**: `TWBEditor` now reads and writes Tableau Packaged Workbook files transparently.
|
|
34
|
+
- **Open**: `TWBEditor("file.twbx")` and `TWBEditor.open_existing("file.twbx")` unzip the archive, locate the embedded `.twb`, and parse it in-memory. The source ZIP path and inner filename are recorded for later re-packing.
|
|
35
|
+
- **Save as `.twbx`**: `editor.save("output.twbx")` serializes the updated XML and re-packs it into a new ZIP, carrying over all bundled assets (`.hyper` data extracts, images, etc.) from the source `.twbx` automatically.
|
|
36
|
+
- **Save as `.twb` from a `.twbx` source**: `editor.save("output.twb")` extracts just the workbook XML, discarding the packaging.
|
|
37
|
+
- **Plain `.twb` → `.twbx`**: any `.twb`-sourced workbook can be packaged by saving with a `.twbx` extension; the result is a single-entry ZIP containing the workbook XML.
|
|
38
|
+
- MCP tools `create_workbook`, `open_workbook`, and `save_workbook` all support `.twbx` paths with no changes to call signatures.
|
|
39
|
+
- **`tests/test_twbx_support.py`**: 25 pytest cases covering open, round-trip save, extract/image preservation, plain-TWB-to-TWBX conversion, modify-and-resave, and MCP tool integration.
|
|
40
|
+
|
|
41
|
+
## [0.13.0] - 2026-03-17
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- **Rich-text `label_runs` in `configure_chart`**: Multi-style labels built from a list of run dicts. Each run supports `text` (literal string), `field` (field expression → `<field_ref>` CDATA), `prefix`, and per-run font attributes (`fontname`, `fontsize`, `fontcolor`, `bold`, `fontalignment`). Use `"\n"` as text to insert a paragraph separator. Pass `"fontalignment": None` to suppress the default alignment attribute. Enables KPI cards with two-line labels, dynamic titles with inline field values, and branded separators.
|
|
46
|
+
- **14 new `configure_worksheet_style` options**:
|
|
47
|
+
- `hide_col_field_labels` / `hide_row_field_labels` — hide column and row field label headers in table/cross-tab views
|
|
48
|
+
- `hide_droplines` — remove drop lines from mark tooltips
|
|
49
|
+
- `hide_table_dividers` — remove row/column divider lines in cross-tab views
|
|
50
|
+
- `hide_reflines` — hide reference lines
|
|
51
|
+
- `disable_tooltip` — disable tooltip entirely (`tooltip-mode='none'`)
|
|
52
|
+
- `pane_cell_style: dict` — pane-level cell text alignment, e.g. `{"text-align": "center", "vertical-align": "center"}`
|
|
53
|
+
- `pane_datalabel_style: dict` — pane-level data label font family, size, and color
|
|
54
|
+
- `pane_mark_style: dict` — pane-level mark color, stroke, transparency, and size (0.0–1.0 scale via `"size"` key)
|
|
55
|
+
- `pane_trendline_hidden: bool` — hide trendline in pane style
|
|
56
|
+
- `label_formats: list[dict]` — per-field label style (font, color, orientation, display toggle)
|
|
57
|
+
- `cell_formats: list[dict]` — per-field table cell style
|
|
58
|
+
- `header_formats: list[dict]` — per-field header height/width
|
|
59
|
+
- `axis_style: dict` — global tick color plus per-field axis display and height control
|
|
60
|
+
- **`mark_color_1` in `configure_dual_axis`**: Explicit hex color for primary-axis marks, symmetric with the existing `mark_color_2`. Useful for pairing a gray bar (`mark_color_1`) against a blue target GanttBar (`mark_color_2`).
|
|
61
|
+
- **`color_map_1` in `configure_dual_axis`**: Datasource-level palette mapping for the primary-axis `color_1` field, using the same mechanism as `configure_chart(color_map=...)`.
|
|
62
|
+
- **`default_format` in `add_calculated_field`**: Optional Tableau number format string written as `default-format` on the column XML, e.g. `'c"$"#,##0,.0K'`.
|
|
63
|
+
- **`color_map` in `configure_dual_axis(extra_axes=[...])`**: Custom palette for `:Measure Names` when used as `"color"` on an extra axis. Each bucket is mapped to a hex color via a datasource-level `<encoding>` element.
|
|
64
|
+
- **`show_title` in dashboard layout nodes**: Pass `show_title: false` in a layout zone dict to suppress the worksheet title bar inside a dashboard zone.
|
|
65
|
+
- **Expanded test suite — 7 new test modules**:
|
|
66
|
+
- `test_worksheet_style.py` — all 18 `configure_worksheet_style` options (hide flags, background, pane styles, per-field formats, axis style)
|
|
67
|
+
- `test_label_runs.py` — text runs, field-ref runs, newline separator, font styling, prefix, fontalignment suppression, KPI card and dynamic title patterns
|
|
68
|
+
- `test_dual_axis_basic.py` — horizontal/vertical dual-axis combos, shared axis, color encoding, filters
|
|
69
|
+
- `test_dual_axis_advanced.py` — `mark_color_1/2`, `color_map_1`, `reverse_axis_1`, `hide_zeroline`, synchronized axis, `show_labels`, `size_value_1/2`
|
|
70
|
+
- `test_dashboard_action_types.py` — highlight action (`tsc:brush`), field-captions param, multiple coexisting actions, error handling (unsupported type, unknown dashboard)
|
|
71
|
+
- `test_mcp_tools.py` — `remove_calculated_field` (add/remove/re-add cycle), connection MCP wrappers, `inspect_target_schema`, `list_capabilities`, `analyze_twb`
|
|
72
|
+
- `test_template_datasource_structure.py` — Superstore template structural sanity: column count, connection class, datasource-dependencies
|
|
73
|
+
- **`tests/README.md`**: Full test suite documentation — run instructions, file index grouped by coverage area, function-to-test mapping table, known gaps.
|
|
74
|
+
|
|
75
|
+
### Changed
|
|
76
|
+
|
|
77
|
+
- **Examples reorganized**: Scripts moved from `examples/` root into `examples/scripts/` with consistent `demo_` prefix naming. `examples/README.md` updated with a new 7-script progression table and expanded Showcase Projects section.
|
|
78
|
+
- **Exec Overview example refined**: Dashboard header updated to 2023, KPI cards use `pane_cell_style` for center alignment, `show_title: false` on Sales by Sub-Category worksheet, spacer zone added for axis alignment.
|
|
79
|
+
|
|
80
|
+
## [0.12.0] - 2026-03-13
|
|
81
|
+
|
|
82
|
+
### Added
|
|
83
|
+
- **Bundled Hyper Extracts**: `Sample - EU Superstore.hyper` and `Sample _ Superstore.hyper` are now included in `src/twilize/references/` and distributed with the wheel. `hyper_and_new_charts.py` and `build_exec_overview.py` no longer require a cloned repository.
|
|
84
|
+
- **Progressive Examples**: All scripts in `examples/scripts/` (5 steps, Beginner → Advanced) and prompts in `examples/prompts/` (10 steps, Beginner → Advanced) now carry explicit step numbers and difficulty labels. `examples/README.md` rewritten with a Quick Start section and full progression tables.
|
|
85
|
+
|
|
86
|
+
### Fixed
|
|
87
|
+
- **Packaging**: Removed redundant `artifacts` declarations from `pyproject.toml`. All non-Python files under `src/twilize/` are git-tracked and included in the wheel automatically via `packages = ["src/twilize"]`.
|
|
88
|
+
- **`.gitignore`**: Added `!src/twilize/references/*.hyper` exception so bundled Hyper files are tracked by git and always present at wheel build time.
|
|
89
|
+
- **Examples — zero external dependencies**: All scripts in `examples/scripts/` and prompts in `examples/prompts/` updated to use `TWBEditor("")` / `create_workbook("")` (built-in default template) instead of hard-coded paths to `templates/twb/superstore.twb`. All work after a plain `pip install twilize`.
|
|
90
|
+
|
|
91
|
+
## [0.11.0] - 2026-03-13
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
- **Table Calculation Fields**: `add_calculated_field` now accepts a `table_calc` parameter (e.g. `table_calc="Rows"`) that writes a `<table-calc ordering-type="..."/>` child inside the `<calculation>` element, enabling `RANK_DENSE`, `RUNNING_SUM`, `WINDOW_AVG`, and all other Tableau table calculation functions to work correctly in the generated workbook.
|
|
95
|
+
- **Table Calc Column Instances**: `_setup_datasource_dependencies` in `builder_base` now automatically propagates a `<table-calc ordering-type="Columns"/>` element to any `<column-instance>` whose source column contains a table-calc calculation, matching the pattern Tableau uses for rank and running calculations.
|
|
96
|
+
- **Multi-field Label Support**: `configure_chart` now accepts `label_extra: list[str]` to bind multiple `<text>` encodings to a single mark, enabling combined text labels such as a sales figure plus a state name in one cell.
|
|
97
|
+
- **Row Dimension Label Hiding**: `configure_worksheet_style` now accepts `hide_row_label: str` to suppress the header column that Tableau renders for a rows-shelf dimension (adds `<style-rule element="label"><format attr="display" ... value="false"/></style-rule>`).
|
|
98
|
+
- **Donut Chart via `extra_axes`**: Pie panes in `configure_dual_axis(extra_axes=[...])` now automatically receive a `<size column="[Multiple Values]"/>` encoding when `measure_values` is present, completing the standard Tableau donut chart pattern without manual intervention.
|
|
99
|
+
- **Non-traditional Pie Mark via `BasicChartBuilder`**: `configure_chart(mark_type="Pie")` without `color` or `wedge_size` now routes through `BasicChartBuilder` instead of `PieChartBuilder`, allowing a Pie mark to display a label (e.g. a rank number) on a dimension-shelved view while retaining full rows/sort/filter support.
|
|
100
|
+
- **`selection-relaxation-disallow` on single-pane charts**: All charts built by `BasicChartBuilder` now set `selection-relaxation-option="selection-relaxation-disallow"` on the `<pane>` element, matching Tableau's default for filtered single-view worksheets and preventing click-interaction from relaxing Top N or categorical filters.
|
|
101
|
+
|
|
102
|
+
### Fixed
|
|
103
|
+
- **Measure Names filter ordering**: In `configure_dual_axis` with `extra_axes` containing `measure_values`, the Measure Names `<filter>` is now inserted into the `<view>` before Top N filters, matching the element order Tableau produces when creating these worksheets interactively.
|
|
104
|
+
|
|
105
|
+
### Example
|
|
106
|
+
- **Exec Overview Recreated** (`examples/superstore_recreated/`): Added `Rank CY` table calculation field; corrected `Top 5 Locations` to use Pie mark with Rank CY label; corrected `Top 5 Locations text` and `Sales by Sub-Category` to match reference workbook (donut size encoding, label style rules, filter order).
|
|
107
|
+
|
|
108
|
+
## [0.10.0] - 2026-03-11
|
|
109
|
+
|
|
110
|
+
### Fixed
|
|
111
|
+
- **XML Schema Conformity**: Fixed strict DTD validation errors related to `<pane>` child element ordering (e.g., `<customized-label>` must precede `<style>`) and `<datasource>` element ordering.
|
|
112
|
+
- **Customized Labels**: Fixed `<customized-label>` generation to correctly wrap dynamic template variables with physical `<` and `>` runs within the XML `<formatted-text>` nodes, complying with strict formatting limits.
|
|
113
|
+
- **Object-Graph Relationship Wiping**: Completely rewrote the `set_hyper_connection` logic for multi-table connections. It now preserves table-level relational links by surgically updating individual pre-existing `<object-graph>/<relation>` attributes correctly matching object definitions instead of flattening them into an unmapped collection.
|
|
114
|
+
|
|
115
|
+
### Added
|
|
116
|
+
- **Charting Capabilities**: Added parameters `axis_fixed_range` to configure exact visual bounds on measures, `color_map` for granular dataset-level color palette assignments, `mark_sizing_off` to disable auto scaling, `customized_label` for rich template texts, and `text_format` for rapid formatting adjustments.
|
|
117
|
+
- **Dashboard Enhancements**: Added support for explicit `"empty"` layout model objects acting as blank spacers within absolute sizing layouts.
|
|
118
|
+
- **MCP Server Capabilities**: Exposed `configure_worksheet_style` tool expressly to cleanly edit gridlines and aesthetics independently of core configuration.
|
|
119
|
+
|
|
120
|
+
## [0.9.0] - 2026-03-10
|
|
121
|
+
|
|
122
|
+
### Added
|
|
123
|
+
- **Unified Recipe Chart API**: Added `configure_chart_recipe` as the single MCP/server entrypoint for showcase recipes, covering `lollipop`, `donut`, `butterfly`, and `calendar` via one registry-driven dispatcher.
|
|
124
|
+
- **Recipe Validation Coverage**: Added regression tests for unknown recipe rejection, required-argument validation, automatic prerequisite field creation, and full `all_supported_charts` showcase reconstruction through the unified recipe API.
|
|
125
|
+
|
|
126
|
+
### Changed
|
|
127
|
+
- **Recipe Tool Surface**: Replaced the old recipe-specific MCP tools with one `configure_chart_recipe` interface to keep the public API compact as more showcase patterns are added.
|
|
128
|
+
- **Recipe Defaults**: Donut and Calendar recipes now auto-create their standard helper calculations (`min 0` and `Sales Over 400`) when those defaults are used and the fields are missing.
|
|
129
|
+
- **Examples and Prompts**: Updated README, examples, skill docs, and the showcase MCP prompt to teach the unified recipe workflow instead of enumerating one tool per recipe chart.
|
|
130
|
+
|
|
131
|
+
### Removed
|
|
132
|
+
- **Recipe-Specific MCP Tools**: Removed `configure_lollipop_chart`, `configure_donut_chart`, `configure_butterfly_chart`, `configure_calendar_chart`, and `apply_calendar_chart_layout` from the public MCP/server API.
|
|
133
|
+
|
|
134
|
+
## [0.8.0] - 2026-03-09
|
|
135
|
+
|
|
136
|
+
### Added
|
|
137
|
+
- **Capability Registry**: Added a shared capability catalog that classifies chart, encoding, dashboard, action, connection, and feature support into `core`, `advanced`, `recipe`, and `unsupported` tiers.
|
|
138
|
+
- **TWB Gap Analysis**: Added `twb_analyzer.py` plus MCP tools `list_capabilities`, `describe_capability`, `analyze_twb`, and `diff_template_gap` so templates can be evaluated against the declared product boundary before implementation work begins.
|
|
139
|
+
- **Hyper Example Coverage**: Added `tests/test_hyper_example.py` to lock in the Advent Calendar Hyper example's physical `Orders_*` table resolution via Tableau Hyper API.
|
|
140
|
+
|
|
141
|
+
### Changed
|
|
142
|
+
- **Product Positioning**: Updated the root README and example READMEs to describe `twilize` as a workbook engineering toolkit rather than a conversational analysis competitor.
|
|
143
|
+
- **Chart Architecture**: Refactored chart handling into focused modules under `src/twilize/charts/`, including dispatcher, pattern mapping, routing policy, helpers, and a dedicated text builder while keeping the public `configure_chart` API stable.
|
|
144
|
+
- **Dashboard Architecture**: Split dashboard orchestration, layout resolution, datasource dependency generation, and action creation into dedicated modules while keeping `DashboardsMixin` as a thin compatibility facade.
|
|
145
|
+
- **Layout Architecture**: Split declarative layout computation and XML rendering into `layout_model.py` and `layout_rendering.py`, leaving `layout.py` as a compatibility export layer.
|
|
146
|
+
- **MCP Architecture**: Split the MCP server implementation into `mcp/app.py`, `mcp/state.py`, `mcp/resources.py`, `mcp/tools_support.py`, `mcp/tools_layout.py`, and `mcp/tools_workbook.py`, with `server.py` now acting as a thin compatibility entry point.
|
|
147
|
+
- **Advanced Hyper Example**: Updated `examples/hyper_and_new_charts.py` to prefer the Tableau Advent Calendar `Sample - EU Superstore.hyper` extract and resolve the physical `Orders_*` table name automatically.
|
|
148
|
+
|
|
149
|
+
### Fixed
|
|
150
|
+
- **Hyper Extract Selection**: The advanced Hyper example no longer picks the first bundled `.hyper` file opportunistically and instead targets the intended Superstore extract.
|
|
151
|
+
- **Hyper Table Resolution**: The advanced Hyper example now resolves the real physical `Orders_*` table name instead of using an incorrect generic table name.
|
|
152
|
+
|
|
153
|
+
## [0.7.0] - 2026-03-06
|
|
154
|
+
|
|
155
|
+
### Added
|
|
156
|
+
- **Agent Skills Workflow System**: Introduced 4 specialized skill files that provide expert-level guidance to AI agents during dashboard creation, inspired by Jeffrey Shaffer (Tableau Visionary Hall of Fame).
|
|
157
|
+
- `calculation_builder.md` — Phase 1: Parameters, calculated fields, LOD expressions
|
|
158
|
+
- `chart_builder.md` — Phase 2: Chart type selection, encodings, filter strategy
|
|
159
|
+
- `dashboard_designer.md` — Phase 3: Layout design, filter panels, interaction actions
|
|
160
|
+
- `formatting.md` — Phase 4: Number formats, color strategy, sorting, tooltips
|
|
161
|
+
- **Skills MCP Resources**: Skills are exposed via MCP protocol as `twilize://skills/index` and `twilize://skills/{skill_name}`, allowing AI agents to load domain expertise on demand.
|
|
162
|
+
- **Updated MCP Server Instructions**: Server instructions now prompt AI agents to read skills before each phase for professional-quality output.
|
|
163
|
+
|
|
164
|
+
### Changed
|
|
165
|
+
- **ROADMAP**: Updated `docs/ROADMAP.md` — marked completed P0 items (module refactor ✅, version sync ✅), added new Skills workflow section.
|
|
166
|
+
- **Package Build**: Added `artifacts` config in `pyproject.toml` to ensure `.md` skill files are distributed with the PyPI wheel.
|
|
167
|
+
|
|
168
|
+
## [0.6.0] - 2026-03-06
|
|
169
|
+
|
|
170
|
+
### Added
|
|
171
|
+
- **Runtime TWB Validator**: `save()` now automatically validates TWB XML structure before writing to disk. Fatal errors (missing `<workbook>`, `<datasources>`, `<table>`) raise `TWBValidationError` and block saving; non-fatal warnings are logged. Validation can be disabled via `save(path, validate=False)`.
|
|
172
|
+
- **`map_fields` Parameter**: New parameter for `configure_chart(mark_type="Map", ...)` allowing users to specify additional geographic LOD fields (e.g. `map_fields=["Country/Region", "City"]`).
|
|
173
|
+
- **TWBAssert DSL**: Chainable assertion API (`tests/twb_assert.py`) for structural TWB validation in tests, with 20+ assertion methods covering worksheets, encodings, filters, parameters, calculated fields, dashboards, and maps.
|
|
174
|
+
- **Shared Test Fixtures**: Added `tests/conftest.py` with `editor` and `editor_superstore` pytest fixtures.
|
|
175
|
+
- **Structure Test Suite**: 19 new tests in `tests/test_twb_structure.py` covering Bar, Line, Pie, Area, Map, KPI, Parameters, Calculated Fields, Dashboards, and Filters.
|
|
176
|
+
- **Project Roadmap**: Added `docs/ROADMAP.md` with P0–P3 priority issues and feature plans.
|
|
177
|
+
|
|
178
|
+
### Changed
|
|
179
|
+
- **Module Architecture**: Refactored `twb_editor.py` (2083→375 lines) into Mixin classes:
|
|
180
|
+
- `charts.py` (ChartsMixin) — `configure_chart` and 9 chart helper methods
|
|
181
|
+
- `dashboards.py` (DashboardsMixin) — `add_dashboard` and dashboard actions
|
|
182
|
+
- `connections.py` (ConnectionsMixin) — MySQL and Tableau Server connections
|
|
183
|
+
- `parameters.py` (ParametersMixin) — parameter management
|
|
184
|
+
- `config.py` — shared constants and `_generate_uuid`
|
|
185
|
+
- **Version Management**: `__init__.py` now dynamically reads the version from `pyproject.toml` via `importlib.metadata` instead of hardcoding it.
|
|
186
|
+
- **API Exports**: `__init__.py` now exports `TWBEditor`, `FieldRegistry`, and `TWBValidationError`.
|
|
187
|
+
- **Worksheet XML Structure**: Improved `add_worksheet` to generate proper `<panes>/<pane>/<view>` hierarchy, `<style>` element, and `<simple-id>` placement per Tableau XSD schema.
|
|
188
|
+
|
|
189
|
+
### Fixed
|
|
190
|
+
- **Error Handling**: Replaced 6 instances of `except Exception: pass` with specific exception types (`KeyError`, `ValueError`) and proper `logging` output across `twb_editor.py`, `layout.py`.
|
|
191
|
+
- **Circular Import**: Extracted `REFERENCES_DIR` and path constants to `config.py`, eliminating circular imports between `twb_editor.py` and `server.py`.
|
|
192
|
+
- **Redundant Imports**: Removed 4 function-level `import` statements (`re`, `copy`, `dataclasses.replace`) by consolidating them at module level.
|
|
193
|
+
|
|
194
|
+
### Breaking Changes
|
|
195
|
+
- **Map Charts**: `configure_chart(mark_type="Map")` no longer automatically adds `Country/Region` as an LOD field. Users must now explicitly pass `map_fields=["Country/Region"]` if needed.
|
|
196
|
+
|
|
197
|
+
## [0.5.3] - 2026-03-05
|
|
198
|
+
|
|
199
|
+
### Fixed
|
|
200
|
+
- **Calculated Field Parsing**: Improved parameter replacement regex to safely handle both `[ParamName]` and `[Parameters].[ParamName]` formats, preventing double-prefixing and broken expressions.
|
|
201
|
+
|
|
202
|
+
## [0.5.2] - 2026-03-05
|
|
203
|
+
|
|
204
|
+
### Added
|
|
205
|
+
- **Business Profitability Overview Prompt**: Added `examples/prompts/overview_business_demo.md` to demonstrate creating an interactive what-if profitability dashboard with parameters and dashboard actions.
|
|
206
|
+
|
|
207
|
+
### Fixed
|
|
208
|
+
- **Packaging Issues**: Pinned `hatchling<1.27.0` to workaround a `twine` metadata validation error related to `license-files` and fixed Windows encoding issues during package build.
|
|
209
|
+
|
|
210
|
+
## [0.5.1] - 2026-03-04
|
|
211
|
+
|
|
212
|
+
### Changed
|
|
213
|
+
- **License**: Updated project license from MIT to AGPL-3.0-or-later.
|
|
214
|
+
|
|
215
|
+
## [0.5.0] - 2026-03-02
|
|
216
|
+
|
|
217
|
+
### Added
|
|
218
|
+
- **Zero-Config Blank Templates**: The SDK and MCP server now come with a built-in `empty_template.twb` and a minimal `Sample - Superstore - simple.xls` dataset.
|
|
219
|
+
- **Dynamic Connection Resolution**: When initializing `TWBEditor` without a `template_path`, it automatically resolves and rewrites the internal Excel connection to the runtime absolute path of the bundled sample dataset.
|
|
220
|
+
- **Always-Valid Workbooks**: `clear_worksheets()` now guarantees the creation of at least one default worksheet (`Sheet 1`), ensuring generated TWB files are completely valid and openable in Tableau Desktop immediately upon creation.
|
|
221
|
+
|
|
222
|
+
### Changed
|
|
223
|
+
- **MCP Tool `create_workbook`**: The `template_path` parameter is now optional. When omitted, it boots up the zero-config blank template.
|
|
224
|
+
- **XML Element Ordering Fix**: `add_worksheet` and `add_dashboard` now strictly enforce the Tableau XSD schema by smartly inserting XML nodes *before* `<windows>`, `<thumbnails>`, and `<external>` tags instead of appending them at the end.
|
|
225
|
+
|
|
226
|
+
## [0.4.0] - 2026-02-28
|
|
227
|
+
|
|
228
|
+
### Fixed
|
|
229
|
+
- **Dashboard Sizing Bug**: Added `sizing-mode="fixed"` to the dashboard `<size>` element. This ensures that custom dimensions (width/height) specified in `add_dashboard` are correctly enforced by Tableau Desktop.
|
|
230
|
+
|
|
231
|
+
### Added
|
|
232
|
+
- **New Showcase Prompt**: Added `examples/prompts/demo_auto_layout4_prompt.md` in English, demonstrating complex nested layouts with fixed headers and KPIs.
|
|
233
|
+
- **Enhanced Testing**: Added assertions to verify `sizing-mode` in `test_declarative_dashboards.py`.
|
|
234
|
+
|
|
235
|
+
## [0.3.0] - 2026-02-28
|
|
236
|
+
|
|
237
|
+
### Added
|
|
238
|
+
|
|
239
|
+
- **Agentic UX Tool: `generate_layout_json`**:
|
|
240
|
+
- Introduced a dedicated MCP tool tailored for Language Models to handle complex dashboard layouts gracefully avoiding `EOF` (End of File) payload oversize crashes.
|
|
241
|
+
- Automatically wraps standard nested `layout` dicts inside the payload with a human-readable `_ascii_layout_preview`, persisting an easy-to-review design draft to local disk.
|
|
242
|
+
- Generates perfectly calculated XML `<zone>` absolute coordinates (in Tableau's 100,000 scale) for both relative weighting (`weight`) and exact sizes (`fixed_size`).
|
|
243
|
+
- `TWBEditor.add_dashboard()` intelligent parsing:
|
|
244
|
+
- If given a file path, it now smartly unpacks the layout JSON, automatically extracting `"layout_schema"` and safely discarding extraneous metadata (like the ASCII diagram).
|
|
245
|
+
- **Prompt Strategies (`demo_simple.md`)**:
|
|
246
|
+
- Updated the golden prompt strategy guide showing models how to seamlessly split reasoning logic: Step 1 (Tool: write layout to disk) -> Step 2 (Tool: pass file path to build dashboard).
|
|
247
|
+
|
|
248
|
+
## [0.2.0] - 2026-02-28
|
|
249
|
+
|
|
250
|
+
### Added
|
|
251
|
+
|
|
252
|
+
- **Database Connections**:
|
|
253
|
+
- `TWBEditor.set_mysql_connection`: Configure TWB to load data from a Local MySQL database.
|
|
254
|
+
- `TWBEditor.set_tableauserver_connection`: Configure TWB for a Tableau Server hosted datasource.
|
|
255
|
+
- Automatically clears template-included dashboards, worksheets, metadata, and column aliases during config to prevent phantom "ghost" fields.
|
|
256
|
+
- **Dynamic Field Registration**:
|
|
257
|
+
- The `field_registry` will now automatically infer the field type natively via naming heuristics when initializing `configure_chart` on strictly offline unknown schemas.
|
|
258
|
+
- **Declarative JSON Dashboard Layouts**:
|
|
259
|
+
- `add_dashboard` now accepts a deeply nested dictionary (JSON-friendly) `layout` schema, allowing complex, FlexBox-like hierarchical layouts.
|
|
260
|
+
- `add_dashboard` `layout` parameter also directly accepts a file path (string) to a `.json` file, easing the payload size for MCP LLM calls.
|
|
261
|
+
- Generates perfectly calculated XML `<zone>` absolute coordinates (in Tableau's 100,000 scale) for both relative weighting (`weight`) and exact sizes (`fixed_size`).
|
|
262
|
+
- Added `demo_declarative_layout.py` showcasing the JSON engine.
|
|
263
|
+
- **MCP Server Tools**:
|
|
264
|
+
- Exposed `set_mysql_connection` and `set_tableauserver_connection` to the MCP Server.
|
|
265
|
+
- Upgraded `add_dashboard` MCP tool to accept JSON-based dictionaries and JSON file paths for the `layout` schema.
|
|
266
|
+
- **Examples & Documentation**:
|
|
267
|
+
- Reorganized the `examples/` directory into `scripts/` (for Python demos) and `prompts/` (for natural language MCP prompts).
|
|
268
|
+
- Extracted test workflows into runnable demos (`demo_e2e_mcp_workflow.py` and `demo_connections.py`).
|
|
269
|
+
|
|
270
|
+
## [0.1.0] - 2026-02-27
|
|
271
|
+
|
|
272
|
+
### Added
|
|
273
|
+
|
|
274
|
+
- **Core library** (`twilize`):
|
|
275
|
+
- `FieldRegistry`: Field name ↔ TWB internal reference mapping with expression parsing (SUM, AVG, COUNT, YEAR, etc.)
|
|
276
|
+
- `TWBEditor`: lxml-based TWB XML editor supporting:
|
|
277
|
+
- Template loading and field initialization
|
|
278
|
+
- Calculated field management (add/remove)
|
|
279
|
+
- Worksheet creation with configurable chart types (Bar, Line, Pie, Area, Circle, Text, Automatic)
|
|
280
|
+
- Color, size, label, detail, and wedge-size encodings
|
|
281
|
+
- Dashboard creation with layout-flow zone structure (vertical, horizontal, grid-2x2)
|
|
282
|
+
- Valid TWB output compatible with Tableau Desktop
|
|
283
|
+
|
|
284
|
+
- **MCP Server** (`server.py`):
|
|
285
|
+
- 8 atomic tools: `create_workbook`, `list_fields`, `add_calculated_field`, `remove_calculated_field`, `add_worksheet`, `configure_chart`, `add_dashboard`, `save_workbook`
|
|
286
|
+
- FastMCP-based stdio transport
|
|
287
|
+
|
|
288
|
+
- **Dashboard layouts**:
|
|
289
|
+
- Verified against Tableau Dashboard Layout Templates (c.2 (2) reference)
|
|
290
|
+
- Dashboard windows use `<viewpoints>` + `<active>` structure (not `<cards>`)
|
|
291
|
+
- Zone structure uses `layout-flow` with `param='vert'/'horz'`
|
|
292
|
+
|
|
293
|
+
- **Tests**:
|
|
294
|
+
- `test_debug.py`: Step-by-step debug test generating intermediate TWB files
|
|
295
|
+
- `test_e2e.py`: End-to-end integration test covering all MCP tools
|
|
296
|
+
- `test_c2_replica.py`: Full replica of c.2 (2) dashboard layout with 8 worksheets
|
|
297
|
+
|
|
298
|
+
- **Package configuration**:
|
|
299
|
+
- `pyproject.toml` with hatchling build backend
|
|
300
|
+
- `twilize` CLI entry point
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Contributing to twilize
|
|
2
|
+
|
|
3
|
+
## Quick start
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
git clone https://github.com/your-org/twilize
|
|
7
|
+
cd twilize
|
|
8
|
+
pip install -e ".[dev]"
|
|
9
|
+
pytest
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`[dev]` includes local contributor tooling (test/lint/type-check).
|
|
13
|
+
If you only need runtime usage, `pip install -e .` is enough.
|
|
14
|
+
|
|
15
|
+
All tests should pass before you start. If any fail, check the known-issues
|
|
16
|
+
section in `tests/README.md` first.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Architecture overview
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
MCP tool call (tools_workbook.py / tools_migration.py / tools_support.py)
|
|
24
|
+
│
|
|
25
|
+
▼
|
|
26
|
+
ChartsMixin method (src/twilize/charts/__init__.py)
|
|
27
|
+
│ facade: stable public API, no logic
|
|
28
|
+
▼
|
|
29
|
+
Dispatcher function (src/twilize/charts/dispatcher.py)
|
|
30
|
+
│ selects the right builder based on mark_type + routing_policy.py
|
|
31
|
+
▼
|
|
32
|
+
Concrete Builder (builder_basic.py / builder_dual_axis.py / builder_pie.py / …)
|
|
33
|
+
│ constructs the lxml XML subtree for the worksheet
|
|
34
|
+
▼
|
|
35
|
+
TWBEditor XML tree (twb_editor.py via lxml)
|
|
36
|
+
│
|
|
37
|
+
▼
|
|
38
|
+
save() → validate() → .twb / .twbx
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Rule:** Every new parameter must travel the full chain top to bottom.
|
|
42
|
+
Adding it only to the builder but forgetting the MCP tool (or vice versa)
|
|
43
|
+
causes silent divergence between the Python API and the MCP surface.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Module responsibilities
|
|
48
|
+
|
|
49
|
+
| Module | Role |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `twb_editor.py` | Main editor class. Composed from mixins. Owns the lxml tree. |
|
|
52
|
+
| `charts/__init__.py` | `ChartsMixin` — thin public facade, delegates to dispatcher |
|
|
53
|
+
| `charts/dispatcher.py` | Selects builder, forwards all parameters |
|
|
54
|
+
| `charts/routing_policy.py` | Rules for which builder handles which `mark_type` |
|
|
55
|
+
| `charts/builder_base.py` | Shared XML helpers used by all builders |
|
|
56
|
+
| `charts/builder_basic.py` | Bar, Line, Area, Scatter, Heatmap, and other standard marks |
|
|
57
|
+
| `charts/builder_dual_axis.py` | Dual-axis compositions (two panes, synchronized axes) |
|
|
58
|
+
| `charts/builder_pie.py` | Pie and donut (via extra_axes) |
|
|
59
|
+
| `charts/builder_text.py` | Text / KPI cards with rich-text label support |
|
|
60
|
+
| `charts/builder_maps.py` | Filled and symbol maps |
|
|
61
|
+
| `charts/helpers.py` | `apply_worksheet_style`, `setup_table_style`, shared XML primitives |
|
|
62
|
+
| `field_registry.py` | Tracks calculated fields added in this session; used for datasource-dep injection |
|
|
63
|
+
| `capability_registry.py` | Declares what twilize supports; used by `analyze_twb` and `list_capabilities` |
|
|
64
|
+
| `migration.py` | Field-mapping inference and workbook rewrite for datasource migration |
|
|
65
|
+
| `validator.py` | Structural and XSD validation called by `save()` |
|
|
66
|
+
| `mcp/` | MCP server tool definitions (thin wrappers; no logic lives here) |
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Adding a parameter to an existing chart
|
|
71
|
+
|
|
72
|
+
Example: adding `my_param` to `configure_chart`.
|
|
73
|
+
|
|
74
|
+
**Step 1 — Builder** (`builder_basic.py` or whichever builder handles the mark type)
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
class BasicChartBuilder:
|
|
78
|
+
def __init__(self, ..., my_param: str | None = None):
|
|
79
|
+
self.my_param = my_param
|
|
80
|
+
|
|
81
|
+
def build(self):
|
|
82
|
+
...
|
|
83
|
+
if self.my_param:
|
|
84
|
+
# write the relevant XML
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Step 2 — Dispatcher** (`charts/dispatcher.py`)
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
def configure_chart(editor, ..., my_param: str | None = None) -> str:
|
|
91
|
+
...
|
|
92
|
+
builder = BasicChartBuilder(..., my_param=my_param)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Step 3 — ChartsMixin** (`charts/__init__.py`)
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
def configure_chart(self, ..., my_param: str | None = None) -> str:
|
|
99
|
+
return dispatch_configure_chart(self, ..., my_param=my_param)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Step 4 — MCP tool** (`mcp/tools_workbook.py`)
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
@server.tool()
|
|
106
|
+
def configure_chart(..., my_param: str | None = None) -> str:
|
|
107
|
+
return editor.configure_chart(..., my_param=my_param)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Step 5 — Test**
|
|
111
|
+
|
|
112
|
+
Add a test in `tests/` that calls `configure_chart` with the new parameter and
|
|
113
|
+
asserts the expected XML is present using XPath.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Adding a new chart type
|
|
118
|
+
|
|
119
|
+
1. Create `src/twilize/charts/builder_mytype.py` subclassing `BaseChartBuilder`
|
|
120
|
+
2. Add a routing rule in `charts/routing_policy.py`
|
|
121
|
+
3. Import and dispatch in `charts/dispatcher.py`
|
|
122
|
+
4. Declare the capability in `capability_registry.py`
|
|
123
|
+
5. Wire through `ChartsMixin` and the MCP tool if needed
|
|
124
|
+
6. Add at least one test and one example
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Adding a capability to the registry
|
|
129
|
+
|
|
130
|
+
Open `src/twilize/capability_registry.py` and add an entry to `CAPABILITIES`:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
Capability(
|
|
134
|
+
kind="chart",
|
|
135
|
+
name="MyNewChart",
|
|
136
|
+
level="core", # core | advanced | recipe | unsupported
|
|
137
|
+
description="...",
|
|
138
|
+
notes="",
|
|
139
|
+
),
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`level` controls what `list_capabilities` and `analyze_twb` report.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Testing
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Full suite
|
|
150
|
+
pytest
|
|
151
|
+
|
|
152
|
+
# Single file
|
|
153
|
+
pytest tests/test_chart_routing.py -v
|
|
154
|
+
|
|
155
|
+
# Keep temp workbooks for inspection
|
|
156
|
+
pytest --basetemp=output/pytest_tmp
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Tests are integration tests: they build real `.twb` XML and assert structure
|
|
160
|
+
with XPath. There are no mocks of the lxml tree. This is intentional — mocking
|
|
161
|
+
the XML layer has historically hidden bugs that only appear in Tableau Desktop.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Code style
|
|
166
|
+
|
|
167
|
+
- Python 3.10+, no walrus operator in public API signatures
|
|
168
|
+
- `from __future__ import annotations` at the top of every module
|
|
169
|
+
- No logic in MCP tool functions — they are thin wrappers only
|
|
170
|
+
- No silent `except Exception: pass` — log or re-raise with context
|
|
171
|
+
- Imports at the top of files, not inside function bodies
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# ---- Stage 1: Build the frontend ----
|
|
2
|
+
FROM node:20-slim AS frontend-builder
|
|
3
|
+
|
|
4
|
+
WORKDIR /app/extension/frontend
|
|
5
|
+
COPY extension/frontend/package.json extension/frontend/package-lock.json* ./
|
|
6
|
+
RUN npm install
|
|
7
|
+
COPY extension/frontend/ ./
|
|
8
|
+
RUN npm run build
|
|
9
|
+
|
|
10
|
+
# ---- Stage 2: Python runtime ----
|
|
11
|
+
FROM python:3.13-slim
|
|
12
|
+
|
|
13
|
+
WORKDIR /app
|
|
14
|
+
|
|
15
|
+
# Install Python dependencies
|
|
16
|
+
COPY requirements.txt ./
|
|
17
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
18
|
+
|
|
19
|
+
# Copy the full project
|
|
20
|
+
COPY . .
|
|
21
|
+
|
|
22
|
+
# Install the twilize package in editable mode
|
|
23
|
+
RUN pip install --no-cache-dir -e .
|
|
24
|
+
|
|
25
|
+
# Copy the built frontend from stage 1
|
|
26
|
+
COPY --from=frontend-builder /app/extension/frontend/dist /app/extension/frontend/dist
|
|
27
|
+
|
|
28
|
+
# Railway sets $PORT; default to 8000
|
|
29
|
+
ENV PORT=8000
|
|
30
|
+
EXPOSE ${PORT}
|
|
31
|
+
|
|
32
|
+
CMD python -m uvicorn extension.backend.app:app --host 0.0.0.0 --port ${PORT}
|