Skip to content

samples: credential helper, pagination fixes, and new jobs/subscriptions samples - #1843

Open
jacalata wants to merge 4 commits into
developmentfrom
jac/samples-improvements
Open

samples: credential helper, pagination fixes, and new jobs/subscriptions samples#1843
jacalata wants to merge 4 commits into
developmentfrom
jac/samples-improvements

Conversation

@jacalata

@jacalata jacalata commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Closes #1551.

Motivation

#1551 flagged three concerns with samples/: credentials always on the
command line, several samples using .get() where they meant to page,
and no examples for background jobs or subscriptions. Each of the three
gets one commit for reviewability.

Behavior change

Samples only -- no library changes. Users running the sample scripts
directly will see:

Credentials. samples/_shared.py adds resolve_credentials(args)
which fills missing sign-in values from env vars
(TABLEAU_SERVER, TABLEAU_TOKEN_NAME, etc.), a plain .env file, or
getpass.getpass(), in that precedence order. CLI args continue to
work for CI use. Wired into login.py, publish_workbook.py, and
publish_datasource.py to establish the pattern; other samples left
alone to keep the diff surgical. Stdlib only, no new deps.

Short flags on the shared helper match tabcmd's canonical set: -s
--server, -t --site, -u --username, -p --password, -l
--logging-level. --token-name and --token-value are long-only.
An earlier iteration of this PR reassigned -p to --token-name; that
was corrected before merge -- see 54e51f5.

Pagination fixes. Several samples called
server.<endpoint>.get() and named the result all_workbooks, which
only returns the first page (default 100). Replaces those with
TSC.Pager(...) so every page is walked. Where a total count was
displayed we still .get() once to grab total_available; that means
one extra request but preserves the count line.

Also fixes an unrelated bug in getting_started/3_hello_universe.py
where the "workbooks" section actually queried datasources.

New samples.

  • list_jobs.py -- background jobs (extract refreshes, publishes,
    flow runs) with .filter() queryset API + wait_for_job
  • manage_subscriptions.py -- list/create/delete subscriptions with
    SubscriptionItem/Target and paginated listing

Not exhaustive on coverage -- data alerts, metrics, tables, databases,
virtual connections still have no dedicated sample. Left for follow-up.

Test plan

samples/ has no automated tests; each check below is manual.

  • python samples/login.py --help shows the new flags with updated help text
  • Setting TABLEAU_TOKEN_NAME / TABLEAU_TOKEN_VALUE in env and running
    python samples/login.py -s <server> signs in with no secrets on the CLI
  • python samples/list_jobs.py --hours 24 lists recent jobs;
    --wait <job_id> blocks until completion
  • python samples/manage_subscriptions.py list prints existing subs;
    create + delete round-trips cleanly
  • Rewritten pagination in explore_datasource.py, explore_workbook.py,
    extracts.py, update_workbook_data_freshness_policy.py, and
    publish_workbook.py returns correct behavior on a >100-item site

🤖 Generated with Claude Code

jacalata added 3 commits July 30, 2026 15:29
Introduces samples/_shared.py with resolve_credentials(args), which fills
missing sign-in values from env vars (TABLEAU_SERVER, TABLEAU_TOKEN_NAME,
etc.) or a .env-style file, and falls back to interactive getpass so
secrets never touch shell history. CLI args still work for CI use.

Wires the new helper into login.py, publish_workbook.py, and
publish_datasource.py to establish the pattern; the remaining samples
still accept the same CLI args and continue to work as before.

Addresses #1551 item 1.
Several samples called `server.<endpoint>.get()` and named the result
`all_workbooks`, `all_datasources`, etc. This only returns the first page
(default 100 items); if the item of interest was not on that page it was
silently missed and the sample failed with a "not found" message.

Replace those calls with `TSC.Pager(server.<endpoint>)` so every page is
walked. Where a total count was being displayed we still make one plain
`.get()` up front so the total_available field is available without
paging through the whole site twice.

Also corrects an unrelated typo in getting_started/3_hello_universe.py
where the "workbooks" section actually queried datasources.

Addresses #1551 item 2 (and #1531).
The existing samples cover workbooks, datasources, schedules, extracts,
projects, users, groups, favorites, and webhooks, but there was no
sample for two frequently asked-about endpoints:

  * list_jobs.py -- lists background jobs (extract refreshes, publishes,
    flow runs, etc.), demonstrating the .filter() queryset with
    date/status/type filters and the wait_for_job helper.
  * manage_subscriptions.py -- list/create/delete site subscriptions,
    demonstrating the SubscriptionItem + Target pattern and paginated
    listing with TSC.Pager.

