Skip to content

Fix #433: accept Classic delete --workbook Name syntax - #451

Open
jacalata wants to merge 2 commits into
developmentfrom
jac/433-delete-classic-syntax
Open

Fix #433: accept Classic delete --workbook Name syntax#451
jacalata wants to merge 2 commits into
developmentfrom
jac/433-delete-classic-syntax

Conversation

@jacalata

@jacalata jacalata commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Closes #433.

Motivation

tabcmd Classic invokes delete as tabcmd delete --workbook "Name"
where --workbook carries the target name as its value. tabcmd 2
shipped tabcmd delete "Name" --workbook (name positional, flag as
type selector). This is a breaking CLI difference for anyone running
Classic scripts against tabcmd 2. Verified against Classic 2025.1 on
main-windows.tsi.lan.

Behavior change

For users: both forms now work.

  • Positional name is now optional (nargs="?").
  • --workbook/--datasource take an optional value (nargs="?").
    Bare form still means True (tabcmd 2 syntax); with a value, the
    value is the target name (Classic syntax).
  • run_command resolves which form supplied the name and normalizes
    args.workbook/args.datasource to True.
  • Mutual exclusion between --workbook and --datasource still holds.
  • If a user passes both a positional and a flag value (e.g. tabcmd delete Name --workbook OtherName), the positional wins and the flag
    value is silently discarded. Not ideal; could be tightened to an
    explicit error in a follow-up.

Test plan

  • tests/parsers/test_parser_delete.py — 11 tests covering: both
    forms, short flags (-w/-d), mutual exclusion, empty parse,
    positional+flag-value conflict, bare --workbook with no value,
    Classic form combined with -r project flag
  • Full unit-test run: 340 passed, 2 skipped
  • Verified live against Classic 2025.1 and tabcmd 2: published 3
    disposable workbooks, deleted via all three combinations (tabcmd 2
    form, tabcmd 2 with Classic-form flag, Classic 2025.1), same outcome
  • run_command normalization not covered here; tracked in Test coverage gap: run_command logic in the recent parity sweep is untested #457

🤖 Generated with Claude Code

tabcmd Classic invokes delete as `tabcmd delete --workbook "Name"` where
--workbook takes the target name as its value. tabcmd 2 shipped
`tabcmd delete "Name" --workbook` (name positional, flag is a type
selector). This is a breaking CLI difference for anyone running Classic
scripts unchanged.

Accept both forms:
- Positional name stays optional (nargs="?").
- --workbook/--datasource take an optional value (nargs="?"). Bare form
  still means True (tabcmd 2 syntax); with a value, the value is the
  target name (Classic syntax).
- In run_command, resolve which form supplied the name and normalize
  args.workbook/args.datasource to True. Emit the same
  "requires workbook or datasource" error when neither form supplied a
  name.

Mutual exclusion between --workbook and --datasource still holds.

Fixes #433.
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
tabcmd
   __main__.py121212 0%
   _version.py111111 0%
   tabcmd.py151515 0%
   version.py955 44%
tabcmd/commands
   commands.py101010 0%
   constants.py771818 77%
   server.py1351818 87%
tabcmd/commands/auth
   session.py3945050 87%
tabcmd/commands/datasources_and_workbooks
   datasources_and_workbooks_command.py1571818 89%
   datasources_workbooks_views_url_parser.py14255 96%
   delete_command.py702323 67%
   export_command.py1202525 79%
   get_url_command.py1274747 63%
   publish_command.py1232828 77%
   runschedule_command.py2177 67%
tabcmd/commands/extracts
   create_extracts_command.py4288 81%
   decrypt_extracts_command.py2722 93%
   delete_extracts_command.py3766 84%
   encrypt_extracts_command.py2722 93%
   extracts.py2022 90%
   reencrypt_extracts_command.py2722 93%
   refresh_extracts_command.py481010 79%
tabcmd/commands/group
   create_group_command.py2955 83%
   delete_group_command.py2722 93%
tabcmd/commands/project
   create_project_command.py4688 83%
   delete_project_command.py3544 89%
   publish_samples_command.py3044 87%
tabcmd/commands/site
   create_site_command.py3455 85%
   delete_site_command.py2722 93%
   edit_site_command.py3822 95%
   list_command.py771212 84%
   list_sites_command.py2922 93%
tabcmd/commands/user
   add_users_command.py2955 83%
   create_site_users.py581111 81%
   create_users_command.py5999 85%
   delete_site_users_command.py4355 88%
   user_data.py2223131 86%
tabcmd/execution
   _version.py222 0%
   global_options.py12588 94%
   localize.py661111 83%
   logger_config.py6066 90%
   tabcmd_controller.py4277 83%
TOTAL288346584% 

Covers gaps flagged in fresh-eyes review:
- `-w` / `-d` short flags on Classic form
- Ambiguous "positional Name + --workbook FlagValue" -- parser accepts
  both; run_command normalization discards flag value
- Bare `--workbook` with no value (parses because nargs="?" const=True)
- Classic form + -r project combined

The run_command normalization itself (`isinstance(args.workbook, str) ->
args.name = args.workbook; args.workbook = True`) is not covered here;
tracked in the follow-up run_command coverage issue.

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.

1 participant