tableau-cli 0.1.3__tar.gz → 0.1.5__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.
Files changed (51) hide show
  1. tableau_cli-0.1.5/.agents/plugins/marketplace.json +21 -0
  2. tableau_cli-0.1.5/.claude-plugin/marketplace.json +14 -0
  3. tableau_cli-0.1.5/.claude-plugin/plugin.json +11 -0
  4. tableau_cli-0.1.5/.codex-plugin/plugin.json +17 -0
  5. tableau_cli-0.1.5/.github/workflows/ci.yml +26 -0
  6. tableau_cli-0.1.5/.github/workflows/release.yml +75 -0
  7. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/PKG-INFO +42 -27
  8. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/README.md +34 -20
  9. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/pyproject.toml +8 -7
  10. {tableau_cli-0.1.3/skills → tableau_cli-0.1.5/skills/tableau-cli}/references/cli.md +5 -3
  11. {tableau_cli-0.1.3/skills → tableau_cli-0.1.5/skills/tableau-cli}/references/installation.md +3 -1
  12. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/cli.py +1 -1
  13. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/commands/convert_cmd.py +10 -10
  14. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/commands/datasources_cmd.py +2 -2
  15. tableau_cli-0.1.5/src/tableau_cli/utils/_hyper_export.py +81 -0
  16. tableau_cli-0.1.5/src/tableau_cli/utils/convert.py +113 -0
  17. tableau_cli-0.1.5/tests/test_cli.py +20 -0
  18. tableau_cli-0.1.5/tests/test_conversion.py +283 -0
  19. tableau_cli-0.1.3/src/tableau_cli/utils/convert.py +0 -99
  20. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/.gitignore +0 -0
  21. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/LICENSE +0 -0
  22. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/NOTICE +0 -0
  23. {tableau_cli-0.1.3/skills → tableau_cli-0.1.5/skills/tableau-cli}/SKILL.md +0 -0
  24. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/__init__.py +0 -0
  25. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/api/__init__.py +0 -0
  26. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/api/client.py +0 -0
  27. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/auth/__init__.py +0 -0
  28. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/auth/with_auth.py +0 -0
  29. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/commands/__init__.py +0 -0
  30. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/commands/config_cmd.py +0 -0
  31. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/commands/projects_cmd.py +0 -0
  32. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/commands/search_cmd.py +0 -0
  33. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/commands/views_cmd.py +0 -0
  34. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/commands/workbooks_cmd.py +0 -0
  35. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/config/__init__.py +0 -0
  36. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/config/store.py +0 -0
  37. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/config/types.py +0 -0
  38. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/errors/__init__.py +0 -0
  39. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/errors/cli_error.py +0 -0
  40. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/errors/vds_error_handler.py +0 -0
  41. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/output/__init__.py +0 -0
  42. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/output/format.py +0 -0
  43. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/output/json_output.py +0 -0
  44. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/output/table_output.py +0 -0
  45. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/utils/__init__.py +0 -0
  46. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/utils/datasource_metadata_utils.py +0 -0
  47. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/utils/lineage_utils.py +0 -0
  48. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/utils/paginate.py +0 -0
  49. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/utils/search_content_utils.py +0 -0
  50. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/utils/tableau_version.py +0 -0
  51. {tableau_cli-0.1.3 → tableau_cli-0.1.5}/src/tableau_cli/utils/web_url.py +0 -0
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "tableau-cli",
3
+ "interface": {
4
+ "displayName": "Tableau CLI"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "tableau-cli",
9
+ "description": "Interact with Tableau Server / Cloud via tableau-cli: search content, query datasources, download files, export view images and data, convert TDSX/HYPER to Parquet/CSV.",
10
+ "source": {
11
+ "source": "local",
12
+ "path": "./"
13
+ },
14
+ "policy": {
15
+ "installation": "AVAILABLE",
16
+ "authentication": "ON_INSTALL"
17
+ },
18
+ "category": "Productivity"
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "tableau-cli",
3
+ "description": "Claude Code plugin for tableau-cli — a Tableau Server / Cloud CLI designed for AI agent integration.",
4
+ "owner": {
5
+ "name": "Richard Wang"
6
+ },
7
+ "plugins": [
8
+ {
9
+ "name": "tableau-cli",
10
+ "source": "./",
11
+ "description": "Interact with Tableau Server / Cloud via tableau-cli: search content, query datasources, download files, export view images and data, convert TDSX/HYPER to Parquet/CSV."
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "tableau-cli",
3
+ "description": "Interact with Tableau Server / Cloud via tableau-cli: search content, query datasources, download files, export view images and data, convert TDSX/HYPER to Parquet/CSV.",
4
+ "version": "0.1.4",
5
+ "author": {
6
+ "name": "Richard Wang"
7
+ },
8
+ "homepage": "https://github.com/i-richardwang/tableau-cli",
9
+ "repository": "https://github.com/i-richardwang/tableau-cli",
10
+ "license": "Apache-2.0"
11
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "tableau-cli",
3
+ "version": "0.1.4",
4
+ "description": "Interact with Tableau Server / Cloud via tableau-cli: search content, query datasources, download files, export view images and data, convert TDSX/HYPER to Parquet/CSV.",
5
+ "author": {
6
+ "name": "Richard Wang"
7
+ },
8
+ "homepage": "https://github.com/i-richardwang/tableau-cli",
9
+ "repository": "https://github.com/i-richardwang/tableau-cli",
10
+ "license": "Apache-2.0",
11
+ "skills": "./skills/",
12
+ "interface": {
13
+ "displayName": "Tableau CLI",
14
+ "shortDescription": "Drive Tableau Server / Cloud from an agent via tableau-cli",
15
+ "category": "Productivity"
16
+ }
17
+ }
@@ -0,0 +1,26 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - "**"
7
+ pull_request:
8
+
9
+ jobs:
10
+ conversion:
11
+ name: Hyper exports (${{ matrix.os }}, Python ${{ matrix.python }})
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [macos-14, macos-15-intel, windows-latest, ubuntu-latest]
16
+ python: ['3.11', '3.14']
17
+ runs-on: ${{ matrix.os }}
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: astral-sh/setup-uv@v6
21
+ - run: uv python install ${{ matrix.python }}
22
+ - run: uv venv --python ${{ matrix.python }}
23
+ - run: uv pip install -e ".[convert,dev]" "tableauhyperapi==0.0.26479"
24
+ - run: uv run --no-sync ruff check .
25
+ - run: uv run --no-sync pytest
26
+ - run: uv build
@@ -0,0 +1,75 @@
1
+ name: "Publish release to PyPI"
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ # Publish on version tags, e.g. v0.1.0
7
+ - "v[0-9]+.[0-9]+.[0-9]+"
8
+ - "v[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
9
+ - "v[0-9]+.[0-9]+.[0-9]+[ab][0-9]+"
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ permissions:
15
+ contents: read
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
+ with:
20
+ persist-credentials: false
21
+
22
+ - name: Check tag matches package version
23
+ run: |
24
+ version="$(python3 -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
25
+ tag="${GITHUB_REF_NAME#v}"
26
+ if [ "$version" != "$tag" ]; then
27
+ echo "::error::Tag ${GITHUB_REF_NAME} does not match pyproject.toml version ${version}."
28
+ exit 1
29
+ fi
30
+
31
+ - name: Install uv
32
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
33
+ with:
34
+ enable-cache: false
35
+
36
+ - name: Build
37
+ run: uv build
38
+
39
+ - name: Smoke test (wheel)
40
+ run: uv run --isolated --no-project --with dist/*.whl tableau-cli --version | grep -F -x "tableau-cli, version ${GITHUB_REF_NAME#v}"
41
+
42
+ - name: Smoke test (source distribution)
43
+ run: uv run --isolated --no-project --with dist/*.tar.gz tableau-cli --version | grep -F -x "tableau-cli, version ${GITHUB_REF_NAME#v}"
44
+
45
+ - name: Upload distributions as artifacts
46
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
47
+ with:
48
+ name: dist
49
+ path: dist/
50
+
51
+ publish:
52
+ needs:
53
+ - build
54
+ runs-on: ubuntu-latest
55
+ environment:
56
+ name: pypi
57
+ permissions:
58
+ id-token: write
59
+ steps:
60
+ - name: Install uv
61
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
62
+ with:
63
+ enable-cache: false
64
+
65
+ - name: Download distributions artifact
66
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
67
+ with:
68
+ name: dist
69
+ path: dist/
70
+
71
+ - name: Generate PEP 740 attestations
72
+ uses: astral-sh/attest-action@f589a42a7efb6fe400b4f400de60b4bc90390027 # v0.0.6
73
+
74
+ - name: Publish
75
+ run: uv publish --trusted-publishing always
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: tableau-cli
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: CLI for Tableau Server/Cloud, designed for AI agent integration
5
5
  Project-URL: Repository, https://github.com/i-richardwang/tableau-cli
6
6
  Author: Richard Wang
@@ -12,20 +12,21 @@ Classifier: Environment :: Console
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: Apache Software License
14
14
  Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.10
16
15
  Classifier: Programming Language :: Python :: 3.11
17
16
  Classifier: Programming Language :: Python :: 3.12
18
17
  Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
19
  Classifier: Topic :: Software Development :: Libraries
20
- Requires-Python: >=3.10
20
+ Requires-Python: >=3.11
21
21
  Requires-Dist: click>=8.0
22
22
  Requires-Dist: httpx>=0.27
23
23
  Provides-Extra: convert
24
- Requires-Dist: pantab>=4.0; extra == 'convert'
25
- Requires-Dist: polars>=1.0; extra == 'convert'
26
- Requires-Dist: pyarrow>=15.0; extra == 'convert'
24
+ Requires-Dist: tableauhyperapi>=0.0.26479; extra == 'convert'
27
25
  Provides-Extra: dev
26
+ Requires-Dist: pyarrow>=15.0; extra == 'dev'
27
+ Requires-Dist: pytest>=8.0; extra == 'dev'
28
28
  Requires-Dist: ruff>=0.11; extra == 'dev'
29
+ Requires-Dist: tzdata; extra == 'dev'
29
30
  Description-Content-Type: text/markdown
30
31
 
31
32
  # tableau-cli
@@ -36,7 +37,7 @@ A command-line interface for Tableau Server / Tableau Cloud, designed for AI age
36
37
 
37
38
  MCP (Model Context Protocol) servers continuously occupy agent context — every tool description is loaded into the system prompt, even when only one command is needed. A CLI follows a simpler call-execute-exit pattern: the agent invokes a command, reads the JSON output, and moves on.
38
39
 
39
- The companion Claude Code skill under `skills/` extends the same idea to command knowledge — the full reference is loaded only when the agent is about to execute a command, not kept in context upfront. See [Use with Claude Code](#use-with-claude-code) below.
40
+ The companion agent skill under `skills/` extends the same idea to command knowledge — the full reference is loaded only when the agent is about to execute a command, not kept in context upfront. See [Use with Coding Agents](#use-with-coding-agents) below.
40
41
 
41
42
  This project provides the same capabilities as the [tableau-mcp](https://github.com/tableau/tableau-mcp) server, with behavioral alignment in data transformations, error handling, and output structures.
42
43
 
@@ -44,7 +45,7 @@ This project provides the same capabilities as the [tableau-mcp](https://github.
44
45
 
45
46
  ### Prerequisites
46
47
 
47
- - Python >= 3.10
48
+ - Python >= 3.11
48
49
  - A Tableau Server or Tableau Cloud instance
49
50
  - A [Personal Access Token (PAT)](https://help.tableau.com/current/server/en-us/security_personal_access_tokens.htm)
50
51
 
@@ -83,28 +84,29 @@ Environment variables take precedence over the config file. `siteName` defaults
83
84
  tableau-cli config show
84
85
  ```
85
86
 
86
- ## Use with Claude Code
87
+ ## Use with Coding Agents
87
88
 
88
- This repository ships with a Claude Code skill under `skills/`. Once loaded, it gives an agent enough context to route a user's request to the right command — without putting the full CLI reference into the system prompt.
89
+ This repository ships an agent skill (`skills/tableau-cli/`) that routes a user's request to the right command and loads the full CLI reference only at execution time. The repository doubles as its own plugin marketplace for both Claude Code and Codex.
90
+
91
+ **Claude Code**
89
92
 
90
93
  ```
91
- skills/
92
- ├── SKILL.md # Intent routing + environment check
93
- └── references/
94
- ├── cli.md # Full command reference (loaded before executing)
95
- └── installation.md # Install + auth setup (loaded if not configured)
94
+ /plugin marketplace add i-richardwang/tableau-cli
95
+ /plugin install tableau-cli@tableau-cli
96
96
  ```
97
97
 
98
- Once Claude Code has loaded the skill, a typical interaction looks like:
98
+ To receive updates, enable auto-update for the `tableau-cli` marketplace in `/plugin`, or run `/plugin marketplace update tableau-cli` manually.
99
99
 
100
- 1. The agent runs `tableau-cli --help` to verify the CLI is installed and configured. If not, it loads `references/installation.md` and stops until setup is complete.
101
- 2. The agent maps the user's intent to a subcommand using the Intent Routing table in `SKILL.md` (e.g., "find datasources with Sales in the name" → `ds list --filter "name:has:Sales"`).
102
- 3. Before constructing the actual command, the agent loads `references/cli.md` — the skill explicitly forbids guessing flags from memory, so the reference is the source of truth for syntax.
103
- 4. The agent runs the command and parses the structured JSON output, including the `hint` field on errors.
100
+ **Codex**
104
101
 
105
- Common workflows (e.g., `ds download --to parquet → load with Polars/Pandas`) are pre-defined under Intent Routing in `SKILL.md`, so the agent doesn't have to reason about chaining from scratch.
102
+ ```
103
+ codex plugin marketplace add i-richardwang/tableau-cli
104
+ codex plugin add tableau-cli@tableau-cli
105
+ ```
106
106
 
107
- You can of course use `tableau-cli` directly from a shell without the skill — the skill is only needed when you want an agent to drive the tool.
107
+ To receive updates, run `codex plugin marketplace upgrade`.
108
+
109
+ The skill is only needed when an agent drives the tool — the CLI works standalone from any shell.
108
110
 
109
111
  ## Commands
110
112
 
@@ -128,7 +130,7 @@ tableau-cli ds list --filter "name:has:Sales" --limit 50
128
130
  # Download datasource file (.tdsx)
129
131
  tableau-cli datasources download <datasourceId> -o ./data/
130
132
 
131
- # Download and convert to Parquet or CSV in one step (requires tableau-cli[convert])
133
+ # Download and convert to Parquet or CSV in one step (requires tableau-cli[convert] or uv)
132
134
  tableau-cli ds download <datasourceId> -o ./data/ --to parquet
133
135
  tableau-cli ds download <datasourceId> -o ./data/ --to csv
134
136
 
@@ -166,7 +168,16 @@ tableau-cli views image <viewId> --vf "Region=West" -o west.png
166
168
 
167
169
  ### Convert
168
170
 
169
- Convert local TDSX/HYPER files to Parquet or CSV. Requires `pip install tableau-cli[convert]`.
171
+ Convert local TDSX/HYPER files to Parquet or CSV.
172
+
173
+ Conversion runs locally through the official `tableauhyperapi` package. Its native Hyper engine exports directly to Parquet or CSV, without loading the entire extract into a DataFrame. You have two options:
174
+
175
+ - Install the export dependency into the CLI: `pip install tableau-cli[convert]`.
176
+ - Don't install anything: if [uv](https://docs.astral.sh/uv/) is on your `PATH`, conversion transparently falls back to running the step in an ephemeral `uv run --with ...` environment, so the conversion dependency never lands in your host Python. The first run provisions the environment (a few seconds); later runs use uv's cache. This is the recommended path when the CLI itself was installed via `uv tool install tableau-cli`.
177
+
178
+ The conversion runtime requires native 64-bit Python 3.11 or newer. Supported targets are Apple Silicon Macs (macOS 13+), Intel Macs, Windows x86_64, and the Linux x86_64 distributions supported by [Hyper API](https://tableau.github.io/hyper-db/docs/installation/). Package installation selects the engine for the interpreter's platform; Apple Silicon uses the native ARM package.
179
+
180
+ Each extract must contain exactly one table. Exports preserve column order and use Hyper's native [Parquet and CSV mappings](https://developer.salesforce.com/docs/data/data-cloud-query-guide/references/dc-sql-reference/copy-to.html). CSV includes a header and uses ISO dates. The destination is replaced only after a complete export. Download-and-convert commands check that the local engine can start before downloading the datasource.
170
181
 
171
182
  For most use cases, `ds download --to parquet` (or `--to csv`) is simpler — it downloads and converts in one step. The `convert` command is useful when you already have a `.tdsx` or `.hyper` file on disk.
172
183
 
@@ -268,8 +279,12 @@ Error types include: `authentication-error`, `feature-disabled`, `tableau-api-er
268
279
  # Run directly
269
280
  python -m tableau_cli.cli views list
270
281
 
271
- # Install in editable mode
272
- pip install -e .
282
+ # Install development and conversion dependencies
283
+ pip install -e ".[convert,dev]"
284
+
285
+ # Validate local exports and isolated uv execution
286
+ ruff check .
287
+ pytest
273
288
  ```
274
289
 
275
290
  ## Acknowledgements
@@ -6,7 +6,7 @@ A command-line interface for Tableau Server / Tableau Cloud, designed for AI age
6
6
 
7
7
  MCP (Model Context Protocol) servers continuously occupy agent context — every tool description is loaded into the system prompt, even when only one command is needed. A CLI follows a simpler call-execute-exit pattern: the agent invokes a command, reads the JSON output, and moves on.
8
8
 
9
- The companion Claude Code skill under `skills/` extends the same idea to command knowledge — the full reference is loaded only when the agent is about to execute a command, not kept in context upfront. See [Use with Claude Code](#use-with-claude-code) below.
9
+ The companion agent skill under `skills/` extends the same idea to command knowledge — the full reference is loaded only when the agent is about to execute a command, not kept in context upfront. See [Use with Coding Agents](#use-with-coding-agents) below.
10
10
 
11
11
  This project provides the same capabilities as the [tableau-mcp](https://github.com/tableau/tableau-mcp) server, with behavioral alignment in data transformations, error handling, and output structures.
12
12
 
@@ -14,7 +14,7 @@ This project provides the same capabilities as the [tableau-mcp](https://github.
14
14
 
15
15
  ### Prerequisites
16
16
 
17
- - Python >= 3.10
17
+ - Python >= 3.11
18
18
  - A Tableau Server or Tableau Cloud instance
19
19
  - A [Personal Access Token (PAT)](https://help.tableau.com/current/server/en-us/security_personal_access_tokens.htm)
20
20
 
@@ -53,28 +53,29 @@ Environment variables take precedence over the config file. `siteName` defaults
53
53
  tableau-cli config show
54
54
  ```
55
55
 
56
- ## Use with Claude Code
56
+ ## Use with Coding Agents
57
57
 
58
- This repository ships with a Claude Code skill under `skills/`. Once loaded, it gives an agent enough context to route a user's request to the right command — without putting the full CLI reference into the system prompt.
58
+ This repository ships an agent skill (`skills/tableau-cli/`) that routes a user's request to the right command and loads the full CLI reference only at execution time. The repository doubles as its own plugin marketplace for both Claude Code and Codex.
59
+
60
+ **Claude Code**
59
61
 
60
62
  ```
61
- skills/
62
- ├── SKILL.md # Intent routing + environment check
63
- └── references/
64
- ├── cli.md # Full command reference (loaded before executing)
65
- └── installation.md # Install + auth setup (loaded if not configured)
63
+ /plugin marketplace add i-richardwang/tableau-cli
64
+ /plugin install tableau-cli@tableau-cli
66
65
  ```
67
66
 
68
- Once Claude Code has loaded the skill, a typical interaction looks like:
67
+ To receive updates, enable auto-update for the `tableau-cli` marketplace in `/plugin`, or run `/plugin marketplace update tableau-cli` manually.
69
68
 
70
- 1. The agent runs `tableau-cli --help` to verify the CLI is installed and configured. If not, it loads `references/installation.md` and stops until setup is complete.
71
- 2. The agent maps the user's intent to a subcommand using the Intent Routing table in `SKILL.md` (e.g., "find datasources with Sales in the name" → `ds list --filter "name:has:Sales"`).
72
- 3. Before constructing the actual command, the agent loads `references/cli.md` — the skill explicitly forbids guessing flags from memory, so the reference is the source of truth for syntax.
73
- 4. The agent runs the command and parses the structured JSON output, including the `hint` field on errors.
69
+ **Codex**
74
70
 
75
- Common workflows (e.g., `ds download --to parquet → load with Polars/Pandas`) are pre-defined under Intent Routing in `SKILL.md`, so the agent doesn't have to reason about chaining from scratch.
71
+ ```
72
+ codex plugin marketplace add i-richardwang/tableau-cli
73
+ codex plugin add tableau-cli@tableau-cli
74
+ ```
76
75
 
77
- You can of course use `tableau-cli` directly from a shell without the skill — the skill is only needed when you want an agent to drive the tool.
76
+ To receive updates, run `codex plugin marketplace upgrade`.
77
+
78
+ The skill is only needed when an agent drives the tool — the CLI works standalone from any shell.
78
79
 
79
80
  ## Commands
80
81
 
@@ -98,7 +99,7 @@ tableau-cli ds list --filter "name:has:Sales" --limit 50
98
99
  # Download datasource file (.tdsx)
99
100
  tableau-cli datasources download <datasourceId> -o ./data/
100
101
 
101
- # Download and convert to Parquet or CSV in one step (requires tableau-cli[convert])
102
+ # Download and convert to Parquet or CSV in one step (requires tableau-cli[convert] or uv)
102
103
  tableau-cli ds download <datasourceId> -o ./data/ --to parquet
103
104
  tableau-cli ds download <datasourceId> -o ./data/ --to csv
104
105
 
@@ -136,7 +137,16 @@ tableau-cli views image <viewId> --vf "Region=West" -o west.png
136
137
 
137
138
  ### Convert
138
139
 
139
- Convert local TDSX/HYPER files to Parquet or CSV. Requires `pip install tableau-cli[convert]`.
140
+ Convert local TDSX/HYPER files to Parquet or CSV.
141
+
142
+ Conversion runs locally through the official `tableauhyperapi` package. Its native Hyper engine exports directly to Parquet or CSV, without loading the entire extract into a DataFrame. You have two options:
143
+
144
+ - Install the export dependency into the CLI: `pip install tableau-cli[convert]`.
145
+ - Don't install anything: if [uv](https://docs.astral.sh/uv/) is on your `PATH`, conversion transparently falls back to running the step in an ephemeral `uv run --with ...` environment, so the conversion dependency never lands in your host Python. The first run provisions the environment (a few seconds); later runs use uv's cache. This is the recommended path when the CLI itself was installed via `uv tool install tableau-cli`.
146
+
147
+ The conversion runtime requires native 64-bit Python 3.11 or newer. Supported targets are Apple Silicon Macs (macOS 13+), Intel Macs, Windows x86_64, and the Linux x86_64 distributions supported by [Hyper API](https://tableau.github.io/hyper-db/docs/installation/). Package installation selects the engine for the interpreter's platform; Apple Silicon uses the native ARM package.
148
+
149
+ Each extract must contain exactly one table. Exports preserve column order and use Hyper's native [Parquet and CSV mappings](https://developer.salesforce.com/docs/data/data-cloud-query-guide/references/dc-sql-reference/copy-to.html). CSV includes a header and uses ISO dates. The destination is replaced only after a complete export. Download-and-convert commands check that the local engine can start before downloading the datasource.
140
150
 
141
151
  For most use cases, `ds download --to parquet` (or `--to csv`) is simpler — it downloads and converts in one step. The `convert` command is useful when you already have a `.tdsx` or `.hyper` file on disk.
142
152
 
@@ -238,8 +248,12 @@ Error types include: `authentication-error`, `feature-disabled`, `tableau-api-er
238
248
  # Run directly
239
249
  python -m tableau_cli.cli views list
240
250
 
241
- # Install in editable mode
242
- pip install -e .
251
+ # Install development and conversion dependencies
252
+ pip install -e ".[convert,dev]"
253
+
254
+ # Validate local exports and isolated uv execution
255
+ ruff check .
256
+ pytest
243
257
  ```
244
258
 
245
259
  ## Acknowledgements
@@ -4,10 +4,10 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "tableau-cli"
7
- version = "0.1.3"
7
+ version = "0.1.5"
8
8
  description = "CLI for Tableau Server/Cloud, designed for AI agent integration"
9
9
  license = "Apache-2.0"
10
- requires-python = ">=3.10"
10
+ requires-python = ">=3.11"
11
11
  readme = "README.md"
12
12
  authors = [
13
13
  { name = "Richard Wang" },
@@ -18,10 +18,10 @@ classifiers = [
18
18
  "Intended Audience :: Developers",
19
19
  "License :: OSI Approved :: Apache Software License",
20
20
  "Programming Language :: Python :: 3",
21
- "Programming Language :: Python :: 3.10",
22
21
  "Programming Language :: Python :: 3.11",
23
22
  "Programming Language :: Python :: 3.12",
24
23
  "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
25
  "Topic :: Software Development :: Libraries",
26
26
  ]
27
27
  dependencies = [
@@ -34,12 +34,13 @@ Repository = "https://github.com/i-richardwang/tableau-cli"
34
34
 
35
35
  [project.optional-dependencies]
36
36
  convert = [
37
- "pantab>=4.0",
38
- "polars>=1.0",
39
- "pyarrow>=15.0",
37
+ "tableauhyperapi>=0.0.26479",
40
38
  ]
41
39
  dev = [
42
40
  "ruff>=0.11",
41
+ "pytest>=8.0",
42
+ "pyarrow>=15.0",
43
+ "tzdata",
43
44
  ]
44
45
 
45
46
  [project.scripts]
@@ -49,7 +50,7 @@ tableau-cli = "tableau_cli.cli:main"
49
50
  packages = ["src/tableau_cli"]
50
51
 
51
52
  [tool.ruff]
52
- target-version = "py310"
53
+ target-version = "py311"
53
54
  line-length = 120
54
55
 
55
56
  [tool.ruff.lint]
@@ -78,7 +78,7 @@ tableau-cli ds download <datasource-id> -o ./output/ --to csv
78
78
 
79
79
  Output: `{"filePath": "<absolute path>"}`
80
80
 
81
- When `--to parquet` or `--to csv` is specified, the datasource is downloaded, converted in a temporary directory, and only the final file is written to the output path. Requires `tableau-cli[convert]` extras.
81
+ When `--to parquet` or `--to csv` is specified, the datasource is downloaded, converted in a temporary directory, and only the final file is written to the output path. Runs locally through Hyper API; requires `tableau-cli[convert]` or `uv` on `PATH`.
82
82
 
83
83
  ### ds metadata
84
84
 
@@ -256,7 +256,7 @@ Results include name, description, parent project, content permissions, owner, a
256
256
 
257
257
  ## convert
258
258
 
259
- Local file conversion: TDSX/HYPER → Parquet/CSV. Requires `tableau-cli[convert]`.
259
+ Local file conversion: TDSX/HYPER → Parquet/CSV. Uses the official local Hyper engine; requires `tableau-cli[convert]` or `uv` on `PATH`.
260
260
 
261
261
  ```bash
262
262
  tableau-cli convert data.tdsx
@@ -273,7 +273,9 @@ tableau-cli convert extract.hyper -o ./output/result.parquet
273
273
 
274
274
  Output: `{"filePath": "<absolute path>"}`
275
275
 
276
- Reports `missing-dependencies` error if convert extras are not installed, with hint to run `pip install "tableau-cli[convert]"`.
276
+ Requires exactly one table per extract. CSV includes a header and uses ISO dates; Parquet uses Hyper's native type mappings. The output is replaced only after a successful export.
277
+
278
+ Reports `missing-dependencies` when neither Hyper API nor `uv` is available. Engine startup and export failures are reported as `convert-error`.
277
279
 
278
280
  ---
279
281
 
@@ -9,7 +9,9 @@ description: Installation and authentication setup for tableau-cli. Load when th
9
9
  pip install "tableau-cli[convert]"
10
10
  ```
11
11
 
12
- Without `[convert]`, only core features are available (search, datasources, views, workbooks) — the `convert` command and `ds download --to parquet/csv` will not work.
12
+ Requires Python 3.11 or newer. The `[convert]` extra installs the official `tableauhyperapi` package for local Parquet/CSV exports. Use native 64-bit Python on Apple Silicon or Intel macOS, Windows x86_64, or a supported Linux x86_64 distribution.
13
+
14
+ Alternatively, install the core CLI and keep `uv` on `PATH`. Conversion then runs in an isolated environment provisioned automatically by `uv`; the first run installs the export dependency and later runs reuse the cache. Core commands do not need conversion dependencies.
13
15
 
14
16
  ## Upgrade
15
17
 
@@ -123,7 +123,7 @@ class TableauCli(click.Group):
123
123
 
124
124
 
125
125
  @click.group(cls=TableauCli)
126
- @click.version_option("0.1.3")
126
+ @click.version_option(package_name="tableau-cli")
127
127
  def cli():
128
128
  """CLI tool for interacting with Tableau Server/Cloud."""
129
129
 
@@ -11,10 +11,8 @@ from ..errors.cli_error import CliError
11
11
  from ..output.format import output
12
12
  from ..utils.convert import (
13
13
  SUPPORTED_FORMATS,
14
- check_convert_deps,
15
14
  extract_hyper_from_tdsx,
16
- read_hyper,
17
- write_df,
15
+ run_conversion,
18
16
  )
19
17
 
20
18
 
@@ -26,8 +24,6 @@ from ..utils.convert import (
26
24
  @click.option("-o", "--output", "output_path", default=None, help="Output file or directory (default: same as input)")
27
25
  def convert_command(input_path, to_fmt, output_path):
28
26
  """Convert TDSX/HYPER files to Parquet or CSV format."""
29
- check_convert_deps()
30
-
31
27
  input_p = Path(input_path)
32
28
  suffix = input_p.suffix.lower()
33
29
 
@@ -47,15 +43,19 @@ def convert_command(input_path, to_fmt, output_path):
47
43
  else:
48
44
  out_p = Path(output_path)
49
45
 
50
- # Read hyper data
46
+ if input_p.resolve() == out_p.resolve():
47
+ raise CliError(
48
+ error_type="invalid-input",
49
+ message="The output path must differ from the input file.",
50
+ )
51
+
52
+ # Convert (in-process if deps present, else via an ephemeral uv environment)
51
53
  if suffix == ".hyper":
52
- df = read_hyper(input_p)
54
+ run_conversion(input_p, out_p, to_fmt)
53
55
  else:
54
56
  with TemporaryDirectory() as td:
55
57
  hyper_path = extract_hyper_from_tdsx(input_p, Path(td))
56
- df = read_hyper(hyper_path)
57
-
58
- write_df(df, out_p, to_fmt)
58
+ run_conversion(hyper_path, out_p, to_fmt)
59
59
 
60
60
  abs_path = os.path.abspath(out_p)
61
61
  sys.stderr.write(f"Converted to {abs_path}\n")
@@ -65,9 +65,9 @@ def datasources_download(datasource_id, output_path, to_fmt):
65
65
  config = resolve_config()
66
66
 
67
67
  if to_fmt != "tdsx":
68
- from ..utils.convert import check_convert_deps
68
+ from ..utils.convert import ensure_convert_available
69
69
 
70
- check_convert_deps()
70
+ ensure_convert_available()
71
71
 
72
72
  data, filename = with_auth(
73
73
  config,