Repository navigation
Conversation
The `Namespace` class detected `http://tableausoftware.com/api` (the pre-8.3 namespace) at runtime on every XML response and let the parser silently switch namespaces if it saw the old one. That behavior has been unreachable for years: the library's `minimum_supported_server_version` is 2.3, which corresponds to Tableau Server 10.0 -- shipped in 2016, three years after the namespace changed. Every server TSC has ever admitted uses `http://tableau.com/api`. Removes: - `tableauserverclient/namespace.py` (the module) and everything it exported: `Namespace`, `UnknownNamespaceError`, `OLD_NAMESPACE`, `NEW_NAMESPACE`, `NAMESPACE_RE`. - `Server._namespace` instance and the per-response `.detect(...)` call in `Endpoint._make_request` and both sign-in paths in `Auth`. Keeps: - The public `TSC.DEFAULT_NAMESPACE` re-export -- now sourced from `tableauserverclient.server.server.NAMESPACE`, which is the canonical constant. Same string value. - `Server.namespace` property -- still returns the `{"t": NAMESPACE}` dict callers pass to ElementTree's `namespaces=` kwarg. Same shape. Callers who imported directly from `tableauserverclient.namespace` (rather than `TSC.DEFAULT_NAMESPACE`) will break; the CHANGELOG entry calls this out. Fixes #1046. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR removes runtime XML namespace detection that allowed parsing legacy (pre-Tableau Server 8.3) REST API XML responses, standardizing the client on the modern http://tableau.com/api namespace in line with the library’s long-standing minimum supported server/API versions.
Changes:
- Removed the
tableauserverclient.namespacemodule and eliminated per-response namespace detection calls. - Centralized the namespace constant in
server.serverand updatedTSC.DEFAULT_NAMESPACEto keep the public re-export working. - Updated server/endpoint code paths to always use the fixed namespace map.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tableauserverclient/server/server.py | Removes per-instance namespace detector and introduces fixed namespace constants/map. |
| tableauserverclient/server/endpoint/endpoint.py | Removes the XML-response namespace detection hook in _make_request. |
| tableauserverclient/server/endpoint/auth_endpoint.py | Removes namespace detection during sign-in and site switching flows. |
| tableauserverclient/namespace.py | Deletes the legacy namespace detection module and exported symbols. |
| tableauserverclient/init.py | Updates DEFAULT_NAMESPACE re-export to come from the new namespace source. |
| CHANGELOG.md | Documents the breaking removal of legacy namespace fallback and module exports. |
Suppressed comments (2)
tableauserverclient/server/endpoint/auth_endpoint.py:159
- With namespace auto-detection removed, a legacy-namespace (or otherwise unexpected) XML response can make
find(...).get(...)raiseAttributeError. Adding an explicit check and raisingServerResponseErrorproduces a clearer, user-facing failure mode for unsupported namespaces/servers.
parsed_response = fromstring(server_response.content)
site_id = parsed_response.find(".//t:site", namespaces=self.parent_srv.namespace).get("id", None)
site_url = parsed_response.find(".//t:site", namespaces=self.parent_srv.namespace).get("contentUrl", None)
tableauserverclient/server/endpoint/auth_endpoint.py:86
- With namespace auto-detection removed, a legacy-namespace (or otherwise unexpected) XML response will make
find(...).get(...)raise anAttributeError, which is hard to diagnose. It’s better to explicitly check that the expected elements are present and raiseServerResponseErrorwith a message that points to a likely namespace / server-version mismatch.
This issue also appears on line 157 of the same file.
parsed_response = fromstring(server_response.content)
site_id = parsed_response.find(".//t:site", namespaces=self.parent_srv.namespace).get("id", None)
site_url = parsed_response.find(".//t:site", namespaces=self.parent_srv.namespace).get("contentUrl", None)
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…hared state Copilot flagged that Server.namespace returned the module-level _NAMESPACE_MAP directly, so a caller mutating the returned dict would have polluted every other Server instance in the process. Old namespace- handling code returned a per-instance dict, so no cross-instance pollution was possible. Wrap in dict(...) to restore that behavior.
Two adjustments from a post-merge fresh-eyes pass: - endpoint.py: the http -> https address-promotion match now compares hostnames case-insensitively (RFC 3986) and normalizes http://host vs http://host:80 so a same-host promotion doesn't silently drop. Split into two comparisons: current-vs-next is hostname-only (schemes differ so default port differs, comparing raw netloc would spuriously mismatch); old-address-vs-current is same-scheme and uses (hostname, effective port) so explicit-vs-implicit port compares equal. Expanded the auth-material comment to acknowledge that sign_in itself carries raw credentials in the POST body, not only the issued token on subsequent calls. - test_redirect_handling.py: added a docstring on test_all_supported_redirect_codes_preserve_post_body naming the RFC 7231 6.4.4 deviation on 303 -- if a future refactor "helpfully" converts 303 to GET, the parametrized test fails with a clear intent statement. Also considered a sign_in namespace-detect hedge for pre-8.3 Tableau responses (Copilot flagged this on #1848); dropped as theoretical because TSC's minimum_supported_server_version = 2.3 (Tableau 10.0, 2016) is eight years past the namespace change, and #1863 removes the whole subsystem anyway.
…e-old-namespace # Conflicts: # tableauserverclient/server/endpoint/auth_endpoint.py
Cosmetic import-graph cleanup on top of #1863's move of `NAMESPACE` from `namespace.py` into `server/server.py`. Before this change, `tableauserverclient/__init__.py:2` did `from tableauserverclient. server.server import NAMESPACE`, which forces `server.server` (and its transitive endpoint tree) to load just to read a string constant. Copilot flagged the circular-import path this creates: `server. server` -> `server.endpoint.endpoint` -> `from tableauserverclient import ...` -> `__init__` -> `server.server`. Python resolves the chain today because the reentrant lookups pull submodules whose own load doesn't back-reference the partially-initialized parent, but the shape is fragile and adding a new top-level import to `__init__.py` before line 2 could easily break it. Replaced the import with the string literal. Kept in sync with the `NAMESPACE` constant in `server/server.py`. Also removes one of the two entry points into `server.server` at package load, though everything else in `__init__.py` still transitively pulls the endpoint tree via the models block below, so no real startup savings -- this is defensive, not a perf fix.
CHANGELOG.md: development now points to the GitHub Releases page, so the changelog entry for this change is dropped (the breaking-change note moves to the PR description). tableauserverclient/namespace.py: deletion kept; development only added docstrings to the removed module. Add test/test_namespace.py pinning TSC.DEFAULT_NAMESPACE to server.NAMESPACE and checking Server.namespace returns an independent copy. Written with Claude Code
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are identified, and the change consistently removes obsolete namespace detection while preserving the documented public interfaces and defensive mapping behavior.
No open issues 🎉
2 resolved since last review
Review effort: Lite


