8000 Merge pull request #7 from t8y8/connection-parser · tableau/document-api-python@a22d077 · GitHub
[go: up one dir, main page]

Skip to content

Commit a22d077

Browse files
committed
Merge pull request #7 from t8y8/connection-parser
Implemented ConnectionParser to handle Federated and Legacy connections
2 parents 3b64cf3 + 6ea5578 commit a22d077

File tree

3 files changed

+78
-20
lines changed

3 files changed

+78
-20
lines changed

tableaudocumentapi/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__version__ = '0.0.1'
22
__VERSION__ = __version__
33
from .connection import Connection
4-
from .datasource import Datasource
4+
from .datasource import Datasource, ConnectionParser
55
from .workbook import Workbook

tableaudocumentapi/datasource.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,25 @@
66
import xml.etree.ElementTree as ET
77
from tableaudocumentapi import Connection
88

9+
class ConnectionParser(object):
10+
11+
def __init__(self, datasource_xml, version):
12+
self._dsxml = datasource_xml
13+
self._dsversion = version
14+
15+
def _extract_federated_connections(self):
16+
return list(map(Connection,self._dsxml.findall('.//named-connections/named-connection/*')))
17+
18+
def _extract_legacy_connection(self):
19+
return Connection(self._dsxml.find('connection'))
20+
21+
def get_connections(self):
22+
if float(self._dsversion) < 10:
23+
connections = self._extract_legacy_connection()
24+
else:
25+
connections = self._extract_federated_connections()
26+
return connections
27+
928

