Skip to content

Workbooks,download fails for Tableau Server v.2023.1.7 #1312

Closed

Description

@ElenasemDA

Describe the bug
Workbooks.download fails with an error in regard to 'filename'.
Versions: Tableau Server 2023.1.7 (API 3.19), tableauserverclient-0.14.1, python 3.7.9
(tested also: Tableau Server 2023.1.7 (API 3.19), tableauserverclient-0.28, python 3.9.13)

To Reproduce
server_int = TSC.Server("https://yousite",use_server_version = True)
tableau_auth_int = TSC.TableauAuth("username", "password", site_id='sitename')

with server_int.auth.sign_in(tableau_auth_int):

workbook= server_int.workbooks.get_by_id('fca33a9a-0139-41b9-b1e7-841a92bf5f92')
wkbk=workbook.name
print(workbook.name)        
print(workbook.id)
file_path = server_int.workbooks.download('fca33a9a-0139-41b9-b1e7-841a92bf5f92')
print("\nDownloaded the file to {0}.".format(file_path))

Results
WorkbookName
fca33a9a-0139-41b9-b1e7-841a92bf5f92

KeyError Traceback (most recent call last)
~\AppData\Local\Temp\1\ipykernel_7340\2448852531.py in
5 print(workbook.name)
6 print(workbook.id)
----> 7 file_path = server_int.workbooks.download('fca33a9a-0139-41b9-b1e7-841a92bf5f92')
8 print("\nDownloaded the file to {0}.".format(file_path))

E:\Anaconda3\envs\Tableau_analytics\lib\site-packages\tableauserverclient\server\endpoint\endpoint.py in wrapper(self, *args, **kwargs)
290 def wrapper(self, *args, **kwargs):
291 self.parent_srv.assert_at_least_version(version, self.class.name)
--> 292 return func(self, *args, **kwargs)
293
294 return wrapper

E:\Anaconda3\envs\Tableau_analytics\lib\site-packages\tableauserverclient\server\endpoint\endpoint.py in wrapper(self, *args, **kwargs)
332 error = "{!r} not available in {}, it will be ignored. Added in {}".format(p, server_ver, min_ver)
333 warnings.warn(error)
--> 334 return func(self, *args, **kwargs)
335
336 return wrapper

E:\Anaconda3\envs\Tableau_analytics\lib\site-packages\tableauserverclient\server\endpoint\endpoint.py in wrapper(self, *args, **kwargs)
332 error = "{!r} not available in {}, it will be ignored. Added in {}".format(p, server_ver, min_ver)
333 warnings.warn(error)
--> 334 return func(self, *args, **kwargs)
335
336 return wrapper

E:\Anaconda3\envs\Tableau_analytics\lib\site-packages\tableauserverclient\server\endpoint\workbooks_endpoint.py in download(self, workbook_id, filepath, include_extract, no_extract)
182 no_extract: Optional[bool] = None,
183 ) -> str:
--> 184 return self.download_revision(workbook_id, None, filepath, include_extract, no_extract)
185
186 # Get all views of workbook

E:\Anaconda3\envs\Tableau_analytics\lib\site-packages\tableauserverclient\server\endpoint\endpoint.py in wrapper(self, *args, **kwargs)
290 def wrapper(self, *args, **kwargs):
291 self.parent_srv.assert_at_least_version(version, self.class.name)
--> 292 return func(self, *args, **kwargs)
293
294 return wrapper

E:\Anaconda3\envs\Tableau_analytics\lib\site-packages\tableauserverclient\server\endpoint\workbooks_endpoint.py in download_revision(self, workbook_id, revision_number, filepath, include_extract, no_extract)
488 return_path = filepath
489 else:
--> 490 filename = to_filename(os.path.basename(params["filename"]))
491 download_path = make_download_path(filepath, filename)
492 with open(download_path, "wb") as f:

KeyError: 'filename'

NOTE: Be careful not to post user names, passwords, auth tokens or any other private or sensitive information.

