Skip to content

Commit 1340616

Browse files
committed
Merge branch 'BUG19168737' into develop
2 parents 396777d + 0dc6988 commit 1340616

File tree

9 files changed

+206
-117
lines changed

9 files changed

+206
-117
lines changed

lib/mysql/connector/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
TimestampFromTicks, TimeFromTicks,
3939
STRING, BINARY, NUMBER, DATETIME, ROWID,
4040
apilevel, threadsafety, paramstyle)
41+
from .optionfiles import read_option_files
4142

4243
_CONNECTION_POOLS = {}
4344

@@ -129,6 +130,10 @@ def connect(*args, **kwargs):
129130
130131
Returns MySQLConnection or PooledMySQLConnection.
131132
"""
133+
# Option files
134+
if 'option_files' in kwargs:
135+
new_config = read_option_files(**kwargs)
136+
return connect(**new_config)
132137

133138
if all(['fabric' in kwargs, 'failover' in kwargs]):
134139
raise InterfaceError("fabric and failover arguments can not be used")

lib/mysql/connector/connection.py

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
MySQLCursorDict, MySQLCursorBufferedDict, MySQLCursorNamedTuple,
4444
MySQLCursorBufferedNamedTuple)
4545
from .network import MySQLUnixSocket, MySQLTCPSocket
46-
from .optionfiles import MySQLOptionsParser
4746
from .protocol import MySQLProtocol
4847
from .utils import int4store
4948

@@ -239,59 +238,6 @@ def _auth_switch_request(self, username=None, password=None):
239238
elif packet[4] == 255:
240239
raise errors.get_exception(packet)
241240

242-
def _read_option_files(self, config):
243-
"""
244-
Read option files for connection parameters.
245-
246-
Checks if connection arguments contain option file arguments, and then
247-
reads option files accordingly.
248-
"""
249-
if 'option_files' in config:
250-
try:
251-
if isinstance(config['option_groups'], str):
252-
config['option_groups'] = [config['option_groups']]
253-
groups = config['option_groups']
254-
del config['option_groups']
255-
except KeyError:
256-
groups = ['client', 'connector_python']
257-
258-
if isinstance(config['option_files'], str):
259-
config['option_files'] = [config['option_files']]
260-
option_parser = MySQLOptionsParser(list(config['option_files']),
261-
keep_dashes=False)
262-
del config['option_files']
263-
264-
config_from_file = option_parser.get_groups_as_dict_with_priority(
265-
*groups)
266-
config_options = {}
267-
for group in groups:
268-
try:
269-
for option, value in config_from_file[group].items():
270-
try:
271-
if option == 'socket':
272-
option = 'unix_socket'
273-
# pylint: disable=W0104
274-
DEFAULT_CONFIGURATION[option]
275-
# pylint: enable=W0104
276-
277-
if (option not in config_options or
278-
config_options[option][1] <= value[1]):
279-
config_options[option] = value
280-
except KeyError:
281-
if group is 'connector_python':
282-
raise AttributeError("Unsupported argument "
283-
"'{0}'".format(option))
284-
except KeyError:
285-
continue
286-
287-
for option, value in config_options.items():
288-
if option not in config:
289-
try:
290-
config[option] = eval(value[0]) # pylint: disable=W0123
291-
except (NameError, SyntaxError):
292-
config[option] = value[0]
293-
return config
294-
295241
def config(self, **kwargs):
296242
"""Configure the MySQL Connection
297243
@@ -303,9 +249,6 @@ def config(self, **kwargs):
303249
if 'dsn' in config:
304250
raise errors.NotSupportedError("Data source name is not supported")
305251

306-
# Read option files
307-
self._read_option_files(config)
308-
309252
# Configure how we handle MySQL warnings
310253
try:
311254
self.get_warnings = config['get_warnings']

lib/mysql/connector/fabric/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@
3939
'shard', 'shard_type', 'group', 'global_group']
4040
)
4141

