Repository: tableau/document-api-python

Issue:
Tabcmd publish with .twb created via Document API
I can successfully create a .twb file via the Document API, but attempting to publish it to my Tableau Server via Tabcmd results in an unexpected error:

**Bad request
unexpected error occurred opening the packaged workbook.**

Attached is the template workbook created in Tableau Desktop (superstore_sales.twb) and one of the workbooks created from that template via the Document API (superstore_sales_arizona.twb)

[superstore_twbs.zip](https://github.com/tableau/document-api-python/files/285303/superstore_twbs.zip)



Discussion:

Patch:
diff --git a/tableaudocumentapi/datasource.py b/tableaudocumentapi/datasource.py
index 93ebe55..617004a 100644
--- a/tableaudocumentapi/datasource.py
+++ b/tableaudocumentapi/datasource.py
@@ -72,7 +72,7 @@ class Datasource(object):
         """
 
         # save the file
-        self._datasourceTree.write(self._filename)
+        self._datasourceTree.write(self._filename, encoding="utf-8", xml_declaration=True)
 
     def save_as(self, new_filename):
         """
@@ -85,7 +85,7 @@ class Datasource(object):
             Nothing.
 
         """
-        self._datasourceTree.write(new_filename)
+        self._datasourceTree.write(new_filename, encoding="utf-8", xml_declaration=True)
 
     ###########
     # name
diff --git a/tableaudocumentapi/workbook.py b/tableaudocumentapi/workbook.py
index 67dbc32..889f746 100644
--- a/tableaudocumentapi/workbook.py
+++ b/tableaudocumentapi/workbook.py
@@ -76,7 +76,7 @@ class Workbook(object):
         """
 
         # save the file
-        self._workbookTree.write(self._filename)
+        self._workbookTree.write(self._filename, encoding="utf-8", xml_declaration=True)
 
     def save_as(self, new_filename):
         """
@@ -90,7 +90,7 @@ class Workbook(object):
 
         """
 
-        self._workbookTree.write(new_filename)
+        self._workbookTree.write(new_filename, encoding="utf-8", xml_declaration=True)
 
     ###########################################################################
     #


Test patch:
diff --git a/test.py b/test.py
index fd7d1bd..5606005 100644
--- a/test.py
+++ b/test.py
@@ -17,6 +17,7 @@ TABLEAU_10_WORKBOOK = '''<?xml version='1.0' encoding='utf-8' ?><workbook source
 TABLEAU_CONNECTION_XML = ET.fromstring(
     '''<connection authentication='sspi' class='sqlserver' dbname='TestV1' odbc-native-protocol='yes' one-time-sql='' server='mssql2012.test.tsi.lan' username=''></connection>''')
 
+
 class HelperMethodTests(unittest.TestCase):
 
     def test_is_valid_file_with_valid_inputs(self):
@@ -39,7 +40,6 @@ class ConnectionParserTests(unittest.TestCase):
         self.assertIsInstance(connections[0], Connection)
         self.assertEqual(connections[0].dbname, 'TestV1')
 
-
     def test_can_extract_federated_connections(self):
         parser = ConnectionParser(ET.fromstring(TABLEAU_10_TDS), '10.0')
         connections = parser.get_connections()
@@ -97,6 +97,17 @@ class DatasourceModelTests(unittest.TestCase):
         new_tds = Datasource.from_file(self.tds_file.name)
         self.assertEqual(new_tds.connections[0].dbname, 'newdb.test.tsi.lan')
 
+    def test_save_has_xml_declaration(self):
+        original_tds = Datasource.from_file(self.tds_file.name)
+        original_tds.connections[0].dbname = 'newdb.test.tsi.lan'
+
+        original_tds.save()
+
+        with open(self.tds_file.name) as f:
+            first_line = f.readline().strip()  # first line should be xml tag
+            self.assertEqual(
+                first_line, "<?xml version='1.0' encoding='utf-8'?>")
+
 
 class WorkbookModelTests(unittest.TestCase):
 
@@ -122,7 +133,8 @@ class WorkbookModelTests(unittest.TestCase):
         original_wb.save()
 
         new_wb = Workbook(self.workbook_file.name)
-        self.assertEqual(new_wb.datasources[0].connections[0].dbname, 'newdb.test.tsi.lan')
+        self.assertEqual(new_wb.datasources[0].connections[
+                         0].dbname, 'newdb.test.tsi.lan')
 
 
 class WorkbookModelV10Tests(unittest.TestCase):
@@ -152,7 +164,19 @@ class WorkbookModelV10Tests(unittest.TestCase):
         original_wb.save()
 
         new_wb = Workbook(self.workbook_file.name)
-        self.assertEqual(new_wb.datasources[0].connections[0].dbname, 'newdb.test.tsi.lan')
+        self.assertEqual(new_wb.datasources[0].connections[
+                         0].dbname, 'newdb.test.tsi.lan')
+
+    def test_save_has_xml_declaration(self):
+        original_wb = Workbook(self.workbook_file.name)
+        original_wb.datasources[0].connections[0].dbname = 'newdb.test.tsi.lan'
+
+        original_wb.save()
+
+        with open(self.workbook_file.name) as f:
+            first_line = f.readline().strip()  # first line should be xml tag
+            self.assertEqual(
+                first_line, "<?xml version='1.0' encoding='utf-8'?>")
 
 if __name__ == '__main__':
     unittest.main()