Skip to content

Commit

Permalink
Merge pull request #1330 from jorwoods/jorwoods/download_hotfix
Browse files Browse the repository at this point in the history
Jorwoods/1312 download hotfix
  • Loading branch information
jacalata authored Jan 4, 2024
2 parents b5f5caa + 19a9f51 commit 666fcd8
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var/
*.egg-info/
.installed.cfg
*.egg
pip-wheel-metadata/

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down Expand Up @@ -89,6 +90,7 @@ env.py
# virtualenv
venv/
ENV/
.venv/

# Spyder project settings
.spyderproject
Expand Down
17 changes: 17 additions & 0 deletions tableauserverclient/helpers/headers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from copy import deepcopy
from urllib.parse import unquote_plus


def fix_filename(params):
if "filename*" not in params:
return params

params = deepcopy(params)
filename = params["filename*"]
prefix = "UTF-8''"
if filename.startswith(prefix):
filename = filename[len(prefix) :]

params["filename"] = unquote_plus(filename)
del params["filename*"]
return params
3 changes: 3 additions & 0 deletions tableauserverclient/server/endpoint/datasources_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from pathlib import Path
from typing import List, Mapping, Optional, Sequence, Tuple, TYPE_CHECKING, Union

from tableauserverclient.helpers.headers import fix_filename

if TYPE_CHECKING:
from tableauserverclient.server import Server
from tableauserverclient.models import PermissionsRule
Expand Down Expand Up @@ -441,6 +443,7 @@ def download_revision(
filepath.write(chunk)
return_path = filepath
else:
params = fix_filename(params)
filename = to_filename(os.path.basename(params["filename"]))
download_path = make_download_path(filepath, filename)
with open(download_path, "wb") as f:
Expand Down
3 changes: 3 additions & 0 deletions tableauserverclient/server/endpoint/flows_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from pathlib import Path
from typing import Iterable, List, Optional, TYPE_CHECKING, Tuple, Union

from tableauserverclient.helpers.headers import fix_filename

from .dqw_endpoint import _DataQualityWarningEndpoint
from .endpoint import QuerysetEndpoint, api
from .exceptions import InternalServerError, MissingRequiredFieldError
Expand Down Expand Up @@ -124,6 +126,7 @@ def download(self, flow_id: str, filepath: Optional[PathOrFileW] = None) -> Path
filepath.write(chunk)
return_path = filepath
else:
params = fix_filename(params)
filename = to_filename(os.path.basename(params["filename"]))
download_path = make_download_path(filepath, filename)
with open(download_path, "wb") as f:
Expand Down
5 changes: 4 additions & 1 deletion tableauserverclient/server/endpoint/workbooks_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from contextlib import closing
from pathlib import Path

from tableauserverclient.helpers.headers import fix_filename

from .endpoint import QuerysetEndpoint, api, parameter_added_in
from .exceptions import InternalServerError, MissingRequiredFieldError
from .permissions_endpoint import _PermissionsEndpoint
Expand Down Expand Up @@ -455,7 +457,7 @@ def _get_workbook_revisions(
def download_revision(
self,
workbook_id: str,
revision_number: str,
revision_number: Optional[str],
filepath: Optional[PathOrFileW] = None,
include_extract: bool = True,
no_extract: Optional[bool] = None,
Expand Down Expand Up @@ -487,6 +489,7 @@ def download_revision(
filepath.write(chunk)
return_path = filepath
else:
params = fix_filename(params)
filename = to_filename(os.path.basename(params["filename"]))
download_path = make_download_path(filepath, filename)
with open(download_path, "wb") as f:
Expand Down
11 changes: 11 additions & 0 deletions test/test_datasource.py
Original file line number Diff line number Diff line change
Expand Up @@ -696,3 +696,14 @@ def test_download_revision(self) -> None:
)
file_path = self.server.datasources.download_revision("9dbd2263-16b5-46e1-9c43-a76bb8ab65fb", "3", td)
self.assertTrue(os.path.exists(file_path))

def test_bad_download_response(self) -> None:
with requests_mock.mock() as m, tempfile.TemporaryDirectory() as td:
m.get(
self.baseurl + "/9dbd2263-16b5-46e1-9c43-a76bb8ab65fb/content",
headers={
"Content-Disposition": '''name="tableau_datasource"; filename*=UTF-8''"Sample datasource.tds"'''
},
)
file_path = self.server.datasources.download("9dbd2263-16b5-46e1-9c43-a76bb8ab65fb", td)
self.assertTrue(os.path.exists(file_path))
10 changes: 10 additions & 0 deletions test/test_flow.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import requests_mock
import tempfile
import unittest

from io import BytesIO
Expand Down Expand Up @@ -203,3 +204,12 @@ def test_refresh(self):
self.assertEqual(refresh_job.flow_run.id, "e0c3067f-2333-4eee-8028-e0a56ca496f6")
self.assertEqual(refresh_job.flow_run.flow_id, "92967d2d-c7e2-46d0-8847-4802df58f484")
self.assertEqual(format_datetime(refresh_job.flow_run.started_at), "2018-05-22T13:00:29Z")

def test_bad_download_response(self) -> None:
with requests_mock.mock() as m, tempfile.TemporaryDirectory() as td:
m.get(
self.baseurl + "/9dbd2263-16b5-46e1-9c43-a76bb8ab65fb/content",
headers={"Content-Disposition": '''name="tableau_flow"; filename*=UTF-8''"Sample flow.tfl"'''},
)
file_path = self.server.flows.download("9dbd2263-16b5-46e1-9c43-a76bb8ab65fb", td)
self.assertTrue(os.path.exists(file_path))
9 changes: 9 additions & 0 deletions test/test_workbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -932,3 +932,12 @@ def test_download_revision(self) -> None:
)
file_path = self.server.workbooks.download_revision("9dbd2263-16b5-46e1-9c43-a76bb8ab65fb", "3", td)
self.assertTrue(os.path.exists(file_path))

def test_bad_download_response(self) -> None:
with requests_mock.mock() as m, tempfile.TemporaryDirectory() as td:
m.get(
self.baseurl + "/9dbd2263-16b5-46e1-9c43-a76bb8ab65fb/content",
headers={"Content-Disposition": '''name="tableau_workbook"; filename*=UTF-8''"Sample workbook.twb"'''},
)
file_path = self.server.workbooks.download("9dbd2263-16b5-46e1-9c43-a76bb8ab65fb", td)
self.assertTrue(os.path.exists(file_path))

0 comments on commit 666fcd8

Please sign in to comment.