42+
CNX_FABRIC_ARGS = ['fabric_host', 'fabric_username', 'fabric_password',
43+
'fabric_port', 'fabric_connect_attempts',
44+
'fabric_connect_delay', 'fabric_report_errors',
45+
'fabric_ssl_ca', 'fabric_ssl_key', 'fabric_ssl_cert',
46+
'fabric_user']
47+
4248
from .connection import (
4349
MODE_READONLY, MODE_READWRITE,
4450
STATUS_PRIMARY, STATUS_SECONDARY,

lib/mysql/connector/optionfiles.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
import re
3131

3232
from .catch23 import PY2
33+
from .connection import DEFAULT_CONFIGURATION
34+
from .pooling import CNX_POOL_ARGS
35+
from .fabric import CNX_FABRIC_ARGS
3336

3437
# pylint: disable=F0401
3538
if PY2:
@@ -45,6 +48,80 @@
4548
}
4649

4750

51+
def read_option_files(**config):
52+
"""
53+
Read option files for connection parameters.
54+
55+
Checks if connection arguments contain option file arguments, and then
56+
reads option files accordingly.
57+
"""
58+
if 'option_files' in config:
59+
try:
60+
if isinstance(config['option_groups'], str):
61+
config['option_groups'] = [config['option_groups']]
62+
groups = config['option_groups']
63+
del config['option_groups']
64+
except KeyError:
65+
groups = ['client', 'connector_python']
66+
67+
if isinstance(config['option_files'], str):
68+
config['option_files'] = [config['option_files']]
69+
option_parser = MySQLOptionsParser(list(config['option_files']),
70+
keep_dashes=False)
71+
del config['option_files']
72+
73+
config_from_file = option_parser.get_groups_as_dict_with_priority(
74+
*groups)
75+
config_options = {}
76+
fabric_options = {}
77+
for group in groups:
78+
try:
79+
for option, value in config_from_file[group].items():
80+
try:
81+
if option == 'socket':
82+
option = 'unix_socket'
83+
84+
if option in CNX_FABRIC_ARGS:
85+
if (option not in fabric_options or
86+
fabric_options[option][1] <= value[1]):
87+
fabric_options[option] = value
88+
continue
89+
90+
if (option not in CNX_POOL_ARGS and
91+
option not in ['fabric', 'failover']):
92+
# pylint: disable=W0104
93+
DEFAULT_CONFIGURATION[option]
94+
# pylint: enable=W0104
95+
96+
if (option not in config_options or
97+
config_options[option][1] <= value[1]):
98+
config_options[option] = value
99+
except KeyError:
100+
if group is 'connector_python':
101+
raise AttributeError("Unsupported argument "
102+
"'{0}'".format(option))
103+
except KeyError:
104+
continue
105+
106+
for option, value in config_options.items():
107+
if option not in config:
108+
try:
109+
config[option] = eval(value[0]) # pylint: disable=W0123
110+
except (NameError, SyntaxError):
111+
config[option] = value[0]
112+
113+
if fabric_options:
114+
config['fabric'] = {}
115+
for option, value in fabric_options.items():
116+
try:
117+
# pylint: disable=W0123
118+
config['fabric'][option.split('_', 1)[1]] = eval(value[0])
119+
# pylint: enable=W0123
120+
except (NameError, SyntaxError):
121+
config['fabric'][option.split('_', 1)[1]] = value[0]
122+
return config
123+
124+
48125
class MySQLOptionsParser(SafeConfigParser): # pylint: disable=R0901
49126
"""This class implements methods to parse MySQL option files"""
50127

lib/mysql/connector/pooling.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
from .connection import MySQLConnection
4040

4141
CONNECTION_POOL_LOCK = threading.RLock()
42-
CNX_POOL_ARGS = ('pool_name', 'pool_size', 'pool_cnx')
42+
CNX_POOL_ARGS = ('pool_name', 'pool_size', 'pool_reset_session')
4343
CNX_POOL_MAXSIZE = 32
4444
CNX_POOL_MAXNAMESIZE = 64
4545
CNX_POOL_NAMEREGEX = re.compile(r'[^a-zA-Z0-9._:\-*$#]')

