|
1 | | -############################################################################### |
2 | | -# |
3 | | -# Connection - A class for writing connections to Tableau files |
4 | | -# |
5 | | -############################################################################### |
6 | 1 | import xml.etree.ElementTree as ET |
7 | 2 | from tableaudocumentapi.dbclass import is_valid_dbclass |
8 | 3 |
|
9 | 4 |
|
10 | 5 | class Connection(object): |
11 | | - """ |
12 | | - A class for writing connections to Tableau files. |
13 | | -
|
14 | | - """ |
15 | | - |
16 | | - ########################################################################### |
17 | | - # |
18 | | - # Public API. |
19 | | - # |
20 | | - ########################################################################### |
| 6 | + """A class representing connections inside Data Sources.""" |
21 | 7 |
|
22 | 8 | def __init__(self, connxml): |
23 | | - """ |
24 | | - Constructor. |
| 9 | + """Connection is usually instantiated by passing in connection elements |
| 10 | + in a Data Source. If creating a connection from scratch you can call |
| 11 | + `from_attributes` passing in the connection attributes. |
25 | 12 |
|
26 | 13 | """ |
27 | 14 | self._connectionXML = connxml |
@@ -31,27 +18,33 @@ def __init__(self, connxml): |
31 | 18 | self._authentication = connxml.get('authentication') |
32 | 19 | self._class = connxml.get('class') |
33 | 20 | self._port = connxml.get('port', None) |
| 21 | + self._query_band = connxml.get('query-band-spec', None) |
| 22 | + self._initial_sql = connxml.get('one-time-sql', None) |
34 | 23 |
|
35 | 24 | def __repr__(self): |
36 | 25 | return "'<Connection server='{}' dbname='{}' @ {}>'".format(self._server, self._dbname, hex(id(self))) |
37 | 26 |
|
38 | 27 | @classmethod |
39 | | - def from_attributes(cls, server, dbname, username, dbclass, port=None, authentication=''): |
| 28 | + def from_attributes(cls, server, dbname, username, dbclass, port=None, query_band=None, |
| 29 | + initial_sql=None, authentication=''): |
| 30 | + """Creates a new connection that can be added into a Data Source. |
| 31 | + defaults to `''` which will be treated as 'prompt' by Tableau.""" |
| 32 | + |
40 | 33 | root = ET.Element('connection', authentication=authentication) |
41 | 34 | xml = cls(root) |
42 | 35 | xml.server = server |
43 | 36 | xml.dbname = dbname |
44 | 37 | xml.username = username |
45 | 38 | xml.dbclass = dbclass |
46 | 39 | xml.port = port |
| 40 | + xml.query_band = query_band |
| 41 | + xml.initial_sql = initial_sql |
47 | 42 |
|
48 | 43 | return xml |
49 | 44 |
|
50 | | - ########### |
51 | | - # dbname |
52 | | - ########### |
53 | 45 | @property |
54 | 46 | def dbname(self): |
| 47 | + """Database name for the connection. Not the table name.""" |
55 | 48 | return self._dbname |
56 | 49 |
|
57 | 50 | @dbname.setter |
@@ -69,11 +62,9 @@ def dbname(self, value): |
69 | 62 | self._dbname = value |
70 | 63 | self._connectionXML.set('dbname', value) |
71 | 64 |
|
72 | | - ########### |
73 | | - # server |
74 | | - ########### |
75 | 65 | @property |
76 | 66 | def server(self): |
| 67 | + """Hostname or IP address of the database server. May also be a URL in some connection types.""" |
77 | 68 | return self._server |
78 | 69 |
|
79 | 70 | @server.setter |
@@ -91,11 +82,9 @@ def server(self, value): |
91 | 82 | self._server = value |
92 | 83 | self._connectionXML.set('server', value) |
93 | 84 |
|
94 | | - ########### |
95 | | - # username |
96 | | - ########### |
97 | 85 | @property |
98 | 86 | def username(self): |
| 87 | + """Username used to authenticate to the database.""" |
99 | 88 | return self._username |
100 | 89 |
|
101 | 90 | @username.setter |
@@ -113,38 +102,49 @@ def username(self, value): |
113 | 102 | self._username = value |
114 | 103 | self._connectionXML.set('username', value) |
115 | 104 |
|
116 | | - ########### |
117 | | - # authentication |
118 | | - ########### |
119 | 105 | @property |
120 | 106 | def authentication(self): |
121 | 107 | return self._authentication |
122 | 108 |
|
123 | | - ########### |
124 | | - # dbclass |
125 | | - ########### |
126 | 109 | @property |
127 | 110 | def dbclass(self): |
| 111 | + """The type of connection (e.g. 'MySQL', 'Postgresql'). A complete list |
| 112 | + can be found in dbclass.py""" |
128 | 113 | return self._class |
129 | 114 |
|
130 | 115 | @dbclass.setter |
131 | 116 | def dbclass(self, value): |
| 117 | + """Set the connection's dbclass property. |
| 118 | +
|
| 119 | + Args: |
| 120 | + value: New dbclass value. String. |
| 121 | +
|
| 122 | + Returns: |
| 123 | + Nothing. |
| 124 | + """ |
132 | 125 |
|
133 | 126 | if not is_valid_dbclass(value): |
134 | 127 | raise AttributeError("'{}' is not a valid database type".format(value)) |
135 | 128 |
|
136 | 129 | self._class = value |
137 | 130 | self._connectionXML.set('class', value) |
138 | 131 |
|
139 | | - ########### |
140 | | - # port |
141 | | - ########### |
142 | 132 | @property |
143 | 133 | def port(self): |
| 134 | + """Port used to connect to the database.""" |
144 | 135 | return self._port |
145 | 136 |
|
146 | 137 | @port.setter |
147 | 138 | def port(self, value): |
| 139 | + """Set the connection's port property. |
| 140 | +
|
| 141 | + Args: |
| 142 | + value: New port value. String. |
| 143 | +
|
| 144 | + Returns: |
| 145 | + Nothing. |
| 146 | + """ |
| 147 | + |
148 | 148 | self._port = value |
149 | 149 | # If port is None we remove the element and don't write it to XML |
150 | 150 | if value is None: |
@@ -154,3 +154,55 @@ def port(self, value): |
154 | 154 | pass |
155 | 155 | else: |
156 | 156 | self._connectionXML.set('port', value) |
| 157 | + |
| 158 | + @property |
| 159 | + def query_band(self): |
| 160 | + """Query band passed on connection to database.""" |
| 161 | + return self._query_band |
| 162 | + |
| 163 | + @query_band.setter |
| 164 | + def query_band(self, value): |
| 165 | + """Set the connection's query_band property. |
| 166 | +
|
| 167 | + Args: |
| 168 | + value: New query_band value. String. |
| 169 | +
|
| 170 | + Returns: |
| 171 | + Nothing. |
| 172 | + """ |
| 173 | + |
| 174 | + self._query_band = value |
| 175 | + # If query band is None we remove the element and don't write it to XML |
| 176 | + if value is None: |
| 177 | + try: |
| 178 | + del self._connectionXML.attrib['query-band-spec'] |
| 179 | + except KeyError: |
| 180 | + pass |
| 181 | + else: |
| 182 | + self._connectionXML.set('query-band-spec', value) |
| 183 | + |
| 184 | + @property |
| 185 | + def initial_sql(self): |
| 186 | + """Initial SQL to be run.""" |
| 187 | + return self._initial_sql |
| 188 | + |
| 189 | + @initial_sql.setter |
| 190 | + def initial_sql(self, value): |
| 191 | + """Set the connection's initial_sql property. |
| 192 | +
|
| 193 | + Args: |
| 194 | + value: New initial_sql value. String. |
| 195 | +
|
| 196 | + Returns: |
| 197 | + Nothing. |
| 198 | + """ |
| 199 | + |
| 200 | + self._initial_sql = value |
| 201 | + # If initial_sql is None we remove the element and don't write it to XML |
| 202 | + if value is None: |
| 203 | + try: |
| 204 | + del self._connectionXML.attrib['one-time-sql'] |
| 205 | + except KeyError: |
| 206 | + pass |
| 207 | + else: |
| 208 | + self._connectionXML.set('one-time-sql', value) |