8000 Prep Flow Support (#494) · rspinder/server-client-python@fa6d444 · GitHub
[go: up one dir, main page]

Skip to content

Commit fa6d444

Browse files
authored
Prep Flow Support (tableau#494)
Add support for Prep Flows on Server.
1 parent f3cf843 commit fa6d444

File tree

13 files changed

+602
-4
lines changed

13 files changed

+602
-4
lines changed

tableauserverclient/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
GroupItem, JobItem, BackgroundJobItem, PaginationItem, ProjectItem, ScheduleItem,\
44
SiteItem, TableauAuth, PersonalAccessTokenAuth, UserItem, ViewItem, WorkbookItem, UnpopulatedPropertyError,\
55
HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval, IntervalItem, TaskItem,\
6-
SubscriptionItem, Target, PermissionsRule, Permission, DatabaseItem, TableItem, ColumnItem
6+
SubscriptionItem, Target, PermissionsRule, Permission, DatabaseItem, TableItem, ColumnItem, FlowItem
77
from .server import RequestOptions, CSVRequestOptions, ImageRequestOptions, PDFRequestOptions, Filter, Sort, \
88
Server, ServerResponseError, MissingRequiredFieldError, NotSignedInError, Pager
99
from ._version import get_versions

tableauserverclient/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from .database_item import DatabaseItem
66
from .exceptions import UnpopulatedPropertyError
77
from .group_item import GroupItem
8+
from .flow_item import FlowItem
89
from .interval_item import IntervalItem, DailyInterval, WeeklyInterval, MonthlyInterval, HourlyInterval
910
from .job_item import JobItem, BackgroundJobItem
1011
from .pagination_item import PaginationItem
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import xml.etree.ElementTree as ET
2+
from .exceptions import UnpopulatedPropertyError
3+
from .property_decorators import property_not_nullable, property_is_boolean
4+
from .tag_item import TagItem
5+
from ..datetime_helpers import parse_datetime
6+
import copy
7+
8+
9+
class FlowItem(object):
10+
def __init__(self, project_id, name=None):
11+
self._webpage_url = None
12+
self._created_at = None
13+
self._id = None
14+
self._initial_tags = set()
15+
self._project_name = None
16+
self._updated_at = None
17+
self.name = name
18+
self.owner_id = None
19+
self.project_id = project_id
20+
self.tags = set()
21+
self.description = None
22+
23+
self._connections = None
24+
self._permissions = None
25+
26+
@property
27+
def connections(self):
28+
if self._connections is None:
29+
error = 'Flow item must be populated with connections first.'
30+
raise UnpopulatedPropertyError(error)
31+
return self._connections()
32+
33+
@property
34+
def permissions(self):
35+
if self._permissions is None:
36+
error = "Project item must be populated with permissions first."
37+
raise UnpopulatedPropertyError(error)
38+
return self._permissions()
39+
40+
@property
41+
def webpage_url(self):
42+
return self._webpage_url
43+
44+
@property
45+
def created_at(self):
46+
return self._created_at
47+
48+
@property
49+
def id(self):
50+
return self._id
51+
52+
@property
53+
def project_id(self):
54+
return self._project_id
55+
56+
@project_id.setter
57+
@property_not_nullable
58+
def project_id(self, value):
59+
self._project_id = value
60+
61+
@property
62+
def description(self):
63+
return self._description
64+
65+
@description.setter
66+
def description(self, value):
67+
self._description = value
68+
69+
@property
70+
def project_name(self):
71+
return self._project_name
72+
73+
@property
74+
def flow_type(self):
75+
return self._flow_type
76+
77+
@property
78+
def updated_at(self):
79+
return self._updated_at
80+
81+
def _set_connections(self, connections):
82+
self._connections = connections
83+
84+
def _set_permissions(self, permissions):
85+
self._permissions = permissions
86+
87+
def _parse_common_elements(self, flow_xml, ns):
88+
if not isinstance(flow_xml, ET.Element):
89+
flow_xml = ET.fromstring(flow_xml).find('.//t:flow', namespaces=ns)
90+
if flow_xml is not None:
91+
(_, _, _, _, _, updated_at, _, project_id, project_name, owner_id) = self._parse_element(flow_xml, ns)
92+
self._set_values(None, None, None, None, None, updated_at, None, project_id,
93+
project_name, owner_id)
94+
return self
95+
96+
def _set_values(self, id, name, description, webpage_url, created_at,
97+
updated_at, tags, project_id, project_name, owner_id):
98+
if id is not None:
99+
self._id = id
100+
if name:
101+
self.name = name
102+
if description:
103+
self.description = description
104+
if webpage_url:
105+
self._webpage_url = webpage_url
106+
if created_at:
107+
self._created_at = created_at
108+
if updated_at:
109+
self._updated_at = updated_at
110+
if tags:
111+
self.tags = tags
112+
self._initial_tags = copy.copy(tags)
113+
if project_id:
114+
self.project_id = project_id
115+
if project_name:
116+
self._project_name = project_name
117+
if owner_id:
118+
self.owner_id = owner_id
119+
120+
@classmethod
121+
def from_response(cls, resp, ns):
122+
all_flow_items = list()
123+
parsed_response = ET.fromstring(resp)
124+
all_flow_xml = parsed_response.findall('.//t:flow', namespaces=ns)
125+
126+
for flow_xml in all_flow_xml:
127+
(id_, name, description, webpage_url, created_at, updated_at,
128+
tags, project_id, project_name, owner_id) = cls._parse_element(flow_xml, ns)
129+
flow_item = cls(project_id)
130+
flow_item._set_values(id_, name, description, webpage_url, created_at, updated_at,
131+
tags, None, project_name, owner_id)
132+
all_flow_items.append(flow_item)
133+
return all_flow_items
134+
135+
@staticmethod
136+
def _parse_element(flow_xml, ns):
137+
id_ = flow_xml.get('id', None)
138+
name = flow_xml.get('name', None)
139+
description = flow_xml.get('description', None)
140+
webpage_url = flow_xml.get('webpageUrl', None)
141+
created_at = parse_datetime(flow_xml.get('createdAt', None))
142+
updated_at = parse_datetime(flow_xml.get('updatedAt', None))
143+
144+
tags = None
145+
tags_elem = flow_xml.find('.//t:tags', namespaces=ns)
146+
if tags_elem is not None:
147+
tags = TagItem.from_xml_element(tags_elem, ns)
148+
149+
project_id = None
150+
project_name = None
151+
project_elem = flow_xml.find('.//t:project', namespaces=ns)
152+
if project_elem is not None:
153+
project_id = project_elem.get('id', None)
154+
project_name = project_elem.get('name', None)
155+
156+
owner_id = None
157+
owner_elem = flow_xml.find('.//t:owner', namespaces=ns)
158+
if owner_elem is not None:
159+
owner_id = owner_elem.get('id', None)
160+
161+
return (id_, name, description, webpage_url, created_at, updated_at, tags, project_id,
162+
project_name, owner_id)

tableauserverclient/server/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
from .. import ConnectionItem, DatasourceItem, DatabaseItem, JobItem, BackgroundJobItem, \
66
GroupItem, PaginationItem, ProjectItem, ScheduleItem, SiteItem, TableauAuth,\
77
UserItem, ViewItem, WorkbookItem, TableItem, TaskItem, SubscriptionItem, \
8-
PermissionsRule, Permission, ColumnItem
8+
PermissionsRule, Permission, ColumnItem, FlowItem
99
from .endpoint import Auth, Datasources, Endpoint, Groups, Projects, Schedules, \
1010
Sites, Tables, Users, Views, Workbooks, Subscriptions, ServerResponseError, \
11-
MissingRequiredFieldError
11+
MissingRequiredFieldError, Flows
1212
from .server import Server
1313
from .pager import Pager
1414
from .exceptions import NotSignedInError

tableauserverclient/server/endpoint/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from .datasources_endpoint import Datasources
33
from .databases_endpoint import Databases
44
from .endpoint import Endpoint
5+
from .flows_endpoint import Flows
56
from .exceptions import ServerResponseError, MissingRequiredFieldError, ServerInfoEndpointNotFoundError
67
from .groups_endpoint import Groups
78
from .jobs_endpoint import Jobs

0 commit comments

Comments
 (0)
0