diff --git a/tableauserverclient/models/group_item.py b/tableauserverclient/models/group_item.py index 00f35e51..6dfce438 100644 --- a/tableauserverclient/models/group_item.py +++ b/tableauserverclient/models/group_item.py @@ -1,6 +1,7 @@ from typing import Callable, Optional, TYPE_CHECKING from defusedxml.ElementTree import fromstring +from typing_extensions import Self from .exceptions import UnpopulatedPropertyError from .property_decorators import property_not_empty, property_is_enum @@ -157,3 +158,8 @@ def from_response(cls, resp, ns) -> list["GroupItem"]: @staticmethod def as_reference(id_: str) -> ResourceReference: return ResourceReference(id_, GroupItem.tag_name) + + def to_reference(self: Self) -> ResourceReference: + if self.id is None: + raise ValueError("UserItem must have id to be converted to reference") + return ResourceReference(self.id, self.tag_name) diff --git a/tableauserverclient/models/groupset_item.py b/tableauserverclient/models/groupset_item.py index aa653a79..e586b266 100644 --- a/tableauserverclient/models/groupset_item.py +++ b/tableauserverclient/models/groupset_item.py @@ -2,6 +2,7 @@ import xml.etree.ElementTree as ET from defusedxml.ElementTree import fromstring +from typing_extensions import Self from tableauserverclient.models.group_item import GroupItem from tableauserverclient.models.reference_item import ResourceReference @@ -51,3 +52,8 @@ def get_group(group_xml: ET.Element) -> GroupItem: @staticmethod def as_reference(id_: str) -> ResourceReference: return ResourceReference(id_, GroupSetItem.tag_name) + + def to_reference(self: Self) -> ResourceReference: + if self.id is None: + raise ValueError("UserItem must have id to be converted to reference") + return ResourceReference(self.id, self.tag_name) diff --git a/tableauserverclient/models/reference_item.py b/tableauserverclient/models/reference_item.py index 4c1fff56..30536b4d 100644 --- a/tableauserverclient/models/reference_item.py +++ b/tableauserverclient/models/reference_item.py @@ -1,9 +1,12 @@ +from typing_extensions import Self + + class ResourceReference: - def __init__(self, id_, tag_name): + def __init__(self, id_: str | None, tag_name: str) -> None: self.id = id_ self.tag_name = tag_name - def __str__(self): + def __str__(self) -> str: return f"" __repr__ = __str__ @@ -13,18 +16,21 @@ def __eq__(self, other: object) -> bool: return False return (self.id == other.id) and (self.tag_name == other.tag_name) + def __hash__(self: Self) -> int: + return hash((self.id, self.tag_name)) + @property - def id(self): + def id(self) -> str | None: return self._id @id.setter - def id(self, value): + def id(self, value: str | None) -> None: self._id = value @property - def tag_name(self): + def tag_name(self) -> str: return self._tag_name @tag_name.setter - def tag_name(self, value): + def tag_name(self, value: str) -> None: self._tag_name = value diff --git a/tableauserverclient/models/user_item.py b/tableauserverclient/models/user_item.py index 8b2dd3dd..04ccf9ef 100644 --- a/tableauserverclient/models/user_item.py +++ b/tableauserverclient/models/user_item.py @@ -5,6 +5,7 @@ from typing import Optional, TYPE_CHECKING from defusedxml.ElementTree import fromstring +from typing_extensions import Self from tableauserverclient.datetime_helpers import parse_datetime from tableauserverclient.models.site_item import SiteAuthConfiguration @@ -377,6 +378,11 @@ def _parse_xml(cls, element_name, resp, ns): def as_reference(id_) -> ResourceReference: return ResourceReference(id_, UserItem.tag_name) + def to_reference(self: Self) -> ResourceReference: + if self.id is None: + raise ValueError("UserItem must have id to be converted to reference") + return ResourceReference(self.id, self.tag_name) + @staticmethod def _parse_element(user_xml, ns): id = user_xml.get("id", None) diff --git a/tableauserverclient/server/request_factory.py b/tableauserverclient/server/request_factory.py index 877a18c3..8445008d 100644 --- a/tableauserverclient/server/request_factory.py +++ b/tableauserverclient/server/request_factory.py @@ -512,7 +512,10 @@ def add_req(self, rules: Iterable[PermissionsRule]) -> bytes: for rule in rules: grantee_capabilities_element = ET.SubElement(permissions_element, "granteeCapabilities") grantee_element = ET.SubElement(grantee_capabilities_element, rule.grantee.tag_name) - grantee_element.attrib["id"] = rule.grantee.id + if rule.grantee.id is not None: + grantee_element.attrib["id"] = rule.grantee.id + else: + raise ValueError("Grantee must have an ID") capabilities_element = ET.SubElement(grantee_capabilities_element, "capabilities") self._add_all_capabilities(capabilities_element, rule.capabilities)