From 41b96a52785455ad3bbfe7ef7ec513f893820ec9 Mon Sep 17 00:00:00 2001 From: Jordan Woods <13803242+jorwoods@users.noreply.github.com> Date: Fri, 11 Oct 2024 22:31:18 -0500 Subject: [PATCH 1/4] docs: docstrings for filter tooling --- tableauserverclient/server/pager.py | 42 ++++++ tableauserverclient/server/request_options.py | 137 +++++++++++++++++- 2 files changed, 177 insertions(+), 2 deletions(-) diff --git a/tableauserverclient/server/pager.py b/tableauserverclient/server/pager.py index e6d261b6..2c05394e 100644 --- a/tableauserverclient/server/pager.py +++ b/tableauserverclient/server/pager.py @@ -27,6 +27,48 @@ class Pager(Iterable[T]): (users in a group, views in a workbook, etc) by passing a different endpoint. Will loop over anything that returns (list[ModelItem], PaginationItem). + + Will make a copy of the `RequestOptions` object passed in so it can be reused. + + Makes a call to the Server for each page of items, then yields each item in the list. + + Parameters + ---------- + endpoint: CallableEndpoint[T] or Endpoint[T] + The endpoint to call to get the items. Can be a callable or an Endpoint object. + Expects a tuple of (list[T], PaginationItem) to be returned. + + request_opts: RequestOptions, optional + The request options to pass to the endpoint. If not provided, will use default RequestOptions. + Filters, sorts, page size, starting page number, etc can be set here. + + Yields + ------ + T + The items returned from the endpoint. + + Raises + ------ + ValueError + If the endpoint is not a callable or an Endpoint object. + + Examples + -------- + >>> # Loop over all workbooks on the site + >>> for workbook in TSC.Pager(server.workbooks): + >>> print(workbook.name) + + >>> # Setting page size + >>> request_options = TSC.RequestOptions(pagesize=1000) + >>> all_workbooks = list(TSC.Pager(server.workbooks, request_options)) + + >>> # Starting on page 2 + >>> request_options = TSC.RequestOptions(pagenumber=2) + >>> for workbook in TSC.Pager(server.workbooks, request_options): + >>> print(workbook.name) + + >>> # Using in a list comprehension + >>> views = [view for view in TSC.Pager(workbook.views) if "sales" in view.name.lower()] """ def __init__( diff --git a/tableauserverclient/server/request_options.py b/tableauserverclient/server/request_options.py index d79ac7f7..9f4342b9 100644 --- a/tableauserverclient/server/request_options.py +++ b/tableauserverclient/server/request_options.py @@ -35,6 +35,44 @@ def apply_query_params(self, url): class RequestOptions(RequestOptionsBase): + """ + This class is used to manage the options that can be used when querying content on the server. + Optionally initialize with a page number and page size to control the number of items returned. + + Additionally, you can add sorting and filtering options to the request. + + The `sort` and `filter` options are set-like objects, so you can only add a field once. If you add the same field + multiple times, only the last one will be used. + + The list of fields that can be sorted on or filtered by can be found in the `Field` + class contained within this class. + + Parameters + ---------- + pagenumber: int, optional + The page number to start the query on. Default is 1. + + pagesize: int, optional + The number of items to return per page. Default is 100. Can also read + from the environment variable `TSC_PAGE_SIZE` + + Examples + -------- + >>> # Get the first 50 workbooks on the site + >>> request_options = TSC.RequestOptions(pagesize=50) + + >>> # Get the next 50 workbooks on the site + >>> request_options.page_number(2) + + >>> # Get the first 50 workbooks on the site, sorted by name + >>> request_options = TSC.RequestOptions(pagesize=50) + >>> request_options.sort.add(TSC.Sort(TSC.RequestOptions.Field.Name, TSC.Sort.Direction.Asc)) + + >>> # Get the first 50 workbooks on the site, filtered by a tag + >>> request_options = TSC.RequestOptions(pagesize=50) + >>> request_options.filter.add(TSC.Filter(TSC.RequestOptions.Field.Tags, TSC.Filter.Operator.Equals, "important")) + + """ def __init__(self, pagenumber=1, pagesize=None): self.pagenumber = pagenumber self.pagesize = pagesize or config.PAGE_SIZE @@ -196,13 +234,43 @@ def get_query_params(self): def vf(self, name: str, value: str) -> Self: """Apply a filter based on a column within the view. - Note that when filtering on a boolean type field, the only valid values are 'true' and 'false'""" + Note that when filtering on a boolean type field, the only valid values are 'true' and 'false' + + For more detail see: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_filtering_and_sorting.htm#Filter-query-views + + Parameters + ---------- + name: str + The name of the column to filter on + + value: str + The value to filter on + + Returns + ------- + Self + The current object + """ self.view_filters.append((name, value)) return self def parameter(self, name: str, value: str) -> Self: """Apply a filter based on a parameter within the workbook. - Note that when filtering on a boolean type field, the only valid values are 'true' and 'false'""" + Note that when filtering on a boolean type field, the only valid values are 'true' and 'false' + + Parameters + ---------- + name: str + The name of the parameter to filter on + + value: str + The value to filter on + + Returns + ------- + Self + The current object + """ self.view_parameters.append((name, value)) return self @@ -254,14 +322,57 @@ def get_query_params(self) -> dict: class CSVRequestOptions(_DataExportOptions): + """ + Options that can be used when exporting a view to CSV. Set the maxage to control the age of the data exported. + Filters to the underlying data can be applied using the `vf` and `parameter` methods. + + Parameters + ---------- + maxage: int, optional + The maximum age of the data to export. Shortest possible duration is 1 + minute. No upper limit. Default is -1, which means no limit. + """ extension = "csv" class ExcelRequestOptions(_DataExportOptions): + """ + Options that can be used when exporting a view to Excel. Set the maxage to control the age of the data exported. + Filters to the underlying data can be applied using the `vf` and `parameter` methods. + + Parameters + ---------- + maxage: int, optional + The maximum age of the data to export. Shortest possible duration is 1 + minute. No upper limit. Default is -1, which means no limit. + """ extension = "xlsx" class ImageRequestOptions(_ImagePDFCommonExportOptions): + """ + Options that can be used when exporting a view to an image. Set the maxage to control the age of the data exported. + Filters to the underlying data can be applied using the `vf` and `parameter` methods. + + Parameters + ---------- + imageresolution: str, optional + The resolution of the image to export. Valid values are "high" or None. Default is None. + Image width and actual pixel density are determined by the display context + of the image. Aspect ratio is always preserved. Set the value to "high" to + ensure maximum pixel density. + + maxage: int, optional + The maximum age of the data to export. Shortest possible duration is 1 + minute. No upper limit. Default is -1, which means no limit. + + viz_height: int, optional + The height of the viz in pixels. If specified, viz_width must also be specified. + + viz_width: int, optional + The width of the viz in pixels. If specified, viz_height must also be specified. + + """ extension = "png" # if 'high' isn't specified, the REST API endpoint returns an image with standard resolution @@ -280,6 +391,28 @@ def get_query_params(self): class PDFRequestOptions(_ImagePDFCommonExportOptions): + """ + Options that can be used when exporting a view to PDF. Set the maxage to control the age of the data exported. + Filters to the underlying data can be applied using the `vf` and `parameter` methods. + + Parameters + ---------- + page_type: str, optional + The page type of the PDF to export. Valid values are accessible via the `PageType` class. + + orientation: str, optional + The orientation of the PDF to export. Valid values are accessible via the `Orientation` class. + + maxage: int, optional + The maximum age of the data to export. Shortest possible duration is 1 + minute. No upper limit. Default is -1, which means no limit. + + viz_height: int, optional + The height of the viz in pixels. If specified, viz_width must also be specified. + + viz_width: int, optional + The width of the viz in pixels. If specified, viz_height must also be specified. + """ class PageType: A3 = "a3" A4 = "a4" From 41f987b0a26814bb05ff3d3529393ede4fa57771 Mon Sep 17 00:00:00 2001 From: Jordan Woods <13803242+jorwoods@users.noreply.github.com> Date: Sat, 12 Oct 2024 08:44:03 -0500 Subject: [PATCH 2/4] docs: docstring for Sort --- tableauserverclient/server/sort.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tableauserverclient/server/sort.py b/tableauserverclient/server/sort.py index 839a8c8d..2f692841 100644 --- a/tableauserverclient/server/sort.py +++ b/tableauserverclient/server/sort.py @@ -1,4 +1,31 @@ class Sort: + """ + Used with request options (RequestOptions) where you can filter and sort on + the results returned from the server. + + Parameters + ---------- + field : str + Sets the field to sort on. The fields are defined in the RequestOption class. + + direction : str + The direction to sort, either ascending (Asc) or descending (Desc). The + options are defined in the RequestOptions.Direction class. + + Examples + -------- + + >>> # create a new instance of a request option object + >>> req_option = TSC.RequestOptions() + + >>> # add the sort expression, sorting by name and direction + >>> req_option.sort.add(TSC.Sort(TSC.RequestOptions.Field.Name, + TSC.RequestOptions.Direction.Asc)) + >>> matching_workbooks, pagination_item = server.workbooks.get(req_option) + + >>> for wb in matching_workbooks: + >>> print(wb.name) + """ def __init__(self, field, direction): self.field = field self.direction = direction From a2198b93a870765cbee0e549db39a171e3b5fbf8 Mon Sep 17 00:00:00 2001 From: Jordan Woods <13803242+jorwoods@users.noreply.github.com> Date: Sat, 12 Oct 2024 08:44:52 -0500 Subject: [PATCH 3/4] style: black --- tableauserverclient/server/request_options.py | 29 +++++++++++-------- tableauserverclient/server/sort.py | 3 +- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/tableauserverclient/server/request_options.py b/tableauserverclient/server/request_options.py index 9f4342b9..29b06d01 100644 --- a/tableauserverclient/server/request_options.py +++ b/tableauserverclient/server/request_options.py @@ -73,6 +73,7 @@ class contained within this class. >>> request_options.filter.add(TSC.Filter(TSC.RequestOptions.Field.Tags, TSC.Filter.Operator.Equals, "important")) """ + def __init__(self, pagenumber=1, pagesize=None): self.pagenumber = pagenumber self.pagesize = pagesize or config.PAGE_SIZE @@ -325,13 +326,14 @@ class CSVRequestOptions(_DataExportOptions): """ Options that can be used when exporting a view to CSV. Set the maxage to control the age of the data exported. Filters to the underlying data can be applied using the `vf` and `parameter` methods. - + Parameters ---------- maxage: int, optional The maximum age of the data to export. Shortest possible duration is 1 minute. No upper limit. Default is -1, which means no limit. """ + extension = "csv" @@ -339,13 +341,14 @@ class ExcelRequestOptions(_DataExportOptions): """ Options that can be used when exporting a view to Excel. Set the maxage to control the age of the data exported. Filters to the underlying data can be applied using the `vf` and `parameter` methods. - + Parameters ---------- maxage: int, optional The maximum age of the data to export. Shortest possible duration is 1 minute. No upper limit. Default is -1, which means no limit. """ + extension = "xlsx" @@ -353,7 +356,7 @@ class ImageRequestOptions(_ImagePDFCommonExportOptions): """ Options that can be used when exporting a view to an image. Set the maxage to control the age of the data exported. Filters to the underlying data can be applied using the `vf` and `parameter` methods. - + Parameters ---------- imageresolution: str, optional @@ -361,18 +364,19 @@ class ImageRequestOptions(_ImagePDFCommonExportOptions): Image width and actual pixel density are determined by the display context of the image. Aspect ratio is always preserved. Set the value to "high" to ensure maximum pixel density. - + maxage: int, optional The maximum age of the data to export. Shortest possible duration is 1 minute. No upper limit. Default is -1, which means no limit. - + viz_height: int, optional The height of the viz in pixels. If specified, viz_width must also be specified. - + viz_width: int, optional The width of the viz in pixels. If specified, viz_height must also be specified. - + """ + extension = "png" # if 'high' isn't specified, the REST API endpoint returns an image with standard resolution @@ -394,25 +398,26 @@ class PDFRequestOptions(_ImagePDFCommonExportOptions): """ Options that can be used when exporting a view to PDF. Set the maxage to control the age of the data exported. Filters to the underlying data can be applied using the `vf` and `parameter` methods. - + Parameters ---------- page_type: str, optional The page type of the PDF to export. Valid values are accessible via the `PageType` class. - + orientation: str, optional The orientation of the PDF to export. Valid values are accessible via the `Orientation` class. - + maxage: int, optional The maximum age of the data to export. Shortest possible duration is 1 minute. No upper limit. Default is -1, which means no limit. - + viz_height: int, optional The height of the viz in pixels. If specified, viz_width must also be specified. - + viz_width: int, optional The width of the viz in pixels. If specified, viz_height must also be specified. """ + class PageType: A3 = "a3" A4 = "a4" diff --git a/tableauserverclient/server/sort.py b/tableauserverclient/server/sort.py index 2f692841..014ed81f 100644 --- a/tableauserverclient/server/sort.py +++ b/tableauserverclient/server/sort.py @@ -14,7 +14,7 @@ class Sort: Examples -------- - + >>> # create a new instance of a request option object >>> req_option = TSC.RequestOptions() @@ -26,6 +26,7 @@ class Sort: >>> for wb in matching_workbooks: >>> print(wb.name) """ + def __init__(self, field, direction): self.field = field self.direction = direction From 194dd64d27f09ede9ed43bdc4321161826df3a1f Mon Sep 17 00:00:00 2001 From: Jordan Woods <13803242+jorwoods@users.noreply.github.com> Date: Tue, 15 Oct 2024 21:03:08 -0500 Subject: [PATCH 4/4] chore: remove examples --- tableauserverclient/server/pager.py | 18 ------------------ tableauserverclient/server/request_options.py | 17 ----------------- tableauserverclient/server/sort.py | 14 -------------- 3 files changed, 49 deletions(-) diff --git a/tableauserverclient/server/pager.py b/tableauserverclient/server/pager.py index 2c05394e..3c7e60f7 100644 --- a/tableauserverclient/server/pager.py +++ b/tableauserverclient/server/pager.py @@ -51,24 +51,6 @@ class Pager(Iterable[T]): ------ ValueError If the endpoint is not a callable or an Endpoint object. - - Examples - -------- - >>> # Loop over all workbooks on the site - >>> for workbook in TSC.Pager(server.workbooks): - >>> print(workbook.name) - - >>> # Setting page size - >>> request_options = TSC.RequestOptions(pagesize=1000) - >>> all_workbooks = list(TSC.Pager(server.workbooks, request_options)) - - >>> # Starting on page 2 - >>> request_options = TSC.RequestOptions(pagenumber=2) - >>> for workbook in TSC.Pager(server.workbooks, request_options): - >>> print(workbook.name) - - >>> # Using in a list comprehension - >>> views = [view for view in TSC.Pager(workbook.views) if "sales" in view.name.lower()] """ def __init__( diff --git a/tableauserverclient/server/request_options.py b/tableauserverclient/server/request_options.py index 29b06d01..fca9a3a3 100644 --- a/tableauserverclient/server/request_options.py +++ b/tableauserverclient/server/request_options.py @@ -55,23 +55,6 @@ class contained within this class. pagesize: int, optional The number of items to return per page. Default is 100. Can also read from the environment variable `TSC_PAGE_SIZE` - - Examples - -------- - >>> # Get the first 50 workbooks on the site - >>> request_options = TSC.RequestOptions(pagesize=50) - - >>> # Get the next 50 workbooks on the site - >>> request_options.page_number(2) - - >>> # Get the first 50 workbooks on the site, sorted by name - >>> request_options = TSC.RequestOptions(pagesize=50) - >>> request_options.sort.add(TSC.Sort(TSC.RequestOptions.Field.Name, TSC.Sort.Direction.Asc)) - - >>> # Get the first 50 workbooks on the site, filtered by a tag - >>> request_options = TSC.RequestOptions(pagesize=50) - >>> request_options.filter.add(TSC.Filter(TSC.RequestOptions.Field.Tags, TSC.Filter.Operator.Equals, "important")) - """ def __init__(self, pagenumber=1, pagesize=None): diff --git a/tableauserverclient/server/sort.py b/tableauserverclient/server/sort.py index 014ed81f..b7864592 100644 --- a/tableauserverclient/server/sort.py +++ b/tableauserverclient/server/sort.py @@ -11,20 +11,6 @@ class Sort: direction : str The direction to sort, either ascending (Asc) or descending (Desc). The options are defined in the RequestOptions.Direction class. - - Examples - -------- - - >>> # create a new instance of a request option object - >>> req_option = TSC.RequestOptions() - - >>> # add the sort expression, sorting by name and direction - >>> req_option.sort.add(TSC.Sort(TSC.RequestOptions.Field.Name, - TSC.RequestOptions.Direction.Asc)) - >>> matching_workbooks, pagination_item = server.workbooks.get(req_option) - - >>> for wb in matching_workbooks: - >>> print(wb.name) """ def __init__(self, field, direction):