GeezerVison is showing github.com — docs+feat: VirtualConnections docstrings, tag parsing, id workaround by jacalata · Pull Request #1858 · tableau/server-client-python
Conversation
jacalata
commented
Aug 11, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Closes #1569.
Motivation
Virtual Connections is the largest remaining chunk in the
needs-docstring bucket per the api-ref migration audit: 14 of the 27
remaining public endpoint methods without docstrings, once the 15
Favorites methods from #1855 land.
While backfilling the docstrings I confirmed via server code + a live
test that the REST endpoint now returns tags on virtual-connection
responses (added server-side in W-21424436, shipping in Tableau Server
2026.2 / Cloud April 2026 / REST API 3.30). VirtualConnectionItem
wasn't parsing them, so the diff-based update_tags couldn't work and
had a NotImplementedError override. Extending the PR to close that
gap now that the server side is available.
Also uncovered two adjacent server-side gaps while implementing this;
both filed on the server team:
- W-23806318 (Tableau CX-DevDocs): public REST API docs still
describe the pre-2026.2 response schema, without <tags>.
- W-23806343 (TDP - VConns):
Get Virtual Connection REST response
omits the id attribute on the <virtualConnection> element even
though List Virtual Connections includes it. Working around
client-side in this PR by stamping the id back from the request path.
Behavior change
For users:
- All 14
VirtualConnections methods now have numpy-style docstrings
ported from api-ref.md, plus a class-level docstring. Content is
unchanged; the generated Sphinx output (docs: set up Sphinx + ReadTheDocs pipeline for auto-generated API reference #1832) will cover what the
handwritten api-ref.md page does today.
VirtualConnectionItem now parses <tags> from responses into
tags: set[str] (populated) and _initial_tags: set[str]
(immutable copy for diff purposes). On pre-2026.2 servers the
response omits <tags> and both attributes are empty sets.
VirtualConnections.update_tags(vc) works for the standard
mutate-and-push pattern: fetch a VC, add/remove entries from
vc.tags, call update_tags. Gated on @api(version="3.30") so
older servers (where _initial_tags would always be empty and
removes would silently no-op) fail loudly at the version check
instead.
VirtualConnections.get_by_id now returns an item with .id set
even though the server response omits it. Downstream calls
(add_tags, delete_tags, update_tags) require the id.
Also bundled (small):
add_permissions and delete_permission grow proper type hints so
the docstring claims and the signatures agree.
- Renamed permissions params to a consistent
virtual_connection
throughout the class.
- Renamed
delete_permission's second parameter from capability_item
to permission_rule, matching what it actually is.
- Fixed a pre-existing copy-paste error:
permissions property error
message said "Workbook item must be populated..." instead of
"Virtual connection item...".
Test plan
- Unit:
test/test_virtual_connection.py 15 passed. New tests:
test_from_xml_populated_tags (multi-item fixture, verifies parse
_initial_tags isolation from tags) and
test_update_tags_diff_round_trip (mocks PUT/DELETE calls, asserts
correct add/delete pattern from a synthetic diff).
- Unit:
test/test_tagging.py 134 passed after bumping the
parametrized-test server version to 3.30.
- Full suite: 864 passed, 1 skipped, 0 failed. mypy clean.
- Live end-to-end against a Tableau server (build 2026-08-09,
REST API 3.30): fetch a VC by id, add_tags(vc, ['a','b','c']),
re-fetch, verify tags == {a,b,c} and _initial_tags == {a,b,c}.
Then locally vc.tags.discard('b'); vc.tags.add('d'); update_tags(vc). Re-fetch confirms server state is {a,c,d}.
Cleanup via delete_tags(vc, list(vc.tags)) succeeds.
🤖 Generated with Claude Code
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Adds a class-level docstring plus 15 method docstrings (14 public
methods + the private _get_virtual_database_connections is unchanged).
Content ported from api-ref.md's Virtual Connections section on
gh-pages so once the Sphinx pipeline in #1832 is live the generated
output will cover what the handwritten page does today.
Virtual Connections was the largest remaining chunk in the
needs_docstring bucket per the api-ref migration audit (14 of the 41
remaining public endpoint methods without docstrings, after the 15
Favorites methods in #1855).
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|

Coverage Report
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
- add_permissions and delete_permission grow proper type hints
(VirtualConnectionItem, list[PermissionsRule], PermissionsRule) so the
docstring claims and the signatures agree.
- Rename docstring/signature params to `virtual_connection` throughout
the permissions methods; `item`, `resource`, `capability_item` were
inconsistent with the rest of the class and with each other.
- Rename `delete_permission`'s second param from `capability_item` to
`permission_rule` (which is what it actually is).
- Class docstring's REST API line now uses the same RST link style as
every method's REST API line.
- update_tags docstring documents WHY it's not implemented: the REST
API's virtual-connection response schema doesn't include tags, so
there's no way to populate _initial_tags on the item and no diff
basis for the mixin's update_tags. Tags exist server-side and are
manipulated via the add-tags / delete-tag endpoints that add_tags /
delete_tags already wrap.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The `VirtualConnections` REST endpoints have carried tags on their
response bodies since Tableau Server 2026.2 / Cloud April 2026 (server
commit 2e687548e10, W-21424436, shipping in v262 with REST API 3.30+).
The public REST docs still don't reflect this (filed W-23806318);
`VirtualConnectionItem` previously didn't parse the <tags> element.
Changes:
- `VirtualConnectionItem.__init__` gains `tags: set[str]` and
`_initial_tags: set[str]` matching every other taggable item.
- `VirtualConnectionItem.from_xml` parses <tags><tag label="..."/></tags>
via the existing `TagItem.from_xml_element` helper. `_initial_tags`
is a shallow copy of `tags` (strings are immutable so copy.copy is
sufficient).
- `VirtualConnections.update_tags` drops the NotImplementedError
override and delegates to `TaggingMixin.update_tags`. Bumped to
`@api(version="3.30")` since older server responses don't carry
<tags>, meaning `_initial_tags` would be empty and every locally-set
tag would be treated as new -- silent no-op on removes.
- `VirtualConnections.get_by_id` stamps the id back onto the returned
item. The `Get Virtual Connection` server response element omits the
`id` attribute (separate server-side bug filed as W-23806343);
downstream calls that need result.id (add_tags, delete_tags,
update_tags) would fail with 'ID not found.' Client-side workaround
until the server fix ships.
- Fixed pre-existing "Workbook item must be populated with permissions
first" copy-paste error in the `permissions` property error message.
- Test fixture `virtual_connections_get.xml` grew a matching empty
`<tags/>` element to reflect the current server response shape.
- `test_from_xml` and `test_virtual_connection_get_by_id` assert on the
new tags/id shape.
- New `test_from_xml_populated_tags` covers the tag-parse path
including no-back-propagation from `tags` to `_initial_tags`.
- New `test_update_tags_diff_round_trip` mocks the PUT/DELETE calls to
verify the diff-based mixin end-to-end.
- `test_tagging.py` server version bumped from 3.28 to 3.30 so the
parametrized virtual_connections update_tags case exercises the real
code path.
Live-verified end-to-end against a Tableau server (build 2026-08-09,
REST API 3.30): fetch a VC, mutate .tags locally, call update_tags,
re-fetch, server state matches the local edit.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
jacalata
changed the title
docs: numpy-style docstrings on VirtualConnections endpoint (14 methods)
docs+feat: VirtualConnections docstrings, tag parsing, id workaround
Aug 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR improves the Virtual Connections surface area by completing docstring coverage on the VirtualConnections endpoint and enabling end-to-end tag parsing + diff-based tag updates (REST API 3.30+), including a workaround for a server response that omits the virtual connection id on get_by_id.
Changes:
- Added numpy-style docstrings across
VirtualConnections methods and a class-level docstring.
- Implemented parsing of
<tags> into VirtualConnectionItem.tags / _initial_tags and enabled VirtualConnections.update_tags() gated to API 3.30.
- Updated and added unit tests + XML fixtures to validate tag parsing, diff behavior, and the
get_by_id id-stamping workaround.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File |
Description |
tableauserverclient/server/endpoint/virtual_connections_endpoint.py |
Adds docstrings, types, enables update_tags (3.30), and stamps missing id on get_by_id results. |
tableauserverclient/models/virtual_connection_item.py |
Adds tag fields and parses <tags> into tags / _initial_tags; fixes VC permissions error message. |
test/test_virtual_connection.py |
Adds tag parsing and update_tags diff round-trip tests; updates get_by_id assertion. |
test/test_tagging.py |
Bumps test server version to 3.30 to cover VC update_tags. |
test/assets/virtual_connections_get.xml |
Updates fixture to include <tags/>. |
test/assets/virtual_connections_get_with_tags.xml |
New fixture covering populated and empty tags cases. |
test/assets/virtual_connection_add_tags.xml |
New fixture for tag-add response used in update_tags tests. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
… test docstring
- VirtualConnectionItem.__init__ now initializes _permissions so accessing
.permissions before populate_permissions raises UnpopulatedPropertyError
instead of AttributeError, matching peer models.
- get_by_id raises ValueError when the resolved id is falsy (empty string
or unset item id), rather than silently building a URL that hits the
list endpoint and returning the wrong object.
- test_update_tags_diff_round_trip docstring corrected: the PUT /tags
call receives only the add-set {e}, not {a,c,e}, per TaggingMixin diff.
- get_by_id docstring notes the id is stamped from the request path due
to a server-side response quirk.
- Drop stray internal ticket reference from a tag-parsing comment.
- test_update_tags_diff_round_trip now inspects the PUT XML body and
asserts the add-set is exactly the diff; also asserts the two
DELETEs target the correct tag URLs. Catches regressions in the
add-set that call_count alone couldn't.
- Extract the "server omits id, stamp from request path" workaround
into VirtualConnectionItem._stamp_id_from_request() so the docstring
explaining W-23806343 lives with the class it mutates. Endpoint no
longer reaches across encapsulation into result._id.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Preserve item= compatibility and add the requested API 3.29 and fetched-tag coverage.
Review details
Suppressed comments (5)
Previously missed (1) — in code that hasn't changed since the last review.
tableauserverclient/server/endpoint/virtual_connections_endpoint.py:417
- This public method previously accepted
item= as a keyword, but renaming the parameter to virtual_connection makes existing keyword calls fail with TypeError even though positional calls still work. Preserve the old keyword or provide a deprecation-compatible alias before making this API rename.
This issue also appears in the following locations of the same file:
tableauserverclient/server/endpoint/virtual_connections_endpoint.py:444
- This public method previously accepted
resource= as a keyword, but the new virtual_connection name breaks existing keyword callers with TypeError. Preserve the existing keyword or provide a deprecation-compatible alias; otherwise this documentation/feature PR introduces an undocumented breaking API change.
def add_permissions(
self, virtual_connection: VirtualConnectionItem, rules: list[PermissionsRule]
) -> list[PermissionsRule]:
tableauserverclient/server/endpoint/virtual_connections_endpoint.py:471
- Both public parameter names were changed (
item to virtual_connection and capability_item to permission_rule), so existing calls using either keyword now fail with TypeError. Keep the old keyword names or add a deprecation-compatible alias before making this breaking API change.
def delete_permission(self, virtual_connection: VirtualConnectionItem, permission_rule: PermissionsRule) -> None:
test/test_tagging.py:20
- Raising the shared fixture to API 3.30 removes coverage of the pre-3.30 failure path. Because the new
@api("3.30") gate is what prevents an old response with an empty snapshot from being treated as all-new tags, add a 3.29 case that asserts the version error.
server.version = "3.30" # min for virtual_connections.update_tags (v262 / 2026.2)
test/test_virtual_connection.py:149
- This new assertion only checks the ID workaround. The
get_by_id fixture has no <tags>, and the diff test constructs tags and _initial_tags manually, so the advertised fetch-by-ID → tag snapshot → update_tags path is not covered. Add tags to the get response fixture and exercise or assert the returned item's two tag sets.
# The server's Get Virtual Connection response omits the `id` attribute on
# the <virtualConnection> element, but get_by_id stamps it back from the
# request path so downstream tag/permission calls can find it.
assert vconn.id == "8fd7cc02-bb55-4d15-b8b1-9650239efe79"
- Files reviewed: 7/7 changed files
- Comments generated: 0 new
- Review effort level: Lite
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Public keyword renames may break existing callers, and the API 3.30 unsupported-version path lacks regression coverage.
No open issues 🎉
Review effort: Lite
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This branch has not been deployed
No deployments
Reviewers
At least 1 approving review is required to merge this pull request.
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
[TYPE 3] [Virtual Connection Tags]
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|