|
26 | 26 | # along with this program; if not, write to the Free Software Foundation, Inc.,
|
27 | 27 | # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
28 | 28 |
|
29 |
| -""" |
30 |
| -MySQL Connector/Python - MySQL driver written in Python |
31 |
| -""" |
| 29 | +"""MySQL Connector/Python - MySQL driver written in Python.""" |
32 | 30 |
|
33 | 31 | try:
|
34 |
| - import _mysql_connector # pylint: disable=F0401 |
35 |
| - |
36 | 32 | from .connection_cext import CMySQLConnection
|
37 | 33 | except ImportError:
|
38 | 34 | HAVE_CEXT = False
|
39 | 35 | else:
|
40 | 36 | HAVE_CEXT = True
|
41 | 37 |
|
42 |
| -try: |
43 |
| - import dns.exception |
44 |
| - import dns.resolver |
45 |
| -except ImportError: |
46 |
| - HAVE_DNSPYTHON = False |
47 |
| -else: |
48 |
| - HAVE_DNSPYTHON = True |
49 |
| - |
50 |
| -import random |
51 |
| -import warnings |
52 | 38 |
|
53 | 39 | from . import version
|
54 | 40 | from .connection import MySQLConnection
|
55 | 41 | from .constants import (
|
56 |
| - DEFAULT_CONFIGURATION, |
57 | 42 | CharacterSet,
|
58 | 43 | ClientFlag,
|
59 | 44 | FieldFlag,
|
|
77 | 62 | paramstyle,
|
78 | 63 | threadsafety,
|
79 | 64 | )
|
80 |
| -from .errors import ( # pylint: disable=W0622 |
| 65 | +from .errors import ( # pylint: disable=redefined-builtin |
81 | 66 | DatabaseError,
|
82 | 67 | DataError,
|
83 | 68 | Error,
|
|
92 | 77 | custom_error_exception,
|
93 | 78 | )
|
94 | 79 | from .optionfiles import read_option_files
|
| 80 | +from .pooling import connect |
95 | 81 |
|
96 |
| -_CONNECTION_POOLS = {} |
97 |
| - |
98 |
| -ERROR_NO_CEXT = "MySQL Connector/Python C Extension not available" |
99 |
| - |
100 |
| - |
101 |
| -def _get_pooled_connection(**kwargs): |
102 |
| - """Return a pooled MySQL connection""" |
103 |
| - # If no pool name specified, generate one |
104 |
| - from .pooling import ( |
105 |
| - CONNECTION_POOL_LOCK, |
106 |
| - MySQLConnectionPool, |
107 |
| - generate_pool_name, |
108 |
| - ) |
109 |
| - |
110 |
| - try: |
111 |
| - pool_name = kwargs["pool_name"] |
112 |
| - except KeyError: |
113 |
| - pool_name = generate_pool_name(**kwargs) |
114 |
| - |
115 |
| - if "use_pure" in kwargs: |
116 |
| - if not kwargs["use_pure"] and not HAVE_CEXT: |
117 |
| - raise ImportError(ERROR_NO_CEXT) |
118 |
| - |
119 |
| - # Setup the pool, ensuring only 1 thread can update at a time |
120 |
| - with CONNECTION_POOL_LOCK: |
121 |
| - if pool_name not in _CONNECTION_POOLS: |
122 |
| - _CONNECTION_POOLS[pool_name] = MySQLConnectionPool(**kwargs) |
123 |
| - elif isinstance(_CONNECTION_POOLS[pool_name], MySQLConnectionPool): |
124 |
| - # pool_size must be the same |
125 |
| - check_size = _CONNECTION_POOLS[pool_name].pool_size |
126 |
| - if "pool_size" in kwargs and kwargs["pool_size"] != check_size: |
127 |
| - raise PoolError("Size can not be changed " "for active pools.") |
128 |
| - |
129 |
| - # Return pooled connection |
130 |
| - try: |
131 |
| - return _CONNECTION_POOLS[pool_name].get_connection() |
132 |
| - except AttributeError: |
133 |
| - raise InterfaceError( |
134 |
| - "Failed getting connection from pool '{0}'".format(pool_name) |
135 |
| - ) |
136 |
| - |
137 |
| - |
138 |
| -def _get_failover_connection(**kwargs): |
139 |
| - """Return a MySQL connection and try to failover if needed |
140 |
| -
|
141 |
| - An InterfaceError is raise when no MySQL is available. ValueError is |
142 |
| - raised when the failover server configuration contains an illegal |
143 |
| - connection argument. Supported arguments are user, password, host, port, |
144 |
| - unix_socket and database. ValueError is also raised when the failover |
145 |
| - argument was not provided. |
146 |
| -
|
147 |
| - Returns MySQLConnection instance. |
148 |
| - """ |
149 |
| - config = kwargs.copy() |
150 |
| - try: |
151 |
| - failover = config["failover"] |
152 |
| - except KeyError: |
153 |
| - raise ValueError("failover argument not provided") |
154 |
| - del config["failover"] |
155 |
| - |
156 |
| - support_cnx_args = set( |
157 |
| - [ |
158 |
| - "user", |
159 |
| - "password", |
160 |
| - "host", |
161 |
| - "port", |
162 |
| - "unix_socket", |
163 |
| - "database", |
164 |
| - "pool_name", |
165 |
| - "pool_size", |
166 |
| - "priority", |
167 |
| - ] |
168 |
| - ) |
169 |
| - |
170 |
| - # First check if we can add all use the configuration |
171 |
| - priority_count = 0 |
172 |
| - for server in failover: |
173 |
| - diff = set(server.keys()) - support_cnx_args |
174 |
| - if diff: |
175 |
| - raise ValueError( |
176 |
| - "Unsupported connection argument {0} in failover: {1}".format( |
177 |
| - "s" if len(diff) > 1 else "", ", ".join(diff) |
178 |
| - ) |
179 |
| - ) |
180 |
| - if hasattr(server, "priority"): |
181 |
| - priority_count += 1 |
182 |
| - |
183 |
| - server["priority"] = server.get("priority", 100) |
184 |
| - if server["priority"] < 0 or server["priority"] > 100: |
185 |
| - raise InterfaceError( |
186 |
| - "Priority value should be in the range of 0 to 100, " |
187 |
| - "got : {}".format(server["priority"]) |
188 |
| - ) |
189 |
| - if not isinstance(server["priority"], int): |
190 |
| - raise InterfaceError( |
191 |
| - "Priority value should be an integer in the range of 0 to " |
192 |
| - "100, got : {}".format(server["priority"]) |
193 |
| - ) |
194 |
| - |
195 |
| - if 0 < priority_count < len(failover): |
196 |
| - raise ProgrammingError( |
197 |
| - "You must either assign no priority to any " |
198 |
| - "of the routers or give a priority for " |
199 |
| - "every router" |
200 |
| - ) |
201 |
| - |
202 |
| - failover.sort(key=lambda x: x["priority"], reverse=True) |
203 |
| - |
204 |
| - server_directory = {} |
205 |
| - server_priority_list = [] |
206 |
| - for server in failover: |
207 |
| - if server["priority"] not in server_directory: |
208 |
| - server_directory[server["priority"]] = [server] |
209 |
| - server_priority_list.append(server["priority"]) |
210 |
| - else: |
211 |
| - server_directory[server["priority"]].append(server) |
212 |
| - |
213 |
| - for priority in server_priority_list: |
214 |
| - failover_list = server_directory[priority] |
215 |
| - for _ in range(len(failover_list)): |
216 |
| - last = len(failover_list) - 1 |
217 |
| - index = random.randint(0, last) |
218 |
| - server = failover_list.pop(index) |
219 |
| - new_config = config.copy() |
220 |
| - new_config.update(server) |
221 |
| - new_config.pop("priority", None) |
222 |
| - try: |
223 |
| - return connect(**new_config) |
224 |
| - except Error: |
225 |
| - # If we failed to connect, we try the next server |
226 |
| - pass |
227 |
| - |
228 |
| - raise InterfaceError("Unable to connect to any of the target hosts") |
229 |
| - |
230 |
| - |
231 |
| -def connect(*args, **kwargs): |
232 |
| - """Create or get a MySQL connection object |
233 |
| -
|
234 |
| - In its simpliest form, Connect() will open a connection to a |
235 |
| - MySQL server and return a MySQLConnection object. |
236 |
| -
|
237 |
| - When any connection pooling arguments are given, for example pool_name |
238 |
| - or pool_size, a pool is created or a previously one is used to return |
239 |
| - a PooledMySQLConnection. |
240 |
| -
|
241 |
| - Returns MySQLConnection or PooledMySQLConnection. |
242 |
| - """ |
243 |
| - # DNS SRV |
244 |
| - dns_srv = kwargs.pop("dns_srv") if "dns_srv" in kwargs else False |
245 |
| - |
246 |
| - if not isinstance(dns_srv, bool): |
247 |
| - raise InterfaceError("The value of 'dns-srv' must be a boolean") |
248 |
| - |
249 |
| - if dns_srv: |
250 |
| - if not HAVE_DNSPYTHON: |
251 |
| - raise InterfaceError( |
252 |
| - "MySQL host configuration requested DNS " |
253 |
| - "SRV. This requires the Python dnspython " |
254 |
| - "module. Please refer to documentation" |
255 |
| - ) |
256 |
| - if "unix_socket" in kwargs: |
257 |
| - raise InterfaceError( |
258 |
| - "Using Unix domain sockets with DNS SRV " |
259 |
| - "lookup is not allowed" |
260 |
| - ) |
261 |
| - if "port" in kwargs: |
262 |
| - raise InterfaceError( |
263 |
| - "Specifying a port number with DNS SRV " |
264 |
| - "lookup is not allowed" |
265 |
| - ) |
266 |
| - if "failover" in kwargs: |
267 |
| - raise InterfaceError( |
268 |
| - "Specifying multiple hostnames with DNS " |
269 |
| - "SRV look up is not allowed" |
270 |
| - ) |
271 |
| - if "host" not in kwargs: |
272 |
| - kwargs["host"] = DEFAULT_CONFIGURATION["host"] |
273 |
| - |
274 |
| - try: |
275 |
| - srv_records = dns.resolver.query(kwargs["host"], "SRV") |
276 |
| - except dns.exception.DNSException: |
277 |
| - raise InterfaceError( |
278 |
| - "Unable to locate any hosts for '{0}'" |
279 |
| - "".format(kwargs["host"]) |
280 |
| - ) |
281 |
| - |
282 |
| - failover = [] |
283 |
| - for srv in srv_records: |
284 |
| - failover.append( |
285 |
| - { |
286 |
| - "host": srv.target.to_text(omit_final_dot=True), |
287 |
| - "port": srv.port, |
288 |
| - "priority": srv.priority, |
289 |
| - "weight": srv.weight, |
290 |
| - } |
291 |
| - ) |
292 |
| - |
293 |
| - failover.sort(key=lambda x: (x["priority"], -x["weight"])) |
294 |
| - kwargs["failover"] = [ |
295 |
| - {"host": srv["host"], "port": srv["port"]} for srv in failover |
296 |
| - ] |
297 |
| - |
298 |
| - # Option files |
299 |
| - if "read_default_file" in kwargs: |
300 |
| - kwargs["option_files"] = kwargs["read_default_file"] |
301 |
| - kwargs.pop("read_default_file") |
302 |
| - |
303 |
| - if "option_files" in kwargs: |
304 |
| - new_config = read_option_files(**kwargs) |
305 |
| - return connect(**new_config) |
306 |
| - |
307 |
| - # Failover |
308 |
| - if "failover" in kwargs: |
309 |
| - return _get_failover_connection(**kwargs) |
310 |
| - |
311 |
| - # Pooled connections |
312 |
| - try: |
313 |
| - from .constants import CNX_POOL_ARGS |
314 |
| - |
315 |
| - if any([key in kwargs for key in CNX_POOL_ARGS]): |
316 |
| - return _get_pooled_connection(**kwargs) |
317 |
| - except NameError: |
318 |
| - # No pooling |
319 |
| - pass |
320 |
| - |
321 |
| - # Use C Extension by default |
322 |
| - use_pure = kwargs.get("use_pure", False) |
323 |
| - if "use_pure" in kwargs: |
324 |
| - del kwargs["use_pure"] # Remove 'use_pure' from kwargs |
325 |
| - if not use_pure and not HAVE_CEXT: |
326 |
| - raise ImportError(ERROR_NO_CEXT) |
327 |
| - |
328 |
| - if HAVE_CEXT and not use_pure: |
329 |
| - return CMySQLConnection(*args, **kwargs) |
330 |
| - return MySQLConnection(*args, **kwargs) |
331 |
| - |
332 |
| - |
333 |
| -Connect = connect # pylint: disable=C0103 |
| 82 | +Connect = connect |
334 | 83 |
|
335 | 84 | __version_info__ = version.VERSION
|
336 | 85 | __version__ = version.VERSION_TEXT
|
|
0 commit comments