1- import logging
21import xml .etree .ElementTree as ET
3- from typing import Optional
2+ from typing import Optional , overload
43
54from defusedxml .ElementTree import fromstring
65
76from tableauserverclient .models .exceptions import UnpopulatedPropertyError
8- from tableauserverclient .models .property_decorators import property_is_enum , property_not_empty
7+ from tableauserverclient .models .property_decorators import property_is_enum
98
109
1110class ProjectItem :
@@ -75,6 +74,8 @@ def __init__(
7574 self .parent_id : Optional [str ] = parent_id
7675 self ._samples : Optional [bool ] = samples
7776 self ._owner_id : Optional [str ] = None
77+ self ._top_level_project : Optional [bool ] = None
78+ self ._writeable : Optional [bool ] = None
7879
7980 self ._permissions = None
8081 self ._default_workbook_permissions = None
@@ -87,6 +88,11 @@ def __init__(
8788 self ._default_database_permissions = None
8889 self ._default_table_permissions = None
8990
91+ self ._project_count : Optional [int ] = None
92+ self ._workbok_count : Optional [int ] = None
93+ self ._view_count : Optional [int ] = None
94+ self ._datasource_count : Optional [int ] = None
95+
9096 @property
9197 def content_permissions (self ):
9298 return self ._content_permissions
@@ -176,25 +182,48 @@ def owner_id(self) -> Optional[str]:
176182 def owner_id (self , value : str ) -> None :
177183 self ._owner_id = value
178184
185+ @property
186+ def top_level_project (self ) -> Optional [bool ]:
187+ return self ._top_level_project
188+
189+ @property
190+ def writeable (self ) -> Optional [bool ]:
191+ return self ._writeable
192+
193+ @property
194+ def project_count (self ) -> Optional [int ]:
195+ return self ._project_count
196+
197+ @property
198+ def workbok_count (self ) -> Optional [int ]:
199+ return self ._workbok_count
200+
201+ @property
202+ def view_count (self ) -> Optional [int ]:
203+ return self ._view_count
204+
205+ @property
206+ def datasource_count (self ) -> Optional [int ]:
207+ return self ._datasource_count
208+
179209 def is_default (self ):
180210 return self .name .lower () == "default"
181211
182- def _parse_common_tags (self , project_xml , ns ):
183- if not isinstance (project_xml , ET .Element ):
184- project_xml = fromstring (project_xml ).find (".//t:project" , namespaces = ns )
185-
186- if project_xml is not None :
187- (
188- _ ,
189- name ,
190- description ,
191- content_permissions ,
192- parent_id ,
193- ) = self ._parse_element (project_xml )
194- self ._set_values (None , name , description , content_permissions , parent_id )
195- return self
196-
197- def _set_values (self , project_id , name , description , content_permissions , parent_id , owner_id ):
212+ def _set_values (
213+ self ,
214+ project_id ,
215+ name ,
216+ description ,
217+ content_permissions ,
218+ parent_id ,
219+ owner_id ,
220+ top_level_project ,
221+ writeable ,
222+ project_count ,
223+ workbok_count ,
224+ view_count ,
225+ datasource_count ,
226+ ):
198227 if project_id is not None :
199228 self ._id = project_id
200229 if name :
@@ -207,6 +236,18 @@ def _set_values(self, project_id, name, description, content_permissions, parent
207236 self .parent_id = parent_id
208237 if owner_id :
209238 self ._owner_id = owner_id
239+ if project_count is not None :
240+ self ._project_count = project_count
241+ if workbok_count is not None :
242+ self ._workbok_count = workbok_count
243+ if view_count is not None :
244+ self ._view_count = view_count
245+ if datasource_count is not None :
246+ self ._datasource_count = datasource_count
247+ if top_level_project is not None :
248+ self ._top_level_project = top_level_project
249+ if writeable is not None :
250+ self ._writeable = writeable
210251
211252 def _set_permissions (self , permissions ):
212253 self ._permissions = permissions
@@ -220,31 +261,68 @@ def _set_default_permissions(self, permissions, content_type):
220261 )
221262
222263 @classmethod
223- def from_response (cls , resp , ns ) -> list ["ProjectItem" ]:
264+ def from_response (cls , resp : bytes , ns : Optional [ dict ] ) -> list ["ProjectItem" ]:
224265 all_project_items = list ()
225266 parsed_response = fromstring (resp )
226267 all_project_xml = parsed_response .findall (".//t:project" , namespaces = ns )
227268
228269 for project_xml in all_project_xml :
229- project_item = cls .from_xml (project_xml )
270+ project_item = cls .from_xml (project_xml , namespace = ns )
230271 all_project_items .append (project_item )
231272 return all_project_items
232273
233274 @classmethod
234- def from_xml (cls , project_xml , namespace = None ) -> "ProjectItem" :
275+ def from_xml (cls , project_xml : ET . Element , namespace : Optional [ dict ] = None ) -> "ProjectItem" :
235276 project_item = cls ()
236- project_item ._set_values (* cls ._parse_element (project_xml ))
277+ project_item ._set_values (* cls ._parse_element (project_xml , namespace ))
237278 return project_item
238279
239280 @staticmethod
240- def _parse_element (project_xml ) :
281+ def _parse_element (project_xml : ET . Element , namespace : Optional [ dict ]) -> tuple :
241282 id = project_xml .get ("id" , None )
242283 name = project_xml .get ("name" , None )
243284 description = project_xml .get ("description" , None )
244285 content_permissions = project_xml .get ("contentPermissions" , None )
245286 parent_id = project_xml .get ("parentProjectId" , None )
287+ top_level_project = str_to_bool (project_xml .get ("topLevelProject" , None ))
288+ writeable = str_to_bool (project_xml .get ("writeable" , None ))
246289 owner_id = None
247- for owner in project_xml :
248- owner_id = owner .get ("id" , None )
290+ if (owner_elem := project_xml .find (".//t:owner" , namespaces = namespace )) is not None :
291+ owner_id = owner_elem .get ("id" , None )
292+
293+ project_count = None
294+ workbok_count = None
295+ view_count = None
296+ datasource_count = None
297+ if (count_elem := project_xml .find (".//t:contentsCounts" , namespaces = namespace )) is not None :
298+ project_count = int (count_elem .get ("projectCount" , 0 ))
299+ workbok_count = int (count_elem .get ("workbookCount" , 0 ))
300+ view_count = int (count_elem .get ("viewCount" , 0 ))
301+ datasource_count = int (count_elem .get ("dataSourceCount" , 0 ))
302+
303+ return (
304+ id ,
305+ name ,
306+ description ,
307+ content_permissions ,
308+ parent_id ,
309+ owner_id ,
310+ top_level_project ,
311+ writeable ,
312+ project_count ,
313+ workbok_count ,
314+ view_count ,
315+ datasource_count ,
316+ )
317+
318+
319+ @overload
320+ def str_to_bool (value : str ) -> bool : ...
321+
322+
323+ @overload
324+ def str_to_bool (value : None ) -> None : ...
325+
249326
250- return id , name , description , content_permissions , parent_id , owner_id
327+ def str_to_bool (value ):
328+ return value .lower () == "true" if value is not None else None
0 commit comments