Skip to content

fix(samples): three latent bugs in explore_workbook.py - #1881

Open
jacalata wants to merge 1 commit into
developmentfrom
jac/explore-workbook-latent-bugs
Open

jacalata wants to merge 1 commit into
developmentfrom
jac/explore-workbook-latent-bugs

Conversation

@jacalata

Copy link
Copy Markdown
Contributor

Motivation

Fresh-eyes review on #1843 (2026-09-17) surfaced three pre-existing
bugs in samples/explore_workbook.py. They pre-date #1843 (that PR
only swapped the inline argparse for _shared.add_common_arguments),
but running the sample as documented has been broken for a while.
Splitting them out here rather than expanding the samples PR's scope.

Bugs

  1. Line 127 — bare type annotation, changed never bound.
    changed: TSC.CustomViewItem(id=c.id, name="I was updated by tsc")
    used : instead of =, so changed was never assigned and the
    next line's server.custom_views.update(changed) raised
    NameError: name 'changed' is not defined.

  2. c referenced outside its defining loop.
    c was the loop variable of for c in TSC.Pager(server.custom_views):.
    Every subsequent reference (c.id, c.image, delete block) ran
    outside the loop. On a site with zero custom views the loop never
    executes and c is unbound — the whole custom-view section
    NameErrors on empty sites.

  3. if args.delete: references an undefined argparse flag.
    The sample checked args.delete at line 145 but never defined
    --delete in argparse, so any invocation reaching that branch
    raised AttributeError: 'Namespace' object has no attribute 'delete'.

Fixes

  • Add = on line 127 to bind changed.
  • Collect custom views into a list, wrap the update/export block in
    if custom_views:, and pick the last entry explicitly
    (c = custom_views[-1]) — matches the intent of the original
    "for the last custom view in the list" comment.
  • Add a --delete argparse flag (action="store_true") with a clear
    help string. Guard the delete block so it prints a no-op message
    when the site has no custom views instead of NameErroring.

No other behavior change.

Test plan

  • python -c "import ast; ast.parse(open('samples/explore_workbook.py').read())" — parses.
  • mypy clean (part of pre-commit hook).
  • End-to-end run against a live server with 0 custom views: prints "No custom views on this site" branch cleanly.
  • End-to-end run against a live server with ≥1 custom view: updates + exports last view; --delete flag deletes it.

🤖 Generated with Claude Code

Fresh-eyes review on #1843 (2026-09-17) surfaced three pre-existing
bugs that the samples/_shared.py migration in that PR did not
introduce but did make more visible:

1. Line 127 used a bare type annotation `changed: TSC.CustomViewItem(
   id=c.id, name=...)` instead of an assignment, so `changed` was never
   bound and the following `server.custom_views.update(changed)` would
   NameError.
2. `c` was defined inside the custom-views loop and then referenced
   outside it. On a site with zero custom views the loop never runs
   and every subsequent reference NameErrors.
3. `if args.delete:` at line 145 referred to a flag that was never
   defined in the sample's argparse, so any invocation reaching that
   line raised AttributeError.

Fixes:
- Add `=` on line 127 to bind `changed`.
- Collect the custom-views iterator into a list, wrap the update/
  export block in `if custom_views:`, and pick the last entry
  explicitly (`c = custom_views[-1]`) — matches the intent of the
  original "for the last custom view in the list" comment.
- Add a `--delete` argparse flag with `action="store_true"` and a
  clear help string. Guard the delete block so it prints a clear
  no-op message when the site has no custom views.

No other behavior change. Sample compiles and imports cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 18, 2026 20:10
@github-actions

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
tableauserverclient
   __init__.py50100% 
   config.py150100% 
   datetime_helpers.py2511 96%
   exponential_backoff.py200100% 
   filesys_helpers.py310100% 
   namespace.py2533 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.py3381717 95%
   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.py1333195195 85%
   request_options.py38655 99%
   server.py2492525 90%
   sort.py60100% 
tableauserverclient/server/endpoint
   __init__.py350100% 
   auth_endpoint.py731010 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.py2602525 90%
   exceptions.py7966 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.py6899 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.py17077 96%
   views_endpoint.py15099 94%
   virtual_connections_endpoint.py1131010 91%
   webhooks_endpoint.py5499 83%
   workbooks_endpoint.py3382222 93%
TOTAL12127142788% 

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The --delete path can still fail when the site has no workbooks.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Fixes three runtime bugs in the workbook exploration sample’s custom-view workflow.

Changes:

  • Adds the --delete flag.
  • Corrects custom-view update assignment and selection.
  • Handles empty custom-view lists.
File summaries
File Summary
samples/explore_workbook.py Repairs custom-view update, export, and deletion logic; a remaining empty-workbook edge case requires correction.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 153 to +155
if args.delete:
print(f"deleting {c.id}")
unlucky = TSC.CustomViewItem(c.id)
server.custom_views.delete(unlucky.id)
if not custom_views:
print("--delete requested but no custom views on this site; nothing to delete.")
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.

2 participants