tableau-cli 0.1.4__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.
- tableau_cli-0.1.5/.agents/plugins/marketplace.json +21 -0
- tableau_cli-0.1.5/.claude-plugin/marketplace.json +14 -0
- tableau_cli-0.1.5/.claude-plugin/plugin.json +11 -0
- tableau_cli-0.1.5/.codex-plugin/plugin.json +17 -0
- tableau_cli-0.1.5/.github/workflows/ci.yml +26 -0
- tableau_cli-0.1.5/.github/workflows/release.yml +75 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/PKG-INFO +39 -29
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/README.md +31 -22
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/pyproject.toml +8 -7
- {tableau_cli-0.1.4/skills → tableau_cli-0.1.5/skills/tableau-cli}/references/cli.md +5 -3
- {tableau_cli-0.1.4/skills → tableau_cli-0.1.5/skills/tableau-cli}/references/installation.md +3 -1
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/cli.py +1 -1
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/commands/convert_cmd.py +6 -0
- tableau_cli-0.1.5/src/tableau_cli/utils/_hyper_export.py +81 -0
- tableau_cli-0.1.5/src/tableau_cli/utils/convert.py +113 -0
- tableau_cli-0.1.5/tests/test_cli.py +20 -0
- tableau_cli-0.1.5/tests/test_conversion.py +283 -0
- tableau_cli-0.1.4/.claude/settings.local.json +0 -8
- tableau_cli-0.1.4/src/tableau_cli/utils/_convert_worker.py +0 -55
- tableau_cli-0.1.4/src/tableau_cli/utils/convert.py +0 -177
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/.gitignore +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/LICENSE +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/NOTICE +0 -0
- {tableau_cli-0.1.4/skills → tableau_cli-0.1.5/skills/tableau-cli}/SKILL.md +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/__init__.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/api/__init__.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/api/client.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/auth/__init__.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/auth/with_auth.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/commands/__init__.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/commands/config_cmd.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/commands/datasources_cmd.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/commands/projects_cmd.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/commands/search_cmd.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/commands/views_cmd.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/commands/workbooks_cmd.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/config/__init__.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/config/store.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/config/types.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/errors/__init__.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/errors/cli_error.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/errors/vds_error_handler.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/output/__init__.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/output/format.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/output/json_output.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/output/table_output.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/utils/__init__.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/utils/datasource_metadata_utils.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/utils/lineage_utils.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/utils/paginate.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/utils/search_content_utils.py +0 -0
- {tableau_cli-0.1.4 → tableau_cli-0.1.5}/src/tableau_cli/utils/tableau_version.py +0 -0
- {tableau_cli-0.1.4 → 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.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: tableau-cli
|
|
3
|
-
Version: 0.1.
|
|
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.
|
|
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:
|
|
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
|
|
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.
|
|
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
|
|
87
|
+
## Use with Coding Agents
|
|
87
88
|
|
|
88
|
-
This repository ships
|
|
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
|
-
|
|
92
|
-
|
|
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
|
-
|
|
98
|
+
To receive updates, enable auto-update for the `tableau-cli` marketplace in `/plugin`, or run `/plugin marketplace update tableau-cli` manually.
|
|
99
|
+
|
|
100
|
+
**Codex**
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
```
|
|
103
|
+
codex plugin marketplace add i-richardwang/tableau-cli
|
|
104
|
+
codex plugin add tableau-cli@tableau-cli
|
|
105
|
+
```
|
|
104
106
|
|
|
105
|
-
|
|
107
|
+
To receive updates, run `codex plugin marketplace upgrade`.
|
|
106
108
|
|
|
107
|
-
|
|
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
|
|
|
@@ -168,10 +170,14 @@ tableau-cli views image <viewId> --vf "Region=West" -o west.png
|
|
|
168
170
|
|
|
169
171
|
Convert local TDSX/HYPER files to Parquet or CSV.
|
|
170
172
|
|
|
171
|
-
Conversion
|
|
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:
|
|
172
174
|
|
|
173
|
-
- Install
|
|
174
|
-
- 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
|
|
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.
|
|
175
181
|
|
|
176
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.
|
|
177
183
|
|
|
@@ -273,8 +279,12 @@ Error types include: `authentication-error`, `feature-disabled`, `tableau-api-er
|
|
|
273
279
|
# Run directly
|
|
274
280
|
python -m tableau_cli.cli views list
|
|
275
281
|
|
|
276
|
-
# Install
|
|
277
|
-
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
|
|
278
288
|
```
|
|
279
289
|
|
|
280
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
|
|
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.
|
|
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
|
|
56
|
+
## Use with Coding Agents
|
|
57
57
|
|
|
58
|
-
This repository ships
|
|
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
|
-
|
|
62
|
-
|
|
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
|
-
|
|
67
|
+
To receive updates, enable auto-update for the `tableau-cli` marketplace in `/plugin`, or run `/plugin marketplace update tableau-cli` manually.
|
|
68
|
+
|
|
69
|
+
**Codex**
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
```
|
|
72
|
+
codex plugin marketplace add i-richardwang/tableau-cli
|
|
73
|
+
codex plugin add tableau-cli@tableau-cli
|
|
74
|
+
```
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
To receive updates, run `codex plugin marketplace upgrade`.
|
|
76
77
|
|
|
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
|
|
|
@@ -138,10 +139,14 @@ tableau-cli views image <viewId> --vf "Region=West" -o west.png
|
|
|
138
139
|
|
|
139
140
|
Convert local TDSX/HYPER files to Parquet or CSV.
|
|
140
141
|
|
|
141
|
-
Conversion
|
|
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:
|
|
142
143
|
|
|
143
|
-
- Install
|
|
144
|
-
- 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
|
|
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.
|
|
145
150
|
|
|
146
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.
|
|
147
152
|
|
|
@@ -243,8 +248,12 @@ Error types include: `authentication-error`, `feature-disabled`, `tableau-api-er
|
|
|
243
248
|
# Run directly
|
|
244
249
|
python -m tableau_cli.cli views list
|
|
245
250
|
|
|
246
|
-
# Install
|
|
247
|
-
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
|
|
248
257
|
```
|
|
249
258
|
|
|
250
259
|
## Acknowledgements
|
|
@@ -4,10 +4,10 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tableau-cli"
|
|
7
|
-
version = "0.1.
|
|
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
|
+
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
|
-
"
|
|
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 = "
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
{tableau_cli-0.1.4/skills → tableau_cli-0.1.5/skills/tableau-cli}/references/installation.md
RENAMED
|
@@ -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
|
-
|
|
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
|
|
|
@@ -43,6 +43,12 @@ def convert_command(input_path, to_fmt, output_path):
|
|
|
43
43
|
else:
|
|
44
44
|
out_p = Path(output_path)
|
|
45
45
|
|
|
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
|
+
|
|
46
52
|
# Convert (in-process if deps present, else via an ephemeral uv environment)
|
|
47
53
|
if suffix == ".hyper":
|
|
48
54
|
run_conversion(input_p, out_p, to_fmt)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Local Hyper exports, shared by the CLI and isolated Python execution."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from tempfile import TemporaryDirectory
|
|
9
|
+
|
|
10
|
+
HYPER_REQUIREMENT = "tableauhyperapi>=0.0.26479"
|
|
11
|
+
SUPPORTED_FORMATS = ("parquet", "csv")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _start_hyper():
|
|
15
|
+
from tableauhyperapi import HyperException, HyperProcess, Telemetry
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
return HyperProcess(
|
|
19
|
+
Telemetry.DO_NOT_SEND_USAGE_DATA_TO_TABLEAU,
|
|
20
|
+
parameters={"log_config": "", "date_style": "YMD"},
|
|
21
|
+
)
|
|
22
|
+
except HyperException as exc:
|
|
23
|
+
raise RuntimeError(
|
|
24
|
+
"Unable to start the local Hyper engine. Use a native 64-bit Python on a supported platform "
|
|
25
|
+
f"and reinstall tableau-cli[convert]. Details: {exc}"
|
|
26
|
+
) from exc
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def check_runtime() -> None:
|
|
30
|
+
"""Verify that the installed Hyper engine can start."""
|
|
31
|
+
with _start_hyper():
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def export_hyper(hyper_path: Path, output_path: Path, to_fmt: str) -> None:
|
|
36
|
+
"""Export a single-table Hyper file, replacing the destination only on success."""
|
|
37
|
+
from tableauhyperapi import Connection, escape_string_literal
|
|
38
|
+
|
|
39
|
+
if to_fmt not in SUPPORTED_FORMATS:
|
|
40
|
+
raise ValueError(f"Unsupported format: {to_fmt}")
|
|
41
|
+
source = hyper_path.resolve()
|
|
42
|
+
destination = output_path.absolute()
|
|
43
|
+
if source == destination.resolve():
|
|
44
|
+
raise ValueError("The output path must differ from the input Hyper file.")
|
|
45
|
+
|
|
46
|
+
with TemporaryDirectory(prefix=".tableau-export-", dir=destination.parent) as td:
|
|
47
|
+
staged = Path(td) / f"data.{to_fmt}"
|
|
48
|
+
with _start_hyper() as hyper, Connection(hyper.endpoint, str(source)) as connection:
|
|
49
|
+
tables = [
|
|
50
|
+
table
|
|
51
|
+
for schema in connection.catalog.get_schema_names()
|
|
52
|
+
for table in connection.catalog.get_table_names(schema)
|
|
53
|
+
]
|
|
54
|
+
if not tables:
|
|
55
|
+
raise ValueError(f"No tables found in {hyper_path.name}")
|
|
56
|
+
if len(tables) != 1:
|
|
57
|
+
raise ValueError(f"Found {len(tables)} tables in {hyper_path.name}, expected 1")
|
|
58
|
+
|
|
59
|
+
options = f"FORMAT => {escape_string_literal(to_fmt)}"
|
|
60
|
+
if to_fmt == "csv":
|
|
61
|
+
options += ", HEADER => true"
|
|
62
|
+
connection.execute_command(f"COPY {tables[0]} TO {escape_string_literal(str(staged))} WITH ({options})")
|
|
63
|
+
staged.replace(destination)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def main() -> None:
|
|
67
|
+
"""Report worker failures as structured JSON for the parent CLI."""
|
|
68
|
+
try:
|
|
69
|
+
if sys.argv[1:] == ["--check"]:
|
|
70
|
+
check_runtime()
|
|
71
|
+
elif len(sys.argv) == 4:
|
|
72
|
+
export_hyper(Path(sys.argv[1]), Path(sys.argv[2]), sys.argv[3])
|
|
73
|
+
else:
|
|
74
|
+
raise ValueError("Expected --check or <hyper_path> <output_path> <parquet|csv>")
|
|
75
|
+
except Exception as exc:
|
|
76
|
+
print(json.dumps({"error_type": "convert-error", "message": str(exc)}))
|
|
77
|
+
sys.exit(1)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
main()
|