Summary
Removes the runtime XML namespace detection that let TSC accept responses from Tableau Server versions predating 8.3 (2013,
http://tableausoftware.com/api). The library'sminimum_supported_server_versionhas been 2.3 for years (Tableau Server 10.0, 2016), so the detection has been unreachable for a decade.Fixes #1046. Also makes #1866 moot: its
application/xmlvstext/xmlguard inEndpoint._make_requestis deleted here along with thedetect()call.What changes
Removed:
tableauserverclient/namespace.py(the whole module) and the symbols it exported:Namespace,UnknownNamespaceError,OLD_NAMESPACE,NEW_NAMESPACE,NAMESPACE_RE.Server._namespaceand the per-response.detect(...)call inEndpoint._make_requestand both sign-in paths inAuth.Kept:
TSC.DEFAULT_NAMESPACEre-export, with the same string value. It is a literal in__init__.pybecause importing it fromserver.serveris circular;test/test_namespace.pypins it toserver.server.NAMESPACE.Server.namespaceproperty, which returns a fresh{"t": NAMESPACE}dict on each call, the same shape callers pass to ElementTree'snamespaces=kwarg.Compatibility
Breaking for callers who import directly from
tableauserverclient.namespace(Namespace,UnknownNamespaceError,OLD_NAMESPACE,NEW_NAMESPACE,NAMESPACE_RE) rather than the documentedTSC.DEFAULT_NAMESPACE. The module was internal in every sense except being top-level, so this is an outright removal with no deprecation shim.CHANGELOG.mdnow points to GitHub Releases, so the release notes should carry this line.Why now
Discussion in #1039 (2022) already noted the fallback was safe to drop; the issue has been open since. Nothing in the diff is complicated; the code is simply dead.
Written with Claude Code