Both samples use the new samples/_shared.py credential resolver so the
sign-in pattern matches the rest of the samples.

Addresses #1551 item 3.
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
tableauserverclient
   __init__.py50100% 
   config.py150100% 
   datetime_helpers.py2511 96%
   exponential_backoff.py200100% 
   filesys_helpers.py310100% 
   namespace.py2633 88%
tableauserverclient/bin
   __init__.py20100% 
   _version.py358212212 41%
tableauserverclient/helpers
   __init__.py10100% 
   logging.py20100% 
   strings.py3111 97%
tableauserverclient/models
   __init__.py460100% 
   collection_item.py4177 83%
   column_item.py553232 42%
   connection_credentials.py351111 69%
   connection_item.py941414 85%
   custom_view_item.py1442121 85%
   data_acceleration_report_item.py5411 98%
   data_alert_item.py15844 97%
   data_freshness_policy_item.py1551515 90%
   database_item.py2073636 83%
   datasource_item.py3001212 96%
   dqw_item.py10455 95%
   exceptions.py40100% 
   extensions_item.py13244 97%
   extract_item.py4444 91%
   favorites_item.py6988 88%
   fileupload_item.py190100% 
   flow_item.py1491010 93%
   flow_run_item.py710100% 
   group_item.py8966 93%
   groupset_item.py4977 86%
   interval_item.py1823232 82%
   job_item.py1921010 95%
   linked_tasks_item.py7911 99%
   location_item.py2922 93%
   metric_item.py1291313 90%
   oidc_item.py6333 95%
   pagination_item.py3411 97%
   permissions_item.py1111212 89%
   project_item.py2073131 85%
   property_decorators.py1001818 82%
   reference_item.py2622 92%
   revision_item.py5911 98%
   schedule_item.py20966 97%
   server_info_item.py3777 81%
   site_item.py6361313 98%
   subscription_item.py10122 98%
   table_item.py1191818 85%
   tableau_auth.py612525 59%
   tableau_types.py2711 96%
   tag_item.py150100% 
   target.py60100% 
   task_item.py5622 96%
   user_item.py3101818 94%
   view_item.py2201616 93%
   virtual_connection_item.py6488 88%
   webhook_item.py6911 99%
   workbook_item.py3621616 96%
tableauserverclient/server
   __init__.py90100% 
   exceptions.py40100% 
   filter.py2911 97%
   pager.py3311 97%
   query.py1431515 90%
   request_factory.py1335195195 85%
   request_options.py38655 99%
   server.py1882323 88%
   sort.py60100% 
tableauserverclient/server/endpoint
   __init__.py350100% 
   auth_endpoint.py771111 86%
   custom_views_endpoint.py1521212 92%
   data_acceleration_report_endpoint.py210100% 
   data_alert_endpoint.py942323 76%
   databases_endpoint.py1113030 73%
   datasources_endpoint.py3233333 90%
   default_permissions_endpoint.py4433 93%
   dqw_endpoint.py451616 64%
   endpoint.py2122020 91%
   exceptions.py7766 92%
   extensions_endpoint.py310100% 
   favorites_endpoint.py942222 77%
   fileuploads_endpoint.py510100% 
   flow_runs_endpoint.py6299 85%
   flow_task_endpoint.py2122 90%
   flows_endpoint.py1985353 73%
   groups_endpoint.py12699 93%
   groupsets_endpoint.py7277 90%
   jobs_endpoint.py6799 87%
   linked_tasks_endpoint.py370100% 
   metadata_endpoint.py881414 84%
   metrics_endpoint.py5566 89%
   oidc_endpoint.py4211 98%
   permissions_endpoint.py4433 93%
   projects_endpoint.py1782424 87%
   resource_tagger.py1273535 72%
   schedules_endpoint.py1191111 91%
   server_info_endpoint.py361010 72%
   sites_endpoint.py1302727 79%
   subscriptions_endpoint.py561414 75%
   tables_endpoint.py1103636 67%
   tasks_endpoint.py6366 90%
   users_endpoint.py18388 96%
   views_endpoint.py15099 94%
   virtual_connections_endpoint.py1131010 91%
   webhooks_endpoint.py5499 83%
   workbooks_endpoint.py3382222 93%
TOTAL12007142388% 

Restore -t for --site, -u for --username, -p for --password; drop short
flags on --token-name and --token-value. This matches tabcmd's canonical
short flags in tabcmd/execution/parent_parser.py so users running both
tools have one convention to remember.

The initial refactor picked new short flags without noticing that the
old samples/login.py already followed tabcmd's convention (-p was
--password, -t was --site). Reassigning -p to --token-name meant
`python login.py -p <password>` silently sent the password as a token
name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve sample files

1 participant