diff --git a/tableau_rest_api/tableau_rest_api_connection.py b/tableau_rest_api/tableau_rest_api_connection.py index 14ebc33..e2f8a17 100644 --- a/tableau_rest_api/tableau_rest_api_connection.py +++ b/tableau_rest_api/tableau_rest_api_connection.py @@ -1219,16 +1219,17 @@ def query_job(self, job_luid): # Start of download / save methods # - # Do not include file extension - def save_workbook_view_preview_image(self, wb_name_or_luid, view_name_or_luid, filename_no_extension, + # You must pass in the wb name because the endpoint needs it (although, you could potentially look up the + # workbook LUID from the view LUID + def query_view_preview_image(self, wb_name_or_luid, view_name_or_luid, proj_name_or_luid=None): """ :type wb_name_or_luid: unicode :type view_name_or_luid: unicode :type proj_name_or_luid: unicode :type filename_no_extension: unicode - :rtype: - """ + :rtype: bytes + """ self.start_log_block() if self.is_luid(wb_name_or_luid): wb_luid = wb_name_or_luid @@ -1241,33 +1242,66 @@ def save_workbook_view_preview_image(self, wb_name_or_luid, view_name_or_luid, f view_luid = self.query_workbook_view_luid(wb_name_or_luid, view_name=view_name_or_luid, proj_name_or_luid=proj_name_or_luid) try: - if filename_no_extension.find('.png') == -1: - filename_no_extension += '.png' - save_file = open(filename_no_extension, 'wb') + url = self.build_api_url(u"workbooks/{}/views/{}/previewImage".format(wb_luid, view_luid)) image = self.send_binary_get_request(url) - save_file.write(image) - save_file.close() + self.end_log_block() + return image # You might be requesting something that doesn't exist except RecoverableHTTPException as e: - self.log(u"Attempt to request preview image results in HTTP error {}, Tableau Code {}".format(e.http_code, e.tableau_error_code)) + self.log(u"Attempt to request preview image results in HTTP error {}, Tableau Code {}".format(e.http_code, + e.tableau_error_code)) self.end_log_block() raise + + + # Do not include file extension + + # Just an alias but it matches the naming of the current reference guide (2019.1) + def save_view_preview_image(self, wb_name_or_luid, view_name_or_luid, filename_no_extension, + proj_name_or_luid=None): + """ + :type wb_name_or_luid: unicode + :type view_name_or_luid: unicode + :type proj_name_or_luid: unicode + :type filename_no_extension: unicode + :rtype: + """ + self.save_workbook_view_preview_image(wb_name_or_luid, view_name_or_luid, filename_no_extension, + proj_name_or_luid) + + def save_workbook_view_preview_image(self, wb_name_or_luid, view_name_or_luid, filename_no_extension, + proj_name_or_luid=None): + """ + :type wb_name_or_luid: unicode + :type view_name_or_luid: unicode + :type proj_name_or_luid: unicode + :type filename_no_extension: unicode + :rtype: + """ + self.start_log_block() + image = self.query_view_preview_image(wb_name_or_luid=wb_name_or_luid, view_name_or_luid=view_name_or_luid, + proj_name_or_luid=proj_name_or_luid) + if filename_no_extension.find('.png') == -1: + filename_no_extension += '.png' + try: + save_file = open(filename_no_extension, 'wb') + save_file.write(image) + save_file.close() + self.end_log_block() + except IOError: self.log(u"Error: File '{}' cannot be opened to save to".format(filename_no_extension)) self.end_log_block() raise - # Do not include file extension - def save_workbook_preview_image(self, wb_name_or_luid, filename_no_extension, proj_name_or_luid=None): + def query_workbook_preview_image(self, wb_name_or_luid, proj_name_or_luid=None): """ :type wb_name_or_luid: unicode - :param filename_no_extension: Correct extension will be added automatically - :type filename_no_extension: unicode :type proj_name_or_luid: unicode - :rtype: + :rtype: bytes """ self.start_log_block() if self.is_luid(wb_name_or_luid): @@ -1275,20 +1309,38 @@ def save_workbook_preview_image(self, wb_name_or_luid, filename_no_extension, pr else: wb_luid = self.query_workbook_luid(wb_name_or_luid, proj_name_or_luid) try: - if filename_no_extension.find('.png') == -1: - filename_no_extension += '.png' - save_file = open(filename_no_extension, 'wb') + url = self.build_api_url(u"workbooks/{}/previewImage".format(wb_luid)) image = self.send_binary_get_request(url) - save_file.write(image) - save_file.close() self.end_log_block() + return image # You might be requesting something that doesn't exist, but unlikely except RecoverableHTTPException as e: self.log(u"Attempt to request preview image results in HTTP error {}, Tableau Code {}".format(e.http_code, e.tableau_error_code)) self.end_log_block() raise + + + # Do not include file extension + def save_workbook_preview_image(self, wb_name_or_luid, filename_no_extension, proj_name_or_luid=None): + """ + :type wb_name_or_luid: unicode + :param filename_no_extension: Correct extension will be added automatically + :type filename_no_extension: unicode + :type proj_name_or_luid: unicode + :rtype: + """ + self.start_log_block() + image = self.query_workbook_preview_image(wb_name_or_luid=wb_name_or_luid, proj_name_or_luid=proj_name_or_luid) + if filename_no_extension.find('.png') == -1: + filename_no_extension += '.png' + try: + save_file = open(filename_no_extension, 'wb') + save_file.write(image) + save_file.close() + self.end_log_block() + except IOError: self.log(u"Error: File '{}' cannot be opened to save to".format(filename_no_extension)) self.end_log_block() diff --git a/tableau_rest_api/tableau_rest_api_connection_25.py b/tableau_rest_api/tableau_rest_api_connection_25.py index 440af95..c567080 100644 --- a/tableau_rest_api/tableau_rest_api_connection_25.py +++ b/tableau_rest_api/tableau_rest_api_connection_25.py @@ -1,5 +1,5 @@ from tableau_rest_api_connection_24 import * - +import urllib class TableauRestApiConnection25(TableauRestApiConnection24): def __init__(self, server, username, password, site_content_url=u""): @@ -120,12 +120,13 @@ def update_project(self, name_or_luid, new_project_name=None, new_project_descri self.end_log_block() return self.get_published_project_object(project_luid, response) - def query_view_image(self, view_name_or_luid, save_filename_no_extension, high_resolution=False, + # Generic implementation of all the CSV/PDF/PNG requests + def _query_data_file(self, download_type, view_name_or_luid, high_resolution=None, view_filter_map=None, wb_name_or_luid=None, proj_name_or_luid=None): """ :type view_name_or_luid: unicode - :type save_filename_no_extension: unicode :type high_resolution: bool + :type view_filter_map: dict :type wb_name_or_luid: unicode :type proj_name_or_luid :rtype: @@ -137,7 +138,80 @@ def query_view_image(self, view_name_or_luid, save_filename_no_extension, high_r view_luid = self.query_workbook_view_luid(wb_name_or_luid, view_name=view_name_or_luid, proj_name_or_luid=proj_name_or_luid) + if view_filter_map is not None: + final_filter_map = {} + for key in view_filter_map: + new_key = u"vf_{}".format(key) + final_filter_map[new_key] = view_filter_map[key] + + additional_url_params = u"?" + urllib.urlencode(final_filter_map) + if high_resolution is True: + additional_url_params += u"&resolution=high" + + else: + additional_url_params = u"" + if high_resolution is True: + additional_url_params += u"?resolution=high" + try: + + url = self.build_api_url(u"views/{}/{}{}".format(view_luid, download_type, additional_url_params)) + binary_result = self.send_binary_get_request(url) + + self.end_log_block() + return binary_result + except RecoverableHTTPException as e: + self.log(u"Attempt to request results in HTTP error {}, Tableau Code {}".format(e.http_code, e.tableau_error_code)) + self.end_log_block() + raise + + def query_view_image(self, view_name_or_luid, high_resolution=False, view_filter_map=None, + wb_name_or_luid=None, proj_name_or_luid=None): + """ + :type view_name_or_luid: unicode + :type high_resolution: bool + :type view_filter_map: dict + :type wb_name_or_luid: unicode + :type proj_name_or_luid + :rtype: + """ + self.start_log_block() + image = self._query_data_file(u'image', view_name_or_luid=view_name_or_luid, high_resolution=high_resolution, + view_filter_map=view_filter_map, wb_name_or_luid=wb_name_or_luid, + proj_name_or_luid=proj_name_or_luid) self.end_log_block() + return image + + def save_view_image(self, wb_name_or_luid=None, view_name_or_luid=None, filename_no_extension=None, + proj_name_or_luid=None, view_filter_map=None): + """ + :type wb_name_or_luid: unicode + :type view_name_or_luid: unicode + :type proj_name_or_luid: unicode + :type filename_no_extension: unicode + :type view_filter_map: dict + :rtype: + """ + self.start_log_block() + data = self.query_view_image(wb_name_or_luid=wb_name_or_luid, view_name_or_luid=view_name_or_luid, + proj_name_or_luid=proj_name_or_luid, view_filter_map=view_filter_map) + + if filename_no_extension is not None: + if filename_no_extension.find('.png') == -1: + filename_no_extension += '.png' + try: + save_file = open(filename_no_extension, 'wb') + save_file.write(data) + save_file.close() + self.end_log_block() + return + except IOError: + self.log(u"Error: File '{}' cannot be opened to save to".format(filename_no_extension)) + self.end_log_block() + raise + else: + raise InvalidOptionException( + u'This method is for saving response to file. Must include filename_no_extension parameter') + ### ### Fields can be used to limit or expand details can be brought in diff --git a/tableau_rest_api/tableau_rest_api_connection_28.py b/tableau_rest_api/tableau_rest_api_connection_28.py index b8374da..bda1bcb 100644 --- a/tableau_rest_api/tableau_rest_api_connection_28.py +++ b/tableau_rest_api/tableau_rest_api_connection_28.py @@ -208,6 +208,14 @@ def add_datasource_to_schedule(self, ds_name_or_luid, schedule_name_or_luid, pro self.end_log_block() + def query_view_pdf(self, wb_name_or_luid, view_name_or_luid, proj_name_or_luid=None, + view_filter_map=None): + self.start_log_block() + pdf = self._query_data_file(u'pdf', view_name_or_luid=view_name_or_luid, wb_name_or_luid=wb_name_or_luid, + proj_name_or_luid=proj_name_or_luid, view_filter_map=view_filter_map) + self.end_log_block() + return pdf + # Do not include file extension def save_view_pdf(self, wb_name_or_luid, view_name_or_luid, filename_no_extension, proj_name_or_luid=None, view_filter_map=None): @@ -220,134 +228,66 @@ def save_view_pdf(self, wb_name_or_luid, view_name_or_luid, filename_no_extensio :rtype: """ self.start_log_block() + pdf = self.query_view_pdf(view_name_or_luid=view_name_or_luid, wb_name_or_luid=wb_name_or_luid, + proj_name_or_luid=proj_name_or_luid, view_filter_map=view_filter_map) - if self.is_luid(view_name_or_luid): - view_luid = view_name_or_luid - else: - if wb_name_or_luid is None: - raise InvalidOptionException(u'If looking up view by name, must include workbook') - view_luid = self.query_workbook_view_luid(wb_name_or_luid, view_name=view_name_or_luid, - proj_name_or_luid=proj_name_or_luid) + if filename_no_extension.find(u'.pdf') == -1: + filename_no_extension += u'.pdf' try: - if filename_no_extension.find(u'.pdf') == -1: - filename_no_extension += u'.pdf' save_file = open(filename_no_extension, 'wb') - if view_filter_map is not None: - final_filter_map = {} - for key in view_filter_map: - new_key = u"vf_{}".format(key) - final_filter_map[new_key] = view_filter_map[key] - - additional_url_params = u"?" + urllib.urlencode(final_filter_map) - else: - additional_url_params = u"" - url = self.build_api_url(u"views/{}/pdf{}".format(view_luid, additional_url_params)) - image = self.send_binary_get_request(url) - save_file.write(image) + save_file.write(pdf) save_file.close() self.end_log_block() - - # You might be requesting something that doesn't exist - except RecoverableHTTPException as e: - self.log(u"Attempt to request preview image results in HTTP error {}, Tableau Code {}".format(e.http_code, e.tableau_error_code)) - self.end_log_block() - raise except IOError: self.log(u"Error: File '{}' cannot be opened to save to".format(filename_no_extension)) self.end_log_block() raise - def save_view_data_as_csv(self, wb_name_or_luid=None, view_name_or_luid=None, filename_no_extension=None, - proj_name_or_luid=None, view_filter_map=None): + def query_view_data(self, wb_name_or_luid=None, view_name_or_luid=None, proj_name_or_luid=None, + view_filter_map=None): """ :type wb_name_or_luid: unicode :type view_name_or_luid: unicode :type proj_name_or_luid: unicode - :type filename_no_extension: unicode :type view_filter_map: dict :rtype: """ self.start_log_block() + csv = self._query_data_file(u'data', view_name_or_luid=view_name_or_luid, wb_name_or_luid=wb_name_or_luid, + proj_name_or_luid=proj_name_or_luid, view_filter_map=view_filter_map) + self.end_log_block() + return csv - if self.is_luid(view_name_or_luid): - view_luid = view_name_or_luid - else: - if wb_name_or_luid is None: - raise InvalidOptionException(u'If looking up view by name, must include workbook') - view_luid = self.query_workbook_view_luid(wb_name_or_luid, view_name=view_name_or_luid, - proj_name_or_luid=proj_name_or_luid) - try: - if view_filter_map is not None: - final_filter_map = {} - for key in view_filter_map: - new_key = u"vf_{}".format(key) - final_filter_map[new_key] = view_filter_map[key] - - additional_url_params = u"?" + urllib.urlencode(final_filter_map) - else: - additional_url_params = u"" - url = self.build_api_url(u"views/{}/data{}".format(view_luid, additional_url_params)) - data = self.send_binary_get_request(url) - if filename_no_extension is not None: - if filename_no_extension.find('.csv') == -1: - filename_no_extension += '.csv' - save_file = open(filename_no_extension, 'wb') - save_file.write(data) - save_file.close() - self.end_log_block() - return - else: - raise InvalidOptionException(u'This method is for saving response to file. Must include filename_no_extension parameter') - - # You might be requesting something that doesn't exist - except RecoverableHTTPException as e: - self.log(u"Attempt to request data results in HTTP error {}, Tableau Code {}".format(e.http_code, e.tableau_error_code)) - self.end_log_block() - raise - except IOError: - self.log(u"Error: File '{}' cannot be opened to save to".format(filename_no_extension)) - self.end_log_block() - raise - - def query_view_data(self, wb_name_or_luid=None, view_name_or_luid=None, proj_name_or_luid=None, - view_filter_map=None): + def save_view_data_as_csv(self, wb_name_or_luid=None, view_name_or_luid=None, filename_no_extension=None, + proj_name_or_luid=None, view_filter_map=None): """ :type wb_name_or_luid: unicode :type view_name_or_luid: unicode :type proj_name_or_luid: unicode + :type filename_no_extension: unicode :type view_filter_map: dict - :rtype: csv + :rtype: """ self.start_log_block() + data = self.query_view_data(wb_name_or_luid=wb_name_or_luid, view_name_or_luid=view_name_or_luid, + proj_name_or_luid=proj_name_or_luid, view_filter_map=view_filter_map) - if self.is_luid(view_name_or_luid): - view_luid = view_name_or_luid + if filename_no_extension is not None: + if filename_no_extension.find('.csv') == -1: + filename_no_extension += '.csv' + try: + save_file = open(filename_no_extension, 'wb') + save_file.write(data) + save_file.close() + self.end_log_block() + return + except IOError: + self.log(u"Error: File '{}' cannot be opened to save to".format(filename_no_extension)) + self.end_log_block() + raise else: - if wb_name_or_luid is None: - raise InvalidOptionException(u'If looking up view by name, must include workbook') - view_luid = self.query_workbook_view_luid(wb_name_or_luid, view_name=view_name_or_luid, - proj_name_or_luid=proj_name_or_luid) - try: - if view_filter_map is not None: - final_filter_map = {} - for key in view_filter_map: - new_key = u"vf_{}".format(key) - final_filter_map[new_key] = view_filter_map[key] - - additional_url_params = u"?" + urllib.urlencode(final_filter_map) - else: - additional_url_params = u"" - url = self.build_api_url(u"views/{}/data{}".format(view_luid, additional_url_params)) - # Raw response should be UTF-8 encoded plain text CSV - data = self.send_binary_get_request(url) - # Convert to CSV object? - return data - - # You might be requesting something that doesn't exist - except RecoverableHTTPException as e: - self.log(u"Attempt to request data results in HTTP error {}, Tableau Code {}".format(e.http_code, e.tableau_error_code)) - self.end_log_block() - raise + raise InvalidOptionException( + u'This method is for saving response to file. Must include filename_no_extension parameter') def update_datasource_now(self, ds_name_or_luid, project_name_or_luid=False): """ diff --git a/tableau_rest_api/tableau_rest_api_connection_33.py b/tableau_rest_api/tableau_rest_api_connection_33.py index 278858a..3cd0ba5 100644 --- a/tableau_rest_api/tableau_rest_api_connection_33.py +++ b/tableau_rest_api/tableau_rest_api_connection_33.py @@ -53,6 +53,7 @@ def query_flows_for_a_site(self, sorts=None): self.end_log_block() return flows + # Just an alias for the method def query_flows(self): return self.query_flows_for_a_site()