Activity

  1. hersh-gupta commented on Nov 3, 2023

    @hersh-gupta

    It looks like the filename header in the following was changed to filename*, throwing the error:

    with closing(self.get_request(url, parameters={"stream": True})) as server_response:
    _, params = cgi.parse_header(server_response.headers["Content-Disposition"])
    if isinstance(filepath, io_types_w):
    for chunk in server_response.iter_content(1024): # 1KB
    filepath.write(chunk)
    return_path = filepath
    else:
    filename = to_filename(os.path.basename(params["filename"]))
    download_path = make_download_path(filepath, filename)
    with open(download_path, "wb") as f:
    for chunk in server_response.iter_content(1024): # 1KB
    f.write(chunk)
    return_path = os.path.abspath(download_path)

  2. DGordon-Placer commented on Nov 5, 2023

    @DGordon-Placer

    @hersh-gupta @ElenasemDA we have run into this issue as well. Any rough idea of how long things like this usually take to get resolved?

  3. mendon26 commented on Nov 8, 2023

    @mendon26

    Any updates on this? We are facing the same issue.

  4. hahu66 commented on Nov 8, 2023

    @hahu66

    Same issue here, after upgrading from 2023.1.5 to 2023.1.7
    Looks like a change in Rest API version 3.19?
    There is no "filename" return in the 'params' set on line 484

    File "C:\Program Files\Python38\lib\site-packages\tableauserverclient\server\endpoint\workbooks_endpoint.py", line 490, in download_revision
    filename = to_filename(os.path.basename(params["filename"]))
    KeyError: 'filename'

  5. madreyg commented on Nov 9, 2023

    @madreyg

    Hello. We faced the same problem. We are looking forward to the fix.

  6. DGordon-Placer commented on Nov 9, 2023

    @DGordon-Placer

    Update From our side, we did a test and upgraded our dev server to 2023.3.0 and it looks like the issue has been resolved. However, we've learnt from past experiences to never upgrade our production server to an 20XX.X.0 version as there are usually very buggy and cause more damage than they fix. We're going to wait till 2023.3.1 comes out.

  7. galmarco commented on Nov 14, 2023

    @galmarco

    Any update on this issue? we are facing the same.

  8. Soltis12 commented on Nov 16, 2023

    @Soltis12

    Also getting this error. Awaiting a fix.

  9. nir9696 commented on Nov 16, 2023

    @nir9696

    I'm also encountering this error. Looking forward to a resolution.

  10. ManikandanUV commented on Nov 17, 2023

    @ManikandanUV

    facing this same issue after our server upgrade. Please push a fix to the python client.

  11. ElenasemDA commented on Nov 21, 2023

    @ElenasemDA
    Author

    We use the snippet below instead of calling the server.workbooks.download (v.2023.1.7). Check if you can incorporate it to your processes.

    with closing(server_int.workbooks.get_request(url, parameters={"stream": True})) as server_response:
    _, params = cgi.parse_header(server_response.headers["Content-Disposition"])
    if isinstance(ind_path, io_types_w):
    for chunk in server_response.iter_content(1024): # 1KB
    ind_path.write(chunk)
    return_path = ind_path
    else:
    filename = to_filename(os.path.basename(params["filename*"]))
    filename = filename.replace("UTF-8","").replace("+"," ")
    filename = filename.replace("28","(").replace("29",")")
    download_path = make_download_path(ind_path, filename)
    with open(download_path, "wb") as f:
    for chunk in server_response.iter_content(1024): # 1KB
    f.write(chunk)
    return_path = os.path.abspath(download_path)

  12. nir9696 commented on Nov 21, 2023

    @nir9696

    We use the snippet below instead of calling the server.workbooks.download (v.2023.1.7). Check if you can incorporate it to your processes.

    with closing(server_int.workbooks.get_request(url, parameters={"stream": True})) as server_response: _, params = cgi.parse_header(server_response.headers["Content-Disposition"]) if isinstance(ind_path, io_types_w): for chunk in server_response.iter_content(1024): # 1KB ind_path.write(chunk) return_path = ind_path else: filename = to_filename(os.path.basename(params["filename*"])) filename = filename.replace("UTF-8","").replace("+"," ") filename = filename.replace("28","(").replace("29",")") download_path = make_download_path(ind_path, filename) with open(download_path, "wb") as f: for chunk in server_response.iter_content(1024): # 1KB f.write(chunk) return_path = os.path.abspath(download_path)

    This is my workaround snippet. maybe you'll find it useful as well until the fix:

    def _decode_filename(self, params):
        if 'filename*' in params:
            encoded_filename = params['filename*']
            if encoded_filename.startswith("UTF-8''"):
                encoded_filename = encoded_filename[
                                   7:]  # strip off the "UTF-8''" prefix
            filename = urllib.parse.unquote_plus(
                encoded_filename)  # decode percent-encoded octets
        elif 'filename' in params:
            filename = params['filename']
        else:
            filename = None
    
        return filename
    
    # Download 1 workbook revision by revision number
    @api(version="2.3")
    def download_revision(
        self,
        workbook_id: str,
        revision_number: str,
        filepath: Optional[PathOrFileW] = None,
        include_extract: bool = True,
        no_extract: Optional[bool] = None,
    ) -> PathOrFileW:
        if not workbook_id:
            error = "Workbook ID undefined."
            raise ValueError(error)
        if revision_number is None:
            url = "{0}/{1}/content".format(self.baseurl, workbook_id)
        else:
            url = "{0}/{1}/revisions/{2}/content".format(self.baseurl, workbook_id, revision_number)
    
        if no_extract is False or no_extract is True:
            import warnings
    
            warnings.warn(
                "no_extract is deprecated, use include_extract instead.",
                DeprecationWarning,
            )
            include_extract = not no_extract
    
        if not include_extract:
            url += "?includeExtract=False"
    
        with closing(self.get_request(url, parameters={"stream": True})) as server_response:
            _, params = cgi.parse_header(server_response.headers["Content-Disposition"])
            if isinstance(filepath, io_types_w):
                for chunk in server_response.iter_content(1024):  # 1KB
                    filepath.write(chunk)
                return_path = filepath
            else:
                filename = self._decode_filename(params)
                filename = to_filename(os.path.basename(filename))
                download_path = make_download_path(filepath, filename)
                with open(download_path, "wb") as f:
                    for chunk in server_response.iter_content(1024):  # 1KB
                        f.write(chunk)
                return_path = os.path.abspath(download_path)
    
        logger.info(
            "Downloaded workbook revision {0} to {1} (ID: {2})".format(revision_number, return_path, workbook_id)
        )
        return return_path
    
  13. hjwilliam commented on Nov 23, 2023

    @hjwilliam

    Same issue for us since upgrading to 2023.1.7 - looking forward to a fix.

  14. PradeepDoddarangaiah commented on Nov 28, 2023

    @PradeepDoddarangaiah

    facing the same issue in 2023.1.7. Looking forward to a resolution.

  15. rickymedrano commented on Dec 1, 2023

    @rickymedrano

    Faced the same issue. You can fix it by opening /{path/to/your/python-libraries}/site-packages/tableauserverclient/server/endpoint/workbooks_endpoint.py and on line 490 update:
    "...(params["filename"]))"
    to
    "...(params["filename*"]))"
    Workbooks should now download but they have "UTF-8" appended to beginning of their name so you can write some code to take care of that until they patch this issue.
    Will probably need to edit the datasources file as well to handle downloading datasources.

  16. ManikandanUV commented on Dec 5, 2023

    @ManikandanUV

    Our code uses both workbook endpoint and datasource endpoint, and is a mixture of upgraded as well as old version servers, so these are the changes I did to get it working for our usecase.

    /venv/lib/python3.8/site-packages/tableauserverclient/server/endpoint/workbooks_endpoint.py

    205             try:
    206                 filename = to_filename(os.path.basename(params["filename*"]))
    207                 filename = filename.replace("UTF-8","").replace("+"," ")
    208             except KeyError:
    209                 filename = to_filename(os.path.basename(params["filename"]))
    

    venv/lib/python3.8/site-packages/tableauserverclient/server/endpoint/datasources_endpoint.py

    161             try:
    162                 filename = to_filename(os.path.basename(params["filename*"]))
    163                 filename = filename.replace("UTF-8","").replace("+"," ")
    164             except KeyError:
    165                 filename = to_filename(os.path.basename(params["filename"]))
    
  17. amarkoe2018 commented on Dec 5, 2023

    @amarkoe2018

    We also are affected by this issue.

  18. bcantoni commented on Jan 17, 2024

    @bcantoni
    Contributor

    For anyone facing this issue, please try downloaded the new v0.29 release. It includes #1330 which should fix this.

  19. SebMontreal06 commented on Jan 22, 2024

    @SebMontreal06

    unfortunately, i get an issue with 0.29 to uploading datasources : 400011: Bad Request
    There was a problem publishing the file '17851:753240939c9444f4a364f54c39c26e3e-1:0'

  20. jorwoods commented on Jan 22, 2024

    @jorwoods
    Contributor

    @SebMontreal06 That is different than the problem being discussed in this issue. Please open a new issue.

  21. SebMontreal06 commented on Jan 22, 2024

    @SebMontreal06
  22. bcantoni commented on Feb 14, 2024

    @bcantoni
    Contributor

    I'm going to resolve this one as closed/fixed now. If anyone is encountering problems like this after upgrading to v.030, please open a new issue with details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions