Skip to content

Commit 04133e7

Browse files
jacalataclaude
andcommitted
fix: encode special characters in tag delete URL path
Fixes #675 #994 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 19f2897 commit 04133e7

2 files changed

Lines changed: 26 additions & 2 deletions

File tree

tableauserverclient/server/endpoint/resource_tagger.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def _add_tags(self, baseurl, resource_id, tag_set):
3939

4040
# Delete a resource's tag by name
4141
def _delete_tag(self, baseurl, resource_id, tag_name):
42-
encoded_tag_name = urllib.parse.quote(tag_name)
42+
encoded_tag_name = urllib.parse.quote(tag_name, safe="")
4343
url = f"{baseurl}/{resource_id}/tags/{encoded_tag_name}"
4444

4545
try:
@@ -124,7 +124,7 @@ def delete_tags(self, item: T | str, tags: Iterable[str] | str) -> None:
124124
tag_set = set(tags)
125125

126126
for tag in tag_set:
127-
encoded_tag_name = urllib.parse.quote(tag)
127+
encoded_tag_name = urllib.parse.quote(tag, safe="")
128128
url = f"{self.baseurl}/{item_id}/tags/{encoded_tag_name}"
129129
self.delete_request(url)
130130

test/test_tagging.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,27 @@ def test_tag_with_spaces_is_quoted_in_request() -> None:
256256
labels = {tag.get("label") for tag in root.findall(".//tag")}
257257
assert '"Yearly Sales"' in labels
258258
assert "simple" in labels
259+
260+
261+
@pytest.mark.parametrize(
262+
"tag, expected_encoded",
263+
[
264+
("tag#name", "tag%23name"), # issue #675: hash must be percent-encoded
265+
("tag.name", "tag.name"), # issue #994: dot is safe, no encoding needed
266+
("tag+name", "tag%2Bname"), # plus must be percent-encoded
267+
("tag/name", "tag%2Fname"), # slash must be percent-encoded (safe='' fix)
268+
("tag name", "tag%20name"), # space must be percent-encoded
269+
],
270+
)
271+
def test_delete_tags_special_characters_encoded(get_server, tag, expected_encoded) -> None:
272+
"""Verify delete_tags percent-encodes special characters in the tag path segment."""
273+
server = get_server
274+
workbook = make_workbook()
275+
276+
with requests_mock.mock() as m:
277+
m.delete(requests_mock.ANY, status_code=200)
278+
server.workbooks.delete_tags(workbook, tag)
279+
history = m.request_history
280+
281+
assert len(history) == 1
282+
assert history[0].url.endswith(f"/tags/{expected_encoded}")

0 commit comments

Comments
 (0)