1029
class Datasource(object):
1130
"""
@@ -28,7 +47,8 @@ def __init__(self, dsxml, filename=None):
2847
self._datasourceTree = ET.ElementTree(self._datasourceXML)
2948
self._name = self._datasourceXML.get('name') or self._datasourceXML.get('formatted-name') # TDS files don't have a name attribute
3049
self._version = self._datasourceXML.get('version')
31-
self._connection = Connection(self._datasourceXML.find('connection'))
50+
self._connection_parser = ConnectionParser(self._datasourceXML, version=self._version)
51+
self._connection = self._connection_parser.get_connections()
3252

3353
@classmethod
3454
def from_file(cls, filename):

test.py

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,20 @@
33
import os
44
import xml.etree.ElementTree as ET
55

6-
from tableaudocumentapi import Workbook, Datasource, Connection
7-
8-
TABLEAU_93_WORKBOOK = '''<?xml version='1.0' encoding='utf-8' ?>
9-
<workbook source-build='9.3.1 (9300.16.0510.0100)' source-platform='mac' version='9.3' xmlns:user='http://www.tableausoftware.com/xml/user'>
10-
<datasources>
11-
<datasource caption='xy (TestV1)' inline='true' name='sqlserver.17u3bqc16tjtxn14e2hxh19tyvpo' version='9.3'>
12-
<connection authentication='sspi' class='sqlserver' dbname='TestV1' odbc-native-protocol='yes' one-time-sql='' server='mssql2012.test.tsi.lan' username=''>
13-
</connection>
14-
</datasource>
15-
</datasources>
16-
</workbook>'''
17-
18-
TABLEAU_93_TDS = '''<?xml version='1.0' encoding='utf-8' ?>
19-
<datasource formatted-name='sqlserver.17u3bqc16tjtxn14e2hxh19tyvpo' inline='true' source-platform='mac' version='9.3' xmlns:user='http://www.tableausoftware.com/xml/user'>
20-
<connection authentication='sspi' class='sqlserver' dbname='TestV1' odbc-native-protocol='yes' one-time-sql='' server='mssql2012.test.tsi.lan' username=''>
21-
</connection>
22-
</datasource>'''
6+
from tableaudocumentapi import Workbook, Datasource, Connection, ConnectionParser
7+
8+
9+
TABLEAU_93_WORKBOOK = '''<?xml version='1.0' encoding='utf-8' ?><workbook source-build='9.3.1 (9300.16.0510.0100)' source-platform='mac' version='9.3' xmlns:user='http://www.tableausoftware.com/xml/user'><datasources><datasource caption='xy (TestV1)' inline='true' name='sqlserver.17u3bqc16tjtxn14e2hxh19tyvpo' version='9.3'><connection authentication='sspi' class='sqlserver' dbname='TestV1' odbc-native-protocol='yes' one-time-sql='' server='mssql2012.test.tsi.lan' username=''></connection></datasource></datasources></workbook>'''
10+
11+
TABLEAU_93_TDS = '''<?xml version='1.0' encoding='utf-8' ?><datasource formatted-name='sqlserver.17u3bqc16tjtxn14e2hxh19tyvpo' inline='true' source-platform='mac' version='9.3' xmlns:user='http://www.tableausoftware.com/xml/user'><connection authentication='sspi' class='sqlserver' dbname='TestV1' odbc-native-protocol='yes' one-time-sql='' server='mssql2012.test.tsi.lan' username=''></connection></datasource>'''
12+
13+
TABLEAU_10_TDS = '''<?xml version='1.0' encoding='utf-8' ?><datasources><datasource caption='xy+ (Multiple Connections)' inline='true' name='federated.1s4nxn20cywkdv13ql0yk0g1mpdx' version='10.0'><connection class='federated'><named-connections><named-connection caption='mysql55.test.tsi.lan' name='mysql.1ewmkrw0mtgsev1dnurma1blii4x'><connection class='mysql' dbname='testv1' odbc-native-protocol='yes' port='3306' server='mysql55.test.tsi.lan' source-charset='' username='test' /></named-connection><named-connection caption='mssql2012.test.tsi.lan' name='sqlserver.1erdwp01uqynlb14ul78p0haai2r'><connection authentication='sqlserver' class='sqlserver' dbname='TestV1' odbc-native-protocol='yes' one-time-sql='' server='mssql2012.test.tsi.lan' username='test' /></named-connection></named-connections></connection></datasource></datasources>'''
14+
15+
TABLEAU_10_WORKBOOK = '''<?xml version='1.0' encoding='utf-8' ?><workbook source-build='0.0.0 (0000.16.0510.1300)' source-platform='mac' version='10.0' xmlns:user='http://www.tableausoftware.com/xml/user'><datasources><datasource caption='xy+ (Multiple Connections)' inline='true' name='federated.1s4nxn20cywkdv13ql0yk0g1mpdx' version='10.0'><connection class='federated'><named-connections><named-connection caption='mysql55.test.tsi.lan' name='mysql.1ewmkrw0mtgsev1dnurma1blii4x'><connection class='mysql' dbname='testv1' odbc-native-protocol='yes' port='3306' server='mysql55.test.tsi.lan' source-charset='' username='test' /></named-connection><named-connection caption='mssql2012.test.tsi.lan' name='sqlserver.1erdwp01uqynlb14ul78p0haai2r'><connection authentication='sqlserver' class='sqlserver' dbname='TestV1' odbc-native-protocol='yes' one-time-sql='' server='mssql2012.test.tsi.lan' username='test' /></named-connection></named-connections></connection></datasource></datasources></workbook>'''
2316

2417
TABLEAU_CONNECTION_XML = ET.fromstring(
2518
'''<connection authentication='sspi' class='sqlserver' dbname='TestV1' odbc-native-protocol='yes' one-time-sql='' server='mssql2012.test.tsi.lan' username=''></connection>''')
2619

27-
2820
class HelperMethodTests(unittest.TestCase):
2921

3022
def test_is_valid_file_with_valid_inputs(self):
@@ -38,6 +30,23 @@ def test_is_valid_file_with_invalid_inputs(self):
3830
self.assertFalse(Workbook._is_valid_file('file2.twb3'))
3931

4032

33+
class ConnectionParserTests(unittest.TestCase):
34+
35+
def test_can_extract_legacy_connection(self):
36+
parser = ConnectionParser(ET.fromstring(TABLEAU_93_TDS), '9.2')
37+
connection = parser.get_connections()
38+
self.assertIsInstance(connection, Connection)
39+
self.assertEqual(connection.dbname, 'TestV1')
40+
41+
42+
def test_can_extract_federated_connections(self):
43+
parser = ConnectionParser(ET.fromstring(TABLEAU_10_TDS), '10.0')
44+
connections = parser.get_connections()
45+
self.assertIsInstance(connections, list)
46+
self.assertIsInstance(connections[0], Connection)
47+
self.assertEqual(connections[0].dbname, 'testv1')
48+
49+
4150
class ConnectionModelTests(unittest.TestCase):
4251

4352
def setUp(self):
@@ -114,5 +123,34 @@ def test_can_update_datasource_connection_and_save(self):
114123
self.assertEqual(new_wb.datasources[0].connection.dbname, 'newdb.test.tsi.lan')
115124

116125

126+
class WorkbookModelV10Tests(unittest.TestCase):
127+
128+
def setUp(self):
129+
self.workbook_file = io.FileIO('testv10.twb', 'w')
130+
self.workbook_file.write(TABLEAU_10_WORKBOOK.encode('utf8'))
131+
self.workbook_file.seek(0)
132+
133+
def tearDown(self):
134+
self.workbook_file.close()
135+
os.unlink(self.workbook_file.name)
136+
137+
def test_can_extract_datasourceV10(self):
138+
wb = Workbook(self.workbook_file.name)
139+
self.assertEqual(len(wb.datasources), 1)
140+
self.assertEqual(len(wb.datasources[0].connection), 2)
141+
self.assertIsInstance(wb.datasources[0].connection, list)
142+
self.assertIsInstance(wb.datasources[0], Datasource)
143+
self.assertEqual(wb.datasources[0].name,
144+
'federated.1s4nxn20cywkdv13ql0yk0g1mpdx')
145+
146+
def test_can_update_datasource_connection_and_saveV10(self):
147+
original_wb = Workbook(self.workbook_file.name)
148+
original_wb.datasources[0].connection[0].dbname = 'newdb.test.tsi.lan'
149+
150+
original_wb.save()
151+
152+
new_wb = Workbook(self.workbook_file.name)
153+
self.assertEqual(new_wb.datasources[0].connection[0].dbname, 'newdb.test.tsi.lan')
154+
117155
if __name__ == '__main__':
118156
unittest.main()

0 commit comments

Comments
 (0)
0