From 4676581465b2bdca8dae301004c144d00e553081 Mon Sep 17 00:00:00 2001 From: Jordan Woods <13803242+jorwoods@users.noreply.github.com> Date: Sat, 12 Oct 2024 23:08:37 -0500 Subject: [PATCH] docs: docstrings for group endpoint and item --- tableauserverclient/models/group_item.py | 40 +++ .../server/endpoint/groups_endpoint.py | 336 +++++++++++++++++- 2 files changed, 365 insertions(+), 11 deletions(-) diff --git a/tableauserverclient/models/group_item.py b/tableauserverclient/models/group_item.py index 6871f8b1..0afd5582 100644 --- a/tableauserverclient/models/group_item.py +++ b/tableauserverclient/models/group_item.py @@ -12,6 +12,46 @@ class GroupItem: + """ + The GroupItem class contains the attributes for the group resources on + Tableau Server. The GroupItem class defines the information you can request + or query from Tableau Server. The class members correspond to the attributes + of a server request or response payload. + + Parameters + ---------- + name: str + The name of the group. + + domain_name: str + The name of the Active Directory domain ("local" if local authentication is used). + + Properties + ---------- + users: Pager[UserItem] + The users in the group. Must be populated with a call to `populate_users()`. + + id: str + The unique identifier for the group. + + minimum_site_role: str + The minimum site role for users in the group. Use the `UserItem.Roles` enum. + Users in the group cannot have their site role set lower than this value. + + license_mode: str + The mode defining when to apply licenses for group members. When the + mode is onLogin, a license is granted for each group member when they + login to a site. When the mode is onSync, a license is granted for group + members each time the domain is synced. + + Examples + -------- + >>> # Create a new group item + >>> newgroup = TSC.GroupItem('My Group') + + + """ + tag_name: str = "group" class LicenseMode: diff --git a/tableauserverclient/server/endpoint/groups_endpoint.py b/tableauserverclient/server/endpoint/groups_endpoint.py index c512b011..4e9af407 100644 --- a/tableauserverclient/server/endpoint/groups_endpoint.py +++ b/tableauserverclient/server/endpoint/groups_endpoint.py @@ -8,7 +8,7 @@ from tableauserverclient.helpers.logging import logger -from typing import Optional, TYPE_CHECKING, Union +from typing import Literal, Optional, TYPE_CHECKING, Union, overload from collections.abc import Iterable from tableauserverclient.server.query import QuerySet @@ -18,13 +18,56 @@ class Groups(QuerysetEndpoint[GroupItem]): + """ + Groups endpoint for creating, reading, updating, and deleting groups on + Tableau Server. + """ + @property def baseurl(self) -> str: return f"{self.parent_srv.baseurl}/sites/{self.parent_srv.site_id}/groups" @api(version="2.0") def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[GroupItem], PaginationItem]: - """Gets all groups""" + """ + Returns information about the groups on the site. + + To get information about the users in a group, you must first populate + the GroupItem with user information using the groups.populate_users + method. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#query_groups + + Parameters + ---------- + req_options : Optional[RequestOptions] + (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 group, you could specify the name of + the group or the group id. + + Returns + ------- + tuple[list[GroupItem], PaginationItem] + + Examples + -------- + >>> # import tableauserverclient as TSC + >>> # tableau_auth = TSC.TableauAuth('USERNAME', 'PASSWORD') + >>> # server = TSC.Server('https://SERVERURL') + + >>> with server.auth.sign_in(tableau_auth): + + >>> # get the groups on the server + >>> all_groups, pagination_item = server.groups.get() + + >>> # print the names of the first 100 groups + >>> for group in all_groups : + >>> print(group.name, group.id) + + + + """ logger.info("Querying all groups on site") url = self.baseurl server_response = self.get_request(url, req_options) @@ -34,7 +77,42 @@ def get(self, req_options: Optional["RequestOptions"] = None) -> tuple[list[Grou @api(version="2.0") def populate_users(self, group_item: GroupItem, req_options: Optional["RequestOptions"] = None) -> None: - """Gets all users in a given group""" + """ + Populates the group_item with the list of users. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#get_users_in_group + + Parameters + ---------- + group_item : GroupItem + The group item to populate with user information. + + req_options : Optional[RequestOptions] + (Optional) You can pass the method a request object that contains + page size and page number. + + Returns + ------- + None + + Raises + ------ + MissingRequiredFieldError + If the group item does not have an ID, the method raises an error. + + Examples + -------- + >>> # Get the group item from the server + >>> groups, pagination_item = server.groups.get() + >>> group = groups[1] + + >>> # Populate the group with user information + >>> server.groups.populate_users(group) + >>> for user in group.users: + >>> print(user.name) + + + """ if not group_item.id: error = "Group item missing ID. Group must be retrieved from server first." raise MissingRequiredFieldError(error) @@ -61,7 +139,32 @@ def _get_users_for_group( @api(version="2.0") def delete(self, group_id: str) -> None: - """Deletes 1 group by id""" + """ + Deletes the group on the site. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#delete_group + + Parameters + ---------- + group_id: str + The id for the group you want to remove from the server + + Returns + ------- + None + + Raises + ------ + ValueError + If the group_id is not provided, the method raises an error. + + Examples + -------- + >>> groups, pagination_item = server.groups.get() + >>> group = groups[1] + >>> server.groups.delete(group.id) + + """ if not group_id: error = "Group ID undefined." raise ValueError(error) @@ -69,8 +172,42 @@ def delete(self, group_id: str) -> None: self.delete_request(url) logger.info(f"Deleted single group (ID: {group_id})") + @overload + def update(self, group_item: GroupItem, as_job: Literal[False]) -> GroupItem: ... + + @overload + def update(self, group_item: GroupItem, as_job: Literal[True]) -> JobItem: ... + @api(version="2.0") - def update(self, group_item: GroupItem, as_job: bool = False) -> Union[GroupItem, JobItem]: + def update(self, group_item, as_job=False): + """ + Updates a group on the site. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#update_group + + Parameters + ---------- + group_item : GroupItem + The group item to update. + + as_job : bool + (Optional) If this value is set to True, the update operation will + be asynchronous and return a JobItem. This is only supported for + Active Directory groups. By default, this value is set to False. + + Returns + ------- + Union[GroupItem, JobItem] + + Raises + ------ + MissingRequiredFieldError + If the group_item does not have an ID, the method raises an error. + + ValueError + If the group_item is a local group and as_job is set to True, the + method raises an error. + """ url = f"{self.baseurl}/{group_item.id}" if not group_item.id: @@ -92,15 +229,71 @@ def update(self, group_item: GroupItem, as_job: bool = False) -> Union[GroupItem @api(version="2.0") def create(self, group_item: GroupItem) -> GroupItem: - """Create a 'local' Tableau group""" + """ + Create a 'local' Tableau group + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#create_group + + Parameters + ---------- + group_item : GroupItem + The group item to create. The group_item specifies the group to add. + You first create a new instance of a GroupItem and pass that to this + method. + + Returns + ------- + GroupItem + + Examples + -------- + >>> new_group = TSC.GroupItem('new_group') + >>> new_group.minimum_site_role = TSC.UserItem.Role.ExplorerCanPublish + >>> new_group = server.groups.create(new_group) + + """ url = self.baseurl create_req = RequestFactory.Group.create_local_req(group_item) server_response = self.post_request(url, create_req) return GroupItem.from_response(server_response.content, self.parent_srv.namespace)[0] + @overload + def create_AD_group(self, group_item: GroupItem, asJob: Literal[False]) -> GroupItem: ... + + @overload + def create_AD_group(self, group_item: GroupItem, asJob: Literal[True]) -> JobItem: ... + @api(version="2.0") - def create_AD_group(self, group_item: GroupItem, asJob: bool = False) -> Union[GroupItem, JobItem]: - """Create a group based on Active Directory""" + def create_AD_group(self, group_item, asJob=False): + """ + Create a group based on Active Directory. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#create_group + + Parameters + ---------- + group_item : GroupItem + The group item to create. The group_item specifies the group to add. + You first create a new instance of a GroupItem and pass that to this + method. + + asJob : bool + (Optional) If this value is set to True, the create operation will + be asynchronous and return a JobItem. This is only supported for + Active Directory groups. By default, this value is set to False. + + Returns + ------- + Union[GroupItem, JobItem] + + Examples + -------- + >>> new_ad_group = TSC.GroupItem('new_ad_group') + >>> new_ad_group.domain_name = 'example.com' + >>> new_ad_group.minimum_site_role = TSC.UserItem.Role.ExplorerCanPublish + >>> new_ad_group.license_mode = TSC.GroupItem.LicenseMode.onSync + >>> new_ad_group = server.groups.create_AD_group(new_ad_group) + """ asJobparameter = "?asJob=true" if asJob else "" url = self.baseurl + asJobparameter create_req = RequestFactory.Group.create_ad_req(group_item) @@ -112,7 +305,37 @@ def create_AD_group(self, group_item: GroupItem, asJob: bool = False) -> Union[G @api(version="2.0") def remove_user(self, group_item: GroupItem, user_id: str) -> None: - """Removes 1 user from 1 group""" + """ + Removes 1 user from 1 group + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#remove_user_to_group + + Parameters + ---------- + group_item : GroupItem + The group item from which to remove the user. + + user_id : str + The ID of the user to remove from the group. + + Returns + ------- + None + + Raises + ------ + MissingRequiredFieldError + If the group_item does not have an ID, the method raises an error. + + ValueError + If the user_id is not provided, the method raises an error. + + Examples + -------- + >>> group = server.groups.get_by_id('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p') + >>> server.groups.populate_users(group) + >>> server.groups.remove_user(group, group.users[0].id) + """ if not group_item.id: error = "Group item missing ID." raise MissingRequiredFieldError(error) @@ -125,7 +348,37 @@ def remove_user(self, group_item: GroupItem, user_id: str) -> None: @api(version="3.21") def remove_users(self, group_item: GroupItem, users: Iterable[Union[str, UserItem]]) -> None: - """Removes multiple users from 1 group""" + """ + Removes multiple users from 1 group. This makes a single API call to + remove the provided users. + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#remove_users_to_group + + Parameters + ---------- + group_item : GroupItem + The group item from which to remove the user. + + users : Iterable[Union[str, UserItem]] + The IDs or UserItems with IDs of the users to remove from the group. + + Returns + ------- + None + + Raises + ------ + ValueError + If the group_item is not a GroupItem or str, the method raises an error. + + Examples + -------- + >>> group = server.groups.get_by_id('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p') + >>> server.groups.populate_users(group) + >>> users = [u for u in group.users if u.domain_name == 'example.com'] + >>> server.groups.remove_users(group, users) + + """ group_id = group_item.id if hasattr(group_item, "id") else group_item if not isinstance(group_id, str): raise ValueError(f"Invalid group provided: {group_item}") @@ -138,7 +391,37 @@ def remove_users(self, group_item: GroupItem, users: Iterable[Union[str, UserIte @api(version="2.0") def add_user(self, group_item: GroupItem, user_id: str) -> UserItem: - """Adds 1 user to 1 group""" + """ + Adds 1 user to 1 group + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#add_user_to_group + + Parameters + ---------- + group_item : GroupItem + The group item to which to add the user. + + user_id : str + The ID of the user to add to the group. + + Returns + ------- + UserItem + UserItem for the user that was added to the group. + + Raises + ------ + MissingRequiredFieldError + If the group_item does not have an ID, the method raises an error. + + ValueError + If the user_id is not provided, the method raises an error. + + Examples + -------- + >>> group = server.groups.get_by_id('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p') + >>> server.groups.add_user(group, '1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p') + """ if not group_item.id: error = "Group item missing ID." raise MissingRequiredFieldError(error) @@ -154,6 +437,37 @@ def add_user(self, group_item: GroupItem, user_id: str) -> UserItem: @api(version="3.21") def add_users(self, group_item: GroupItem, users: Iterable[Union[str, UserItem]]) -> list[UserItem]: + """ + Adds 1 or more user to 1 group + + REST API: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_users_and_groups.htm#add_user_to_group + + Parameters + ---------- + group_item : GroupItem + The group item to which to add the user. + + user_id : Iterable[Union[str, UserItem]] + User IDs or UserItems with IDs to add to the group. + + Returns + ------- + list[UserItem] + UserItem for the user that was added to the group. + + Raises + ------ + MissingRequiredFieldError + If the group_item does not have an ID, the method raises an error. + + ValueError + If the user_id is not provided, the method raises an error. + + Examples + -------- + >>> group = server.groups.get_by_id('1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p') + >>> added_users = server.groups.add_users(group, '1a2b3c4d-5e6f-7g8h-9i0j-1k2l3m4n5o6p') + """ """Adds multiple users to 1 group""" group_id = group_item.id if hasattr(group_item, "id") else group_item if not isinstance(group_id, str):