tests/data/option_files/pool.cnf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[pooling]
2+
pool_size = 1
3+
pool_name = my_pool
4+
pool_reset_session = True
5+
6+
[fabric]
7+
fabric_host = fabric.example.com
8+
fabric_connect_delay = 3
9+
fabric_ssl_ca = /path/to/ssl
10+
fabric_password = foo
11+
12+
[failover]
13+
failover = ({'port': 3306, 'pool_name': 'failA' }, {'port': 3307, 'pool_name': 'failB' },)
14+

tests/test_bugs.py

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
from . import PY2
4949
from mysql.connector import (connection, cursor, conversion, protocol,
5050
errors, constants, pooling)
51+
from mysql.connector.optionfiles import read_option_files
5152
import mysql.connector
5253

5354

@@ -2730,17 +2731,14 @@ class BugOra19170287(tests.MySQLConnectorTests):
27302731
def test_duplicate_groups(self):
27312732
option_file_dir = os.path.join('tests', 'data', 'option_files')
27322733
opt_file = os.path.join(option_file_dir, 'dup_groups.cnf')
2733-
config = tests.get_mysql_config()
27342734

2735-
cnx = mysql.connector.connect(**config)
27362735
exp = {
27372736
u'password': u'mypass',
27382737
u'user': u'mysql',
27392738
u'database': u'duplicate_data',
27402739
u'port': 10000
27412740
}
2742-
self.assertEqual(exp, cnx._read_option_files(
2743-
{'option_files': opt_file}))
2741+
self.assertEqual(exp, read_option_files(option_files=opt_file))
27442742

27452743

27462744
class BugOra19169143(tests.MySQLConnectorTests):
@@ -2750,7 +2748,7 @@ def test_duplicate_optionfiles(self):
27502748
option_file_dir = os.path.join('tests', 'data', 'option_files')
27512749
files = [
27522750
os.path.join(option_file_dir, 'include_files', '1.cnf'),
2753-
os.path.join(option_file_dir, 'include_files', '2.cnf'),
2751+
os.path.join(option_file_dir, 'include_files', '2.cnf'),
27542752
os.path.join(option_file_dir, 'include_files', '1.cnf'),
27552753
]
27562754
self.assertRaises(ValueError, mysql.connector.connect,
@@ -2794,3 +2792,44 @@ def test_null(self):
27942792
cur.execute(sql)
27952793
self.assertEqual(exp, cur.fetchone())
27962794
cur.close()
2795+
2796+
2797+
class BugOra19168737(tests.MySQLConnectorTests):
2798+
"""BUG#19168737: UNSUPPORTED CONNECTION ARGUMENTS WHILE USING OPTION_FILES
2799+
"""
2800+
def test_unsupported_arguments(self):
2801+
option_file_dir = os.path.join('tests', 'data', 'option_files')
2802+
opt_file = os.path.join(option_file_dir, 'pool.cnf')
2803+
config = tests.get_mysql_config()
2804+
2805+
conn = mysql.connector.connect(option_files=opt_file,
2806+
option_groups=['pooling'], **config)
2807+
self.assertEqual('my_pool', conn.pool_name)
2808+
mysql.connector._CONNECTION_POOLS = {}
2809+
conn.close()
2810+
2811+
new_config = read_option_files(option_files=opt_file,
2812+
option_groups=['fabric'], **config)
2813+
2814+
exp = {
2815+
'fabric': {
2816+
'connect_delay': 3,
2817+
'host': 'fabric.example.com',
2818+
'password': 'foo',
2819+
'ssl_ca': '/path/to/ssl'
2820+
}
2821+
}
2822+
exp.update(config)
2823+
2824+
self.assertEqual(exp, new_config)
2825+
2826+
new_config = read_option_files(option_files=opt_file,
2827+
option_groups=['failover'], **config)
2828+
2829+
exp = {
2830+
'failover': ({'pool_name': 'failA', 'port': 3306},
2831+
{'pool_name': 'failB', 'port': 3307})
2832+
}
2833+
exp.update(config)
2834+
2835+
self.assertEqual(exp, new_config)

0 commit comments

Comments
 (0)