From 98c6f876ad6f3c84694dfafa79df49e9c5ac73ff Mon Sep 17 00:00:00 2001 From: Jordan Woods <13803242+jorwoods@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:15:56 -0500 Subject: [PATCH 1/3] docs: workbook docstrings Add detailed docstrings to workbook item and endpoint --- tableauserverclient/models/workbook_item.py | 78 ++ .../server/endpoint/workbooks_endpoint.py | 801 +++++++++++++++++- 2 files changed, 877 insertions(+), 2 deletions(-) diff --git a/tableauserverclient/models/workbook_item.py b/tableauserverclient/models/workbook_item.py index ab5ff415..776d041e 100644 --- a/tableauserverclient/models/workbook_item.py +++ b/tableauserverclient/models/workbook_item.py @@ -21,6 +21,84 @@ class WorkbookItem: + """ + The workbook resources for Tableau are defined in the WorkbookItem class. + The class corresponds to the workbook resources you can access using the + Tableau REST API. Some workbook methods take an instance of the WorkbookItem + class as arguments. The workbook item specifies the project. + + Parameters + ---------- + project_id : Optional[str], optional + The project ID for the workbook, by default None. + + name : Optional[str], optional + The name of the workbook, by default None. + + show_tabs : bool, optional + Determines whether the workbook shows tabs for the view. + + Attributes + ---------- + connections : list[ConnectionItem] + The list of data connections (ConnectionItem) for the data sources used + by the workbook. You must first call the workbooks.populate_connections + method to access this data. See the ConnectionItem class. + + content_url : Optional[str] + The name of the workbook as it appears in the URL. + + created_at : Optional[datetime.datetime] + The date and time the workbook was created. + + description : Optional[str] + User-defined description of the workbook. + + id : Optional[str] + The identifier for the workbook. You need this value to query a specific + workbook or to delete a workbook with the get_by_id and delete methods. + + owner_id : Optional[str] + The identifier for the owner (UserItem) of the workbook. + + preview_image : bytes + The thumbnail image for the view. You must first call the + workbooks.populate_preview_image method to access this data. + + project_name : Optional[str] + The name of the project that contains the workbook. + + size: int + The size of the workbook in megabytes. + + hidden_views: Optional[list[str]] + List of string names of views that need to be hidden when the workbook + is published. + + tags: set[str] + The set of tags associated with the workbook. + + updated_at : Optional[datetime.datetime] + The date and time the workbook was last updated. + + views : list[ViewItem] + The list of views (ViewItem) for the workbook. You must first call the + workbooks.populate_views method to access this data. See the ViewItem + class. + + web_page_url : Optional[str] + The full URL for the workbook. + + Examples + -------- + # creating a new instance of a WorkbookItem + >>> import tableauserverclient as TSC + + >>> # Create new workbook_item with project id '3a8b6148-493c-11e6-a621-6f3499394a39' + + >>> new_workbook = TSC.WorkbookItem('3a8b6148-493c-11e6-a621-6f3499394a39') + """ + def __init__(self, project_id: Optional[str] = None, name: Optional[str] = None, show_tabs: bool = False) -> None: self._connections = None self._content_url = None diff --git a/tableauserverclient/server/endpoint/workbooks_endpoint.py b/tableauserverclient/server/endpoint/workbooks_endpoint.py index 5e4442b6..a6bde144 100644 --- a/tableauserverclient/server/endpoint/workbooks_endpoint.py +++ b/tableauserverclient/server/endpoint/workbooks_endpoint.py @@ -7,6 +7,7 @@ from pathlib import Path from tableauserverclient.helpers.headers import fix_filename +from tableauserverclient.models.permissions_item import PermissionsRule from tableauserverclient.server.query import QuerySet from tableauserverclient.server.endpoint.endpoint import QuerysetEndpoint, api, parameter_added_in @@ -69,6 +70,32 @@ def baseurl(self) -> str: # Get all workbooks on site @api(version="2.0") def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[WorkbookItem], PaginationItem]: + """ + Queries the server and returns information about the workbooks the site. + + Parameters + ---------- + (Optional) You can pass the method a request object that contains + additional parameters to filter the request. For example, if you were + searching for a specific workbook, you could specify the name of the + workbook or the name of the owner. + + Returns + ------- + Tuple containing one page's worth of workbook items and pagination + information. + + Examples + -------- + >>> import tableauserverclient as TSC + >>> tableau_auth = TSC.TableauAuth('username', 'password', site_id='site') + >>> server = TSC.Server('https://servername') + + >>> with server.auth.sign_in(tableau_auth): + >>> all_workbooks_items, pagination_item = server.workbooks.get() + >>> # print names of first 100 workbooks + >>> print([workbook.name for workbook in all_workbooks_items]) + """ logger.info("Querying all workbooks on site") url = self.baseurl server_response = self.get_request(url, req_options) @@ -79,6 +106,24 @@ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[Work # Get 1 workbook @api(version="2.0") def get_by_id(self, workbook_id: str) -> WorkbookItem: + """ + Returns information about the specified workbook on the site. + + Parameters + ---------- + workbook_id : str + The workbook ID. + + Returns + ------- + WorkbookItem + The workbook item. + + Examples + -------- + >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + >>> print(workbook.name) + """ if not workbook_id: error = "Workbook ID undefined." raise ValueError(error) @@ -89,6 +134,34 @@ def get_by_id(self, workbook_id: str) -> WorkbookItem: @api(version="2.8") def refresh(self, workbook_item: Union[WorkbookItem, str]) -> JobItem: + """ + Refreshes the extract of an existing workbook. + + Parameters + ---------- + workbook_item : WorkbookItem | str + The workbook item or workbook ID. + + Returns + ------- + JobItem + The job item. + + Examples + -------- + >>> import tableauserverclient as TSC + >>> tableau_auth = TSC.TableauAuth('username', 'password', site_id='site') + >>> server = TSC.Server('https://servername') + + >>> with server.auth.sign_in(tableau_auth): + + >>> # get the workbook item from the site + >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + + >>> # call the update method + >>> workbook = server.workbooks.refresh(workbook) + >>> print("\nThe data of workbook {0} is refreshed.".format(workbook.name)) + """ id_ = getattr(workbook_item, "id", workbook_item) url = f"{self.baseurl}/{id_}/refresh" empty_req = RequestFactory.Empty.empty_req() @@ -105,6 +178,37 @@ def create_extract( includeAll: bool = True, datasources: Optional[list["DatasourceItem"]] = None, ) -> JobItem: + """ + Create one or more extracts on 1 workbook, optionally encrypted. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#create_extracts_for_workbook + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook item to create extracts for. + + encrypt : bool, default False + Set to True to encrypt the extracts. + + includeAll : bool, default True + If True, all data sources in the workbook will have an extract + created for them. If False, then a data source must be supplied in + the request. + + datasources : list[DatasourceItem] | None + List of DatasourceItem objects for the data sources to create + extracts for. Only required if includeAll is False. + + Returns + ------- + JobItem + The job item for the extract creation. + + Examples + -------- + + """ id_ = getattr(workbook_item, "id", workbook_item) url = f"{self.baseurl}/{id_}/createExtract?encrypt={encrypt}" @@ -116,6 +220,33 @@ def create_extract( # delete all the extracts on 1 workbook @api(version="3.3") def delete_extract(self, workbook_item: WorkbookItem, includeAll: bool = True, datasources=None) -> JobItem: + """ + Delete all extracts of embedded datasources on 1 workbook. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#delete_extracts_from_workbook + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook item to delete extracts from. + + includeAll : bool, default True + If True, all data sources in the workbook will have their extracts + deleted. If False, then a data source must be supplied in the + request. + + datasources : list[DatasourceItem] | None + List of DatasourceItem objects for the data sources to delete + extracts from. Only required if includeAll is False. + + Returns + ------- + JobItem + + Examples + -------- + + """ id_ = getattr(workbook_item, "id", workbook_item) url = f"{self.baseurl}/{id_}/deleteExtract" datasource_req = RequestFactory.Workbook.embedded_extract_req(includeAll, datasources) @@ -126,6 +257,22 @@ def delete_extract(self, workbook_item: WorkbookItem, includeAll: bool = True, d # Delete 1 workbook by id @api(version="2.0") def delete(self, workbook_id: str) -> None: + """ + Deletes a workbook with the specified ID. + + Parameters + ---------- + workbook_id : str + The workbook ID. + + Returns + ------- + None + + Examples + -------- + >>> server.workbooks.delete('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + """ if not workbook_id: error = "Workbook ID undefined." raise ValueError(error) @@ -141,6 +288,49 @@ def update( workbook_item: WorkbookItem, include_view_acceleration_status: bool = False, ) -> WorkbookItem: + """ + Modifies an existing workbook. Use this method to change the owner or + the project that the workbook belongs to, or to change whether the + workbook shows views in tabs. The workbook item must include the + workbook ID and overrides the existing settings. + + See https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#update_workbook + for a list of fields that can be updated. + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook item to update. ID is required. Other fields are + optional. Any fields that are not specified will not be changed. + + include_view_acceleration_status : bool, default False + Set to True to include the view acceleration status in the response. + + Returns + ------- + WorkbookItem + The updated workbook item. + + Examples + -------- + + >>> import tableauserverclient as TSC + >>> tableau_auth = TSC.TableauAuth('username', 'password', site_id='site') + >>> server = TSC.Server('https://servername') + + >>> with server.auth.sign_in(tableau_auth): + + >>> # get the workbook item from the site + >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + >>> print("\nUpdate {0} workbook. Project was {1}".format(workbook.name, workbook.project_name)) + + >>> # make an change, for example a new project ID + >>> workbook.project_id = '1f2f3e4e-5d6d-7c8c-9b0b-1a2a3f4f5e6e' + + >>> # call the update method + >>> workbook = server.workbooks.update(workbook) + >>> print("\nUpdated {0} workbook. Project is now {1}".format(workbook.name, workbook.project_name)) + """ if not workbook_item.id: error = "Workbook item missing ID. Workbook must be retrieved from server first." raise MissingRequiredFieldError(error) @@ -161,6 +351,42 @@ def update( # Update workbook_connection @api(version="2.3") def update_connection(self, workbook_item: WorkbookItem, connection_item: ConnectionItem) -> ConnectionItem: + """ + Updates a workbook connection information (server addres, server port, + user name, and password). + + The workbook connections must be populated before the strings can be + updated. + + Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#update_workbook_connection + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook item to update. + + connection_item : ConnectionItem + The connection item to update. + + Returns + ------- + ConnectionItem + The updated connection item. + + Examples + -------- + >>> # query for workbook connections + >>> server.workbooks.populate_connections(workbook) + + >>> # update the connection + >>> connection = workbook.connections[0] + >>> connection.username = 'new_username' + >>> connection.password = 'new_password' + + >>> # call the update method + >>> connection = server.workbooks.update_connection(workbook, connection) + + """ url = f"{self.baseurl}/{workbook_item.id}/connections/{connection_item.id}" update_req = RequestFactory.Connection.update_req(connection_item) server_response = self.put_request(url, update_req) @@ -179,6 +405,38 @@ def download( filepath: Optional[PathOrFileW] = None, include_extract: bool = True, ) -> PathOrFileW: + """ + Downloads a workbook to the specified directory (optional). + + Parameters + ---------- + workbook_id : str + The workbook ID. + + filepath : Path or File object, optional + Downloads the file to the location you specify. If no location is + specified, the file is downloaded to the current working directory. + The default is Filepath=None. + + include_extract : bool, default True + Set to False to exclude the extract from the download. The default + is True. + + Returns + ------- + Path or File object + The path to the downloaded workbook or the file object. + + Raises + ------ + ValueError + If the workbook ID is not defined. + + Examples + -------- + >>> filepath = server.workbooks.download('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + """ + return self.download_revision( workbook_id, None, @@ -189,6 +447,54 @@ def download( # Get all views of workbook @api(version="2.0") def populate_views(self, workbook_item: WorkbookItem, usage: bool = False) -> None: + """ + Populates (or gets) a list of views for a workbook. + + You must first call this method to populate views before you can iterate + through the views. + + This method retrieves the view information for the specified workbook. + The REST API is designed to return only the information you ask for + explicitly. When you query for all the workbooks, the view information + is not included. Use this method to retrieve the views. The method adds + the list of views to the workbook item (workbook_item.views). This is a + list of ViewItem. + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook item to populate views for. + + usage : bool, default False + Set to True to include usage statistics for each view. + + Returns + ------- + None + + Raises + ------ + MissingRequiredFieldError + If the workbook item is missing an ID. + + Examples + -------- + >>> # import tableauserverclient as TSC + + >>> # server = TSC.Server('https://SERVERURL') + >>> # ... + + >>> # get the workbook item + >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + + + >>> # get the view information + >>> server.workbooks.populate_views(workbook) + + >>> # print information about the views for the work item + >>> print("\nThe views for {0}: ".format(workbook.name)) + >>> print([view.name for view in workbook.views]) + """ if not workbook_item.id: error = "Workbook item missing ID. Workbook must be retrieved from server first." raise MissingRequiredFieldError(error) @@ -214,6 +520,54 @@ def _get_views_for_workbook(self, workbook_item: WorkbookItem, usage: bool) -> l # Get all connections of workbook @api(version="2.0") def populate_connections(self, workbook_item: WorkbookItem) -> None: + """ + Populates a list of data source connections for the specified workbook. + + You must populate connections before you can iterate through the + connections. + + This method retrieves the data source connection information for the + specified workbook. The REST API is designed to return only the + information you ask for explicitly. When you query all the workbooks, + the data source connection information is not included. Use this method + to retrieve the connection information for any data sources used by the + workbook. The method adds the list of data connections to the workbook + item (workbook_item.connections). This is a list of ConnectionItem. + + REST API docs: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_workbook_connections + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook item to populate connections for. + + Returns + ------- + None + + Raises + ------ + MissingRequiredFieldError + If the workbook item is missing an ID. + + Examples + -------- + >>> # import tableauserverclient as TSC + + >>> # server = TSC.Server('https://SERVERURL') + >>> # ... + + >>> # get the workbook item + >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + + + >>> # get the connection information + >>> server.workbooks.populate_connections(workbook) + + >>> # print information about the data connections for the workbook item + >>> print("\nThe connections for {0}: ".format(workbook.name)) + >>> print([connection.id for connection in workbook.connections]) + """ if not workbook_item.id: error = "Workbook item missing ID. Workbook must be retrieved from server first." raise MissingRequiredFieldError(error) @@ -235,6 +589,40 @@ def _get_workbook_connections( # Get the pdf of the entire workbook if its tabs are enabled, pdf of the default view if its tabs are disabled @api(version="3.4") def populate_pdf(self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"] = None) -> None: + """ + Populates the PDF for the specified workbook item. + + This method populates a PDF with image(s) of the workbook view(s) you + specify. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#download_workbook_pdf + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook item to populate the PDF for. + + req_options : RequestOptions, optional + (Optional) You can pass in request options to specify the page type + and orientation of the PDF content, as well as the maximum age of + the PDF rendered on the server. See PDFRequestOptions class for more + details. + + Returns + ------- + None + + Raises + ------ + MissingRequiredFieldError + If the workbook item is missing an ID. + + Examples + -------- + >>> server.workbooks.populate_pdf(workbook) + >>> with open("workbook.pdf", "wb") as f: + >>> f.write(workbook.pdf) + """ if not workbook_item.id: error = "Workbook item missing ID." raise MissingRequiredFieldError(error) @@ -253,6 +641,42 @@ def _get_wb_pdf(self, workbook_item: WorkbookItem, req_options: Optional["Reques @api(version="3.8") def populate_powerpoint(self, workbook_item: WorkbookItem, req_options: Optional["RequestOptions"] = None) -> None: + """ + Populates the PowerPoint for the specified workbook item. + + This method populates a PowerPoint with image(s) of the workbook view(s) you + specify. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#download_workbook_powerpoint + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook item to populate the PDF for. + + req_options : RequestOptions, optional + (Optional) You can pass in request options to specify the maximum + number of minutes a workbook .pptx will be cached before being + refreshed. To prevent multiple .pptx requests from overloading the + server, the shortest interval you can set is one minute. There is no + maximum value, but the server job enacting the caching action may + expire before a long cache period is reached. + + Returns + ------- + None + + Raises + ------ + MissingRequiredFieldError + If the workbook item is missing an ID. + + Examples + -------- + >>> server.workbooks.populate_powerpoint(workbook) + >>> with open("workbook.pptx", "wb") as f: + >>> f.write(workbook.pptx) + """ if not workbook_item.id: error = "Workbook item missing ID." raise MissingRequiredFieldError(error) @@ -272,6 +696,38 @@ def _get_wb_pptx(self, workbook_item: WorkbookItem, req_options: Optional["Reque # Get preview image of workbook @api(version="2.0") def populate_preview_image(self, workbook_item: WorkbookItem) -> None: + """ + This method gets the preview image (thumbnail) for the specified workbook item. + + This method uses the workbook's ID to get the preview image. The method + adds the preview image to the workbook item (workbook_item.preview_image). + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook item to populate the preview image for. + + Returns + ------- + None + + Raises + ------ + MissingRequiredFieldError + If the workbook item is missing an ID. + + Examples + -------- + >>> # import tableauserverclient as TSC + >>> # server = TSC.Server('https://SERVERURL') + >>> # ... + + >>> # get the workbook item + >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + + >>> # get the preview image + >>> server.workbooks.populate_preview_image(workbook) + """ if not workbook_item.id: error = "Workbook item missing ID. Workbook must be retrieved from server first." raise MissingRequiredFieldError(error) @@ -290,14 +746,85 @@ def _get_wb_preview_image(self, workbook_item: WorkbookItem) -> bytes: @api(version="2.0") def populate_permissions(self, item: WorkbookItem) -> None: + """ + Populates the permissions for the specified workbook item. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_permissions.htm#query_workbook_permissions + + Parameters + ---------- + item : WorkbookItem + The workbook item to populate permissions for. + + Returns + ------- + None + + Examples + -------- + >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + >>> server.workbooks.populate_permissions(workbook) + """ self._permissions.populate(item) @api(version="2.0") - def update_permissions(self, resource, rules): + def update_permissions(self, resource: WorkbookItem, rules: list[PermissionsRule]) -> list[PermissionsRule]: + """ + Updates the permissions for the specified workbook item. The method + replaces the existing permissions with the new permissions. Any missing + permissions are removed. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_permissions.htm#replace_permissions_for_content + + Parameters + ---------- + resource : WorkbookItem + The workbook item to update permissions for. + + rules : list[PermissionsRule] + A list of permissions rules to apply to the workbook item. + + Returns + ------- + list[PermissionsRule] + The updated permissions rules. + + Examples + -------- + >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + >>> server.workbooks.populate_permissions(workbook) + >>> rules = workbook.permissions + >>> rules[0].capabilities |= {TSC.PermissionRule.Capability.Read: TSC.PermissionRule.Mode.Allow} + >>> server.workbooks.update_permissions(workbook, rules) + """ return self._permissions.update(resource, rules) @api(version="2.0") - def delete_permission(self, item, capability_item): + def delete_permission(self, item: WorkbookItem, capability_item: PermissionsRule) -> None: + """ + Deletes a single permission rule from the specified workbook item. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_permissions.htm#delete_workbook_permission + + Parameters + ---------- + item : WorkbookItem + The workbook item to delete the permission from. + + capability_item : PermissionsRule + The permission rule to delete. + + Returns + ------- + None + + Examples + -------- + >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + >>> server.workbooks.populate_permissions(workbook) + >>> rule = workbook.permissions[0] + >>> server.workbooks.delete_permission(workbook, rule) + """ return self._permissions.delete(item, capability_item) @api(version="2.0") @@ -313,6 +840,97 @@ def publish( skip_connection_check: bool = False, parameters=None, ): + """ + Publish a workbook to the specified site. + + Note: The REST API cannot automatically include extracts or other + resources that the workbook uses. Therefore, a .twb file that uses data + from an Excel or csv file on a local computer cannot be published, + unless you package the data and workbook in a .twbx file, or publish the + data source separately. + + For workbooks that are larger than 64 MB, the publish method + automatically takes care of chunking the file in parts for uploading. + Using this method is considerably more convenient than calling the + publish REST APIs directly. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#publish_workbook + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook_item specifies the workbook you are publishing. When + you are adding a workbook, you need to first create a new instance + of a workbook_item that includes a project_id of an existing + project. The name of the workbook will be the name of the file, + unless you also specify a name for the new workbook when you create + the instance. + + file : Path or File object + The file path or file object of the workbook to publish. When + providing a file object, you must also specifiy the name of the + workbook in your instance of the workbook_itemworkbook_item , as + the name cannot be derived from the file name. + + mode : str + Specifies whether you are publishing a new workbook (CreateNew) or + overwriting an existing workbook (Overwrite). You cannot appending + workbooks. You can also use the publish mode attributes, for + example: TSC.Server.PublishMode.Overwrite. + + connections : list[ConnectionItem] | None + List of ConnectionItems objects for the connections created within + the workbook. + + as_job : bool, default False + Set to True to run the upload as a job (asynchronous upload). If set + to True a job will start to perform the publishing process and a Job + object is returned. Defaults to False. + + skip_connection_check : bool, default False + Set to True to skip connection check at time of upload. Publishing + will succeed but unchecked connection issues may result in a + non-functioning workbook. Defaults to False. + + Raises + ------ + OSError + If the file path does not lead to an existing file. + + ServerResponseError + If the server response is not successful. + + TypeError + If the file is not a file path or file object. + + ValueError + If the file extension is not supported + + ValueError + If the mode is invalid. + + ValueError + Workbooks cannot be appended. + + Returns + ------- + WorkbookItem | JobItem + The workbook item or job item that was published. + + Examples + -------- + >>> import tableauserverclient as TSC + >>> tableau_auth = TSC.TableauAuth('username', 'password', site_id='site') + >>> server = TSC.Server('https://servername') + + >>> with server.auth.sign_in(tableau_auth): + >>> # create a workbook item + >>> wb_item = TSC.WorkbookItem(name='Sample', project_id='1f2f3e4e-5d6d-7c8c-9b0b-1a2a3f4f5e6e') + >>> # set hidden views + >>> wb_item.hidden_views = ['Sheet1', 'Sheet2'] + >>> # call the publish method with the workbook item + >>> wb_item = server.workbooks.publish(wb_item, 'SampleWB.twbx', 'Overwrite') + """ if isinstance(file, (str, os.PathLike)): if not os.path.isfile(file): error = "File path does not lead to an existing file." @@ -419,6 +1037,35 @@ def publish( # Populate workbook item's revisions @api(version="2.3") def populate_revisions(self, workbook_item: WorkbookItem) -> None: + """ + Populates (or gets) a list of revisions for a workbook. + + You must first call this method to populate revisions before you can + iterate through the revisions. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#get_workbook_revisions + + Parameters + ---------- + workbook_item : WorkbookItem + The workbook item to populate revisions for. + + Returns + ------- + None + + Raises + ------ + MissingRequiredFieldError + If the workbook item is missing an ID. + + Examples + -------- + >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') + >>> server.workbooks.populate_revisions(workbook) + >>> print([revision.revision_number for revision in workbook.revisions]) + + """ if not workbook_item.id: error = "Workbook item missing ID. Workbook must be retrieved from server first." raise MissingRequiredFieldError(error) @@ -446,6 +1093,44 @@ def download_revision( filepath: Optional[PathOrFileW] = None, include_extract: bool = True, ) -> PathOrFileW: + """ + Downloads a workbook revision to the specified directory (optional). + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#download_workbook_revision + + Parameters + ---------- + workbook_id : str + The workbook ID. + + revision_number : str | None + The revision number of the workbook. If None, the latest revision is + downloaded. + + filepath : Path or File object, optional + Downloads the file to the location you specify. If no location is + specified, the file is downloaded to the current working directory. + The default is Filepath=None. + + include_extract : bool, default True + Set to False to exclude the extract from the download. The default + is True. + + Returns + ------- + Path or File object + The path to the downloaded workbook or the file object. + + Raises + ------ + ValueError + If the workbook ID is not defined. + + Examples + -------- + >>> filepath = server.workbooks.download('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d', '5') + """ + if not workbook_id: error = "Workbook ID undefined." raise ValueError(error) @@ -479,6 +1164,32 @@ def download_revision( @api(version="2.3") def delete_revision(self, workbook_id: str, revision_number: str) -> None: + """ + Deletes a specific revision from a workbook on Tableau Server. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_revisions.htm#remove_workbook_revision + + Parameters + ---------- + workbook_id : str + The workbook ID. + + revision_number : str + The revision number of the workbook to delete. + + Returns + ------- + None + + Raises + ------ + ValueError + If the workbook ID or revision number is not defined. + + Examples + -------- + >>> server.workbooks.delete_revision('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d', '5') + """ if workbook_id is None or revision_number is None: raise ValueError url = "/".join([self.baseurl, workbook_id, "revisions", revision_number]) @@ -491,18 +1202,104 @@ def delete_revision(self, workbook_id: str, revision_number: str) -> None: def schedule_extract_refresh( self, schedule_id: str, item: WorkbookItem ) -> list["AddResponse"]: # actually should return a task + """ + Adds a workbook to a schedule for extract refresh. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#add_workbook_to_schedule + + Parameters + ---------- + schedule_id : str + The schedule ID. + + item : WorkbookItem + The workbook item to add to the schedule. + + Returns + ------- + list[AddResponse] + The response from the server. + + Examples + -------- + >>> server.workbooks.schedule_extract_refresh('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d', workbook) + """ return self.parent_srv.schedules.add_to_schedule(schedule_id, workbook=item) @api(version="1.0") def add_tags(self, item: Union[WorkbookItem, str], tags: Union[Iterable[str], str]) -> set[str]: + """ + Adds tags to a workbook. One or more tags may be added at a time. If a + tag already exists on the workbook, it will not be duplicated. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#add_tags_to_workbook + + Parameters + ---------- + item : WorkbookItem | str + The workbook item or workbook ID to add tags to. + + tags : Iterable[str] | str + The tag or tags to add to the workbook. Tags can be a single tag or + a list of tags. + + Returns + ------- + set[str] + The set of tags added to the workbook. + + Examples + -------- + >>> server.workbooks.add_tags(workbook, 'tag1') + >>> server.workbooks.add_tags(workbook, ['tag1', 'tag2']) + """ return super().add_tags(item, tags) @api(version="1.0") def delete_tags(self, item: Union[WorkbookItem, str], tags: Union[Iterable[str], str]) -> None: + """ + Deletes tags from a workbook. One or more tags may be deleted at a time. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#delete_tag_from_workbook + + Parameters + ---------- + item : WorkbookItem | str + The workbook item or workbook ID to delete tags from. + + tags : Iterable[str] | str + The tag or tags to delete from the workbook. Tags can be a single + tag or a list of tags. + + Returns + ------- + None + + Examples + -------- + >>> server.workbooks.delete_tags(workbook, 'tag1') + >>> server.workbooks.delete_tags(workbook, ['tag1', 'tag2']) + """ return super().delete_tags(item, tags) @api(version="1.0") def update_tags(self, item: WorkbookItem) -> None: + """ + Updates the tags on a workbook. This method is used to update the tags + on the server to match the tags on the workbook item. This method is a + convenience method that calls add_tags and delete_tags to update the + tags on the server. + + Parameters + ---------- + item : WorkbookItem + The workbook item to update the tags for. The tags on the workbook + item will be used to update the tags on the server. + + Returns + ------- + None + """ return super().update_tags(item) def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> QuerySet[WorkbookItem]: From 067094eb600146f3921228572a959ef2151a1af8 Mon Sep 17 00:00:00 2001 From: Jordan Woods <13803242+jorwoods@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:35:03 -0500 Subject: [PATCH 2/3] fix: missing variable name --- .../server/endpoint/workbooks_endpoint.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tableauserverclient/server/endpoint/workbooks_endpoint.py b/tableauserverclient/server/endpoint/workbooks_endpoint.py index a6bde144..ce2f9ba9 100644 --- a/tableauserverclient/server/endpoint/workbooks_endpoint.py +++ b/tableauserverclient/server/endpoint/workbooks_endpoint.py @@ -75,10 +75,11 @@ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[Work Parameters ---------- - (Optional) You can pass the method a request object that contains - additional parameters to filter the request. For example, if you were - searching for a specific workbook, you could specify the name of the - workbook or the name of the owner. + req_options : RequestOptions, optional + (Optional) You can pass the method a request object that contains + additional parameters to filter the request. For example, if you + were searching for a specific workbook, you could specify the name + of the workbook or the name of the owner. Returns ------- From a1aacb3124d785b46d2e4b61c3b7a95e4981558d Mon Sep 17 00:00:00 2001 From: Jordan Woods <13803242+jorwoods@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:06:34 -0500 Subject: [PATCH 3/3] docs: remove examples --- .../server/endpoint/workbooks_endpoint.py | 204 ------------------ 1 file changed, 204 deletions(-) diff --git a/tableauserverclient/server/endpoint/workbooks_endpoint.py b/tableauserverclient/server/endpoint/workbooks_endpoint.py index ce2f9ba9..460017d1 100644 --- a/tableauserverclient/server/endpoint/workbooks_endpoint.py +++ b/tableauserverclient/server/endpoint/workbooks_endpoint.py @@ -85,17 +85,6 @@ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[Work ------- Tuple containing one page's worth of workbook items and pagination information. - - Examples - -------- - >>> import tableauserverclient as TSC - >>> tableau_auth = TSC.TableauAuth('username', 'password', site_id='site') - >>> server = TSC.Server('https://servername') - - >>> with server.auth.sign_in(tableau_auth): - >>> all_workbooks_items, pagination_item = server.workbooks.get() - >>> # print names of first 100 workbooks - >>> print([workbook.name for workbook in all_workbooks_items]) """ logger.info("Querying all workbooks on site") url = self.baseurl @@ -119,11 +108,6 @@ def get_by_id(self, workbook_id: str) -> WorkbookItem: ------- WorkbookItem The workbook item. - - Examples - -------- - >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') - >>> print(workbook.name) """ if not workbook_id: error = "Workbook ID undefined." @@ -147,21 +131,6 @@ def refresh(self, workbook_item: Union[WorkbookItem, str]) -> JobItem: ------- JobItem The job item. - - Examples - -------- - >>> import tableauserverclient as TSC - >>> tableau_auth = TSC.TableauAuth('username', 'password', site_id='site') - >>> server = TSC.Server('https://servername') - - >>> with server.auth.sign_in(tableau_auth): - - >>> # get the workbook item from the site - >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') - - >>> # call the update method - >>> workbook = server.workbooks.refresh(workbook) - >>> print("\nThe data of workbook {0} is refreshed.".format(workbook.name)) """ id_ = getattr(workbook_item, "id", workbook_item) url = f"{self.baseurl}/{id_}/refresh" @@ -205,10 +174,6 @@ def create_extract( ------- JobItem The job item for the extract creation. - - Examples - -------- - """ id_ = getattr(workbook_item, "id", workbook_item) url = f"{self.baseurl}/{id_}/createExtract?encrypt={encrypt}" @@ -243,10 +208,6 @@ def delete_extract(self, workbook_item: WorkbookItem, includeAll: bool = True, d Returns ------- JobItem - - Examples - -------- - """ id_ = getattr(workbook_item, "id", workbook_item) url = f"{self.baseurl}/{id_}/deleteExtract" @@ -269,10 +230,6 @@ def delete(self, workbook_id: str) -> None: Returns ------- None - - Examples - -------- - >>> server.workbooks.delete('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') """ if not workbook_id: error = "Workbook ID undefined." @@ -311,26 +268,6 @@ def update( ------- WorkbookItem The updated workbook item. - - Examples - -------- - - >>> import tableauserverclient as TSC - >>> tableau_auth = TSC.TableauAuth('username', 'password', site_id='site') - >>> server = TSC.Server('https://servername') - - >>> with server.auth.sign_in(tableau_auth): - - >>> # get the workbook item from the site - >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') - >>> print("\nUpdate {0} workbook. Project was {1}".format(workbook.name, workbook.project_name)) - - >>> # make an change, for example a new project ID - >>> workbook.project_id = '1f2f3e4e-5d6d-7c8c-9b0b-1a2a3f4f5e6e' - - >>> # call the update method - >>> workbook = server.workbooks.update(workbook) - >>> print("\nUpdated {0} workbook. Project is now {1}".format(workbook.name, workbook.project_name)) """ if not workbook_item.id: error = "Workbook item missing ID. Workbook must be retrieved from server first." @@ -373,20 +310,6 @@ def update_connection(self, workbook_item: WorkbookItem, connection_item: Connec ------- ConnectionItem The updated connection item. - - Examples - -------- - >>> # query for workbook connections - >>> server.workbooks.populate_connections(workbook) - - >>> # update the connection - >>> connection = workbook.connections[0] - >>> connection.username = 'new_username' - >>> connection.password = 'new_password' - - >>> # call the update method - >>> connection = server.workbooks.update_connection(workbook, connection) - """ url = f"{self.baseurl}/{workbook_item.id}/connections/{connection_item.id}" update_req = RequestFactory.Connection.update_req(connection_item) @@ -432,10 +355,6 @@ def download( ------ ValueError If the workbook ID is not defined. - - Examples - -------- - >>> filepath = server.workbooks.download('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') """ return self.download_revision( @@ -477,24 +396,6 @@ def populate_views(self, workbook_item: WorkbookItem, usage: bool = False) -> No ------ MissingRequiredFieldError If the workbook item is missing an ID. - - Examples - -------- - >>> # import tableauserverclient as TSC - - >>> # server = TSC.Server('https://SERVERURL') - >>> # ... - - >>> # get the workbook item - >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') - - - >>> # get the view information - >>> server.workbooks.populate_views(workbook) - - >>> # print information about the views for the work item - >>> print("\nThe views for {0}: ".format(workbook.name)) - >>> print([view.name for view in workbook.views]) """ if not workbook_item.id: error = "Workbook item missing ID. Workbook must be retrieved from server first." @@ -550,24 +451,6 @@ def populate_connections(self, workbook_item: WorkbookItem) -> None: ------ MissingRequiredFieldError If the workbook item is missing an ID. - - Examples - -------- - >>> # import tableauserverclient as TSC - - >>> # server = TSC.Server('https://SERVERURL') - >>> # ... - - >>> # get the workbook item - >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') - - - >>> # get the connection information - >>> server.workbooks.populate_connections(workbook) - - >>> # print information about the data connections for the workbook item - >>> print("\nThe connections for {0}: ".format(workbook.name)) - >>> print([connection.id for connection in workbook.connections]) """ if not workbook_item.id: error = "Workbook item missing ID. Workbook must be retrieved from server first." @@ -617,12 +500,6 @@ def populate_pdf(self, workbook_item: WorkbookItem, req_options: Optional["Reque ------ MissingRequiredFieldError If the workbook item is missing an ID. - - Examples - -------- - >>> server.workbooks.populate_pdf(workbook) - >>> with open("workbook.pdf", "wb") as f: - >>> f.write(workbook.pdf) """ if not workbook_item.id: error = "Workbook item missing ID." @@ -671,12 +548,6 @@ def populate_powerpoint(self, workbook_item: WorkbookItem, req_options: Optional ------ MissingRequiredFieldError If the workbook item is missing an ID. - - Examples - -------- - >>> server.workbooks.populate_powerpoint(workbook) - >>> with open("workbook.pptx", "wb") as f: - >>> f.write(workbook.pptx) """ if not workbook_item.id: error = "Workbook item missing ID." @@ -716,18 +587,6 @@ def populate_preview_image(self, workbook_item: WorkbookItem) -> None: ------ MissingRequiredFieldError If the workbook item is missing an ID. - - Examples - -------- - >>> # import tableauserverclient as TSC - >>> # server = TSC.Server('https://SERVERURL') - >>> # ... - - >>> # get the workbook item - >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') - - >>> # get the preview image - >>> server.workbooks.populate_preview_image(workbook) """ if not workbook_item.id: error = "Workbook item missing ID. Workbook must be retrieved from server first." @@ -760,11 +619,6 @@ def populate_permissions(self, item: WorkbookItem) -> None: Returns ------- None - - Examples - -------- - >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') - >>> server.workbooks.populate_permissions(workbook) """ self._permissions.populate(item) @@ -789,14 +643,6 @@ def update_permissions(self, resource: WorkbookItem, rules: list[PermissionsRule ------- list[PermissionsRule] The updated permissions rules. - - Examples - -------- - >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') - >>> server.workbooks.populate_permissions(workbook) - >>> rules = workbook.permissions - >>> rules[0].capabilities |= {TSC.PermissionRule.Capability.Read: TSC.PermissionRule.Mode.Allow} - >>> server.workbooks.update_permissions(workbook, rules) """ return self._permissions.update(resource, rules) @@ -818,13 +664,6 @@ def delete_permission(self, item: WorkbookItem, capability_item: PermissionsRule Returns ------- None - - Examples - -------- - >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') - >>> server.workbooks.populate_permissions(workbook) - >>> rule = workbook.permissions[0] - >>> server.workbooks.delete_permission(workbook, rule) """ return self._permissions.delete(item, capability_item) @@ -917,20 +756,6 @@ def publish( ------- WorkbookItem | JobItem The workbook item or job item that was published. - - Examples - -------- - >>> import tableauserverclient as TSC - >>> tableau_auth = TSC.TableauAuth('username', 'password', site_id='site') - >>> server = TSC.Server('https://servername') - - >>> with server.auth.sign_in(tableau_auth): - >>> # create a workbook item - >>> wb_item = TSC.WorkbookItem(name='Sample', project_id='1f2f3e4e-5d6d-7c8c-9b0b-1a2a3f4f5e6e') - >>> # set hidden views - >>> wb_item.hidden_views = ['Sheet1', 'Sheet2'] - >>> # call the publish method with the workbook item - >>> wb_item = server.workbooks.publish(wb_item, 'SampleWB.twbx', 'Overwrite') """ if isinstance(file, (str, os.PathLike)): if not os.path.isfile(file): @@ -1059,13 +884,6 @@ def populate_revisions(self, workbook_item: WorkbookItem) -> None: ------ MissingRequiredFieldError If the workbook item is missing an ID. - - Examples - -------- - >>> workbook = server.workbooks.get_by_id('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d') - >>> server.workbooks.populate_revisions(workbook) - >>> print([revision.revision_number for revision in workbook.revisions]) - """ if not workbook_item.id: error = "Workbook item missing ID. Workbook must be retrieved from server first." @@ -1126,10 +944,6 @@ def download_revision( ------ ValueError If the workbook ID is not defined. - - Examples - -------- - >>> filepath = server.workbooks.download('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d', '5') """ if not workbook_id: @@ -1186,10 +1000,6 @@ def delete_revision(self, workbook_id: str, revision_number: str) -> None: ------ ValueError If the workbook ID or revision number is not defined. - - Examples - -------- - >>> server.workbooks.delete_revision('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d', '5') """ if workbook_id is None or revision_number is None: raise ValueError @@ -1220,10 +1030,6 @@ def schedule_extract_refresh( ------- list[AddResponse] The response from the server. - - Examples - -------- - >>> server.workbooks.schedule_extract_refresh('1a1b1c1d-2e2f-2a2b-3c3d-3e3f4a4b4c4d', workbook) """ return self.parent_srv.schedules.add_to_schedule(schedule_id, workbook=item) @@ -1248,11 +1054,6 @@ def add_tags(self, item: Union[WorkbookItem, str], tags: Union[Iterable[str], st ------- set[str] The set of tags added to the workbook. - - Examples - -------- - >>> server.workbooks.add_tags(workbook, 'tag1') - >>> server.workbooks.add_tags(workbook, ['tag1', 'tag2']) """ return super().add_tags(item, tags) @@ -1275,11 +1076,6 @@ def delete_tags(self, item: Union[WorkbookItem, str], tags: Union[Iterable[str], Returns ------- None - - Examples - -------- - >>> server.workbooks.delete_tags(workbook, 'tag1') - >>> server.workbooks.delete_tags(workbook, ['tag1', 'tag2']) """ return super().delete_tags(item, tags)