Skip to content

Commit

Permalink
docs: docstrings for custom_views (#1540)
Browse files Browse the repository at this point in the history
Also adds support for using view_id, workbook_id and owner_id
to filter custom_views returned by the REST API

Co-authored-by: Jordan Woods <[email protected]>
  • Loading branch information
jorwoods and jorwoods authored Nov 27, 2024
1 parent 3460528 commit a4278e5
Show file tree
Hide file tree
Showing 3 changed files with 249 additions and 17 deletions.
54 changes: 49 additions & 5 deletions tableauserverclient/models/custom_view_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,58 @@
from typing import Callable, Optional
from collections.abc import Iterator

from .exceptions import UnpopulatedPropertyError
from .user_item import UserItem
from .view_item import ViewItem
from .workbook_item import WorkbookItem
from ..datetime_helpers import parse_datetime
from tableauserverclient.models.exceptions import UnpopulatedPropertyError
from tableauserverclient.models.user_item import UserItem
from tableauserverclient.models.view_item import ViewItem
from tableauserverclient.models.workbook_item import WorkbookItem
from tableauserverclient.datetime_helpers import parse_datetime


class CustomViewItem:
"""
Represents a Custom View item on Tableau Server.
Parameters
----------
id : Optional[str]
The ID of the Custom View item.
name : Optional[str]
The name of the Custom View item.
Attributes
----------
content_url : Optional[str]
The content URL of the Custom View item.
created_at : Optional[datetime]
The date and time the Custom View item was created.
image: bytes
The image of the Custom View item. Must be populated first.
pdf: bytes
The PDF of the Custom View item. Must be populated first.
csv: Iterator[bytes]
The CSV of the Custom View item. Must be populated first.
shared : Optional[bool]
Whether the Custom View item is shared.
updated_at : Optional[datetime]
The date and time the Custom View item was last updated.
owner : Optional[UserItem]
The id of the owner of the Custom View item.
workbook : Optional[WorkbookItem]
The id of the workbook the Custom View item belongs to.
view : Optional[ViewItem]
The id of the view the Custom View item belongs to.
"""

def __init__(self, id: Optional[str] = None, name: Optional[str] = None) -> None:
self._content_url: Optional[str] = None # ?
self._created_at: Optional["datetime"] = None
Expand Down
209 changes: 197 additions & 12 deletions tableauserverclient/server/endpoint/custom_views_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os
from contextlib import closing
from pathlib import Path
from typing import Optional, Union
from typing import Optional, Union, TYPE_CHECKING
from collections.abc import Iterator

from tableauserverclient.config import BYTES_PER_MB, config
Expand All @@ -21,6 +21,9 @@

from tableauserverclient.helpers.logging import logger

if TYPE_CHECKING:
from tableauserverclient.server.query import QuerySet

"""
Get a list of custom views on a site
get the details of a custom view
Expand Down Expand Up @@ -51,19 +54,31 @@ def baseurl(self) -> str:
def expurl(self) -> str:
return f"{self.parent_srv._server_address}/api/exp/sites/{self.parent_srv.site_id}/customviews"

"""
If the request has no filter parameters: Administrators will see all custom views.
Other users will see only custom views that they own.
If the filter parameters include ownerId: Users will see only custom views that they own.
If the filter parameters include viewId and/or workbookId, and don't include ownerId:
Users will see those custom views that they have Write and WebAuthoring permissions for.
If site user visibility is not set to Limited, the Users will see those custom views that are "public",
meaning the value of their shared attribute is true.
If site user visibility is set to Limited, ????
"""

@api(version="3.18")
def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[CustomViewItem], PaginationItem]:
"""
Get a list of custom views on a site.
If the request has no filter parameters: Administrators will see all custom views.
Other users will see only custom views that they own.
If the filter parameters include ownerId: Users will see only custom views that they own.
If the filter parameters include viewId and/or workbookId, and don't include ownerId:
Users will see those custom views that they have Write and WebAuthoring permissions for.
If site user visibility is not set to Limited, the Users will see those custom views that are "public",
meaning the value of their shared attribute is true.
If site user visibility is set to Limited, ????
Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#list_custom_views
Parameters
----------
req_options : RequestOptions, optional
Filtering options for the request, by default None
Returns
-------
tuple[list[CustomViewItem], PaginationItem]
"""
logger.info("Querying all custom views on site")
url = self.baseurl
server_response = self.get_request(url, req_options)
Expand All @@ -73,6 +88,19 @@ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[Cust

@api(version="3.18")
def get_by_id(self, view_id: str) -> Optional[CustomViewItem]:
"""
Get the details of a specific custom view.
Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#get_custom_view
Parameters
----------
view_id : str
Returns
-------
Optional[CustomViewItem]
"""
if not view_id:
error = "Custom view item missing ID."
raise MissingRequiredFieldError(error)
Expand All @@ -83,6 +111,27 @@ def get_by_id(self, view_id: str) -> Optional[CustomViewItem]:

@api(version="3.18")
def populate_image(self, view_item: CustomViewItem, req_options: Optional["ImageRequestOptions"] = None) -> None:
"""
Populate the image of a custom view.
Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#get_custom_view_image
Parameters
----------
view_item : CustomViewItem
req_options : ImageRequestOptions, optional
Options to customize the image returned, by default None
Returns
-------
None
Raises
------
MissingRequiredFieldError
If the view_item is missing an ID
"""
if not view_item.id:
error = "Custom View item missing ID."
raise MissingRequiredFieldError(error)
Expand All @@ -101,6 +150,26 @@ def _get_view_image(self, view_item: CustomViewItem, req_options: Optional["Imag

@api(version="3.23")
def populate_pdf(self, custom_view_item: CustomViewItem, req_options: Optional["PDFRequestOptions"] = None) -> None:
"""
Populate the PDF of a custom view.
Parameters
----------
custom_view_item : CustomViewItem
The custom view item to populate the PDF for.
req_options : PDFRequestOptions, optional
Options to customize the PDF returned, by default None
Returns
-------
None
Raises
------
MissingRequiredFieldError
If the custom view item is missing an ID
"""
if not custom_view_item.id:
error = "Custom View item missing ID."
raise MissingRequiredFieldError(error)
Expand All @@ -121,6 +190,26 @@ def _get_custom_view_pdf(

@api(version="3.23")
def populate_csv(self, custom_view_item: CustomViewItem, req_options: Optional["CSVRequestOptions"] = None) -> None:
"""
Populate the CSV of a custom view.
Parameters
----------
custom_view_item : CustomViewItem
The custom view item to populate the CSV for.
req_options : CSVRequestOptions, optional
Options to customize the CSV returned, by default None
Returns
-------
None
Raises
------
MissingRequiredFieldError
If the custom view item is missing an ID
"""
if not custom_view_item.id:
error = "Custom View item missing ID."
raise MissingRequiredFieldError(error)
Expand All @@ -141,6 +230,21 @@ def _get_custom_view_csv(

@api(version="3.18")
def update(self, view_item: CustomViewItem) -> Optional[CustomViewItem]:
"""
Updates the name, owner, or shared status of a custom view.
Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#update_custom_view
Parameters
----------
view_item : CustomViewItem
The custom view item to update.
Returns
-------
Optional[CustomViewItem]
The updated custom view item.
"""
if not view_item.id:
error = "Custom view item missing ID."
raise MissingRequiredFieldError(error)
Expand All @@ -158,6 +262,25 @@ def update(self, view_item: CustomViewItem) -> Optional[CustomViewItem]:
# Delete 1 view by id
@api(version="3.19")
def delete(self, view_id: str) -> None:
"""
Deletes a single custom view by ID.
Rest API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#delete_custom_view
Parameters
----------
view_id : str
The ID of the custom view to delete.
Returns
-------
None
Raises
------
ValueError
If the view_id is not provided.
"""
if not view_id:
error = "Custom View ID undefined."
raise ValueError(error)
Expand All @@ -167,6 +290,27 @@ def delete(self, view_id: str) -> None:

@api(version="3.21")
def download(self, view_item: CustomViewItem, file: PathOrFileW) -> PathOrFileW:
"""
Download the definition of a custom view as json. The file parameter can
be a file path or a file object. If a file path is provided, the file
will be written to that location. If a file object is provided, the file
will be written to that object.
May contain sensitive information.
Parameters
----------
view_item : CustomViewItem
The custom view item to download.
file : PathOrFileW
The file path or file object to write the custom view to.
Returns
-------
PathOrFileW
The file path or file object that the custom view was written to.
"""
url = f"{self.expurl}/{view_item.id}/content"
server_response = self.get_request(url)
if isinstance(file, io_types_w):
Expand All @@ -180,6 +324,25 @@ def download(self, view_item: CustomViewItem, file: PathOrFileW) -> PathOrFileW:

@api(version="3.21")
def publish(self, view_item: CustomViewItem, file: PathOrFileR) -> Optional[CustomViewItem]:
"""
Publish a custom view to Tableau Server. The file parameter can be a
file path or a file object. If a file path is provided, the file will be
read from that location. If a file object is provided, the file will be
read from that object.
Parameters
----------
view_item : CustomViewItem
The custom view item to publish.
file : PathOrFileR
The file path or file object to read the custom view from.
Returns
-------
Optional[CustomViewItem]
The published custom view item.
"""
url = self.expurl
if isinstance(file, io_types_r):
size = get_file_object_size(file)
Expand Down Expand Up @@ -207,3 +370,25 @@ def publish(self, view_item: CustomViewItem, file: PathOrFileR) -> Optional[Cust

server_response = self.post_request(url, xml_request, content_type)
return CustomViewItem.from_response(server_response.content, self.parent_srv.namespace)

def filter(self, *invalid, page_size: Optional[int] = None, **kwargs) -> "QuerySet[CustomViewItem]":
"""
Queries the Tableau Server for items using the specified filters. Page
size can be specified to limit the number of items returned in a single
request. If not specified, the default page size is 100. Page size can
be an integer between 1 and 1000.
No positional arguments are allowed. All filters must be specified as
keyword arguments. If you use the equality operator, you can specify it
through <field_name>=<value>. If you want to use a different operator,
you can specify it through <field_name>__<operator>=<value>. Field
names can either be in snake_case or camelCase.
This endpoint supports the following fields and operators:
view_id=...
workbook_id=...
owner_id=...
"""

return super().filter(*invalid, page_size=page_size, **kwargs)
3 changes: 3 additions & 0 deletions tableauserverclient/server/request_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class Field:
NotificationType = "notificationType"
OwnerDomain = "ownerDomain"
OwnerEmail = "ownerEmail"
OwnerId = "ownerId"
OwnerName = "ownerName"
ParentProjectId = "parentProjectId"
Priority = "priority"
Expand All @@ -148,8 +149,10 @@ class Field:
UpdatedAt = "updatedAt"
UserCount = "userCount"
UserId = "userId"
ViewId = "viewId"
ViewUrlName = "viewUrlName"
WorkbookDescription = "workbookDescription"
WorkbookId = "workbookId"
WorkbookName = "workbookName"

class Direction:
Expand Down

0 comments on commit a4278e5

Please sign in to comment.