33# Workbook - A class for writing Tableau workbook files
44#
55###############################################################################
6- import contextlib
76import os
8- import shutil
9- import tempfile
107import zipfile
118
129import xml .etree .ElementTree as ET
1310
14- from tableaudocumentapi import Datasource
11+ from tableaudocumentapi import Datasource , xfile
1512
1613###########################################################################
1714#
2017###########################################################################
2118
2219
23- @contextlib .contextmanager
24- def temporary_directory (* args , ** kwargs ):
25- d = tempfile .mkdtemp (* args , ** kwargs )
26- try :
27- yield d
28- finally :
29- shutil .rmtree (d )
30-
31-
32- def find_twb_in_zip (zip ):
33- for filename in zip .namelist ():
34- if os .path .splitext (filename )[- 1 ].lower () == '.twb' :
35- return filename
36-
37-
38- def get_twb_xml_from_twbx (filename ):
39- with temporary_directory () as temp :
40- with zipfile .ZipFile (filename ) as zf :
41- zf .extractall (temp )
42- twb_file = find_twb_in_zip (zf )
43- twb_xml = ET .parse (os .path .join (temp , twb_file ))
44-
45- return twb_xml
46-
47-
48- def build_twbx_file (twbx_contents , zip ):
49- for root_dir , _ , files in os .walk (twbx_contents ):
50- relative_dir = os .path .relpath (root_dir , twbx_contents )
51- for f in files :
52- temp_file_full_path = os .path .join (
53- twbx_contents , relative_dir , f )
54- zipname = os .path .join (relative_dir , f )
55- zip .write (temp_file_full_path , arcname = zipname )
56-
57-
5820class Workbook (object ):
5921 """
6022 A class for writing Tableau workbook files.
@@ -75,7 +37,8 @@ def __init__(self, filename):
7537
7638 # Determine if this is a twb or twbx and get the xml root
7739 if zipfile .is_zipfile (self ._filename ):
78- self ._workbookTree = get_twb_xml_from_twbx (self ._filename )
40+ self ._workbookTree = xfile .get_xml_from_archive (
41+ self ._filename )
7942 else :
8043 self ._workbookTree = ET .parse (self ._filename )
8144
@@ -111,12 +74,7 @@ def save(self):
11174 """
11275
11376 # save the file
114-
115- if zipfile .is_zipfile (self ._filename ):
116- self ._save_into_twbx (self ._filename )
117- else :
118- self ._workbookTree .write (
119- self ._filename , encoding = "utf-8" , xml_declaration = True )
77+ xfile ._save_file (self ._filename , self ._workbookTree )
12078
12179 def save_as (self , new_filename ):
12280 """
@@ -129,12 +87,8 @@ def save_as(self, new_filename):
12987 Nothing.
13088
13189 """
132-
133- if zipfile .is_zipfile (self ._filename ):
134- self ._save_into_twbx (new_filename )
135- else :
136- self ._workbookTree .write (
137- new_filename , encoding = "utf-8" , xml_declaration = True )
90+ xfile ._save_file (
91+ self ._filename , self ._workbookTree , new_filename )
13892
13993 ###########################################################################
14094 #
@@ -150,31 +104,3 @@ def _prepare_datasources(self, xmlRoot):
150104 datasources .append (ds )
151105
152106 return datasources
153-
154- def _save_into_twbx (self , filename = None ):
155- # Save reuses existing filename, 'save as' takes a new one
156- if filename is None :
157- filename = self ._filename
158-
159- # Saving a twbx means extracting the contents into a temp folder,
160- # saving the changes over the twb in that folder, and then
161- # packaging it back up into a specifically formatted zip with the correct
162- # relative file paths
163-
164- # Extract to temp directory
165- with temporary_directory () as temp_path :
166- with zipfile .ZipFile (self ._filename ) as zf :
167- twb_file = find_twb_in_zip (zf )
168- zf .extractall (temp_path )
169- # Write the new version of the twb to the temp directory
170- self ._workbookTree .write (os .path .join (
171- temp_path , twb_file ), encoding = "utf-8" , xml_declaration = True )
172-
173- # Write the new twbx with the contents of the temp folder
174- with zipfile .ZipFile (filename , "w" , compression = zipfile .ZIP_DEFLATED ) as new_twbx :
175- build_twbx_file (temp_path , new_twbx )
176-
177- @staticmethod
178- def _is_valid_file (filename ):
179- fileExtension = os .path .splitext (filename )[- 1 ].lower ()
180- return fileExtension in ('.twb' , '.tds' )
0 commit comments