forked from tableau/document-api-python
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathworkbook.py
More file actions
159 lines (118 loc) · 5.16 KB
/
workbook.py
File metadata and controls
159 lines (118 loc) · 5.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import weakref
from tableaudocumentapi import Datasource, xfile
from tableaudocumentapi.xfile import xml_open
from tableaudocumentapi.worksheet import Worksheet
from tableaudocumentapi.window import Window
from tableaudocumentapi.action import Action
from tableaudocumentapi.shared_view import SharedView
from tableaudocumentapi.datasource_dependency import DatasourceDependency
from tableaudocumentapi.datasource_relationships import DatasourceRelationships
from tableaudocumentapi.dashboard import Dashboard
class Workbook(object):
"""A class for writing Tableau workbook files."""
def __init__(self, filename):
"""Open the workbook at `filename`. This will handle packaged and unpacked
workbook files automatically. This will also parse Data Sources and Worksheets
for access.
"""
self._filename = filename
self._workbookTree = xml_open(self._filename, 'workbook')
self._workbookRoot = self._workbookTree.getroot()
# prepare our datasource objects
self._datasources = self._prepare_datasources(
self._workbookRoot) # self.workbookRoot.find('datasources')
self._datasource_index = self._prepare_datasource_index(self._datasources)
self._ds_relationships_xml = self._workbookRoot.find('./datasource-relationships')
self._ds_relationships = DatasourceRelationships(self._ds_relationships_xml) if self._ds_relationships_xml else None
self._worksheets = self._prepare_worksheets(self._workbookRoot, self._datasource_index)
self._windows = list(map(Window, self._workbookRoot.findall('./windows/window')))
self._actions_xml = self._workbookRoot.findall('./actions/action')
self._actions = list(map(Action, self._actions_xml)) if self._actions_xml else []
self._ds_dep_xml = self._workbookRoot.findall('./actions/datasource-dependencies')
self._actions_ds_deps = list(map(DatasourceDependency, self._ds_dep_xml)) if bool(self._ds_dep_xml) else []
self._shared_views_xmls = self._workbookRoot.findall('./shared-views/shared-view')
self._shared_views = list(map(SharedView, self._shared_views_xmls)) if bool(self._shared_views_xmls) else []
self._actions = list(map(Action, self._workbookRoot.findall('./actions/action')))
self._dashboards = list(map(Dashboard, self._workbookRoot.findall('./dashboards/dashboard')))
@property
def datasources(self):
return self._datasources
@property
def worksheets(self):
return self._worksheets
@property
def windows(self):
return self._windows
@property
def filename(self):
return self._filename
@property
def actions(self):
return self._actions
@property
def shared_views(self):
return self._shared_views
@property
def actions_ds_deps(self):
return self._actions_ds_deps
@property
def ds_relationships(self):
return self._ds_relationships
@property
def dashboards(self):
return self._dashboards
def save(self):
"""
Call finalization code and save file.
Args:
None.
Returns:
Nothing.
"""
# save the file
xfile._save_file(self._filename, self._workbookTree)
def save_as(self, new_filename):
"""
Save our file with the name provided.
Args:
new_filename: New name for the workbook file. String.
Returns:
Nothing.
"""
xfile._save_file(
self._filename, self._workbookTree, new_filename)
@staticmethod
def _prepare_datasource_index(datasources):
retval = weakref.WeakValueDictionary()
for datasource in datasources:
retval[datasource.name] = datasource
return retval
@staticmethod
def _prepare_datasources(xml_root):
datasources = []
# loop through our datasources and append
datasource_elements = xml_root.find('datasources')
if datasource_elements is None:
return []
for datasource in datasource_elements:
ds = Datasource(datasource)
datasources.append(ds)
return datasources
@staticmethod
def _prepare_worksheets(xml_root, ds_index):
worksheets = []
worksheets_element = xml_root.find('.//worksheets')
if worksheets_element is None:
return worksheets
for worksheet_element in worksheets_element:
worksheet_name = worksheet_element.attrib['name']
worksheets.append(Worksheet(worksheet_element)) # TODO: A real worksheet object, for now, only name
dependencies = worksheet_element.findall('.//datasource-dependencies')
for dependency in dependencies:
datasource_name = dependency.attrib['datasource']
datasource = ds_index[datasource_name]
for column in dependency.findall('.//column'):
column_name = column.attrib['name']
if column_name in datasource.fields:
datasource.fields[column_name].add_used_in(worksheet_name)
return worksheets