Skip to content

Commit b4aeeb3

Browse files
committed
BUG21530100: Fix reading option files
During iteration of a dictionary, deleting of a key from the dictionary causes the following exception: RuntimeError: dictionary changed size during iteration This happens because `dict.keys` returns iterable views in python 3 instead of copies like in python 2. Using Python Dictionary Comprehension's fixes this issue. Test has been added for regression.
1 parent fc636f1 commit b4aeeb3

File tree

2 files changed

+56
-20
lines changed

2 files changed

+56
-20
lines changed

lib/mysql/connector/optionfiles.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -286,19 +286,19 @@ def get_groups(self, *args):
286286
args = self._options_dict.keys()
287287

288288
options = {}
289+
priority = {}
289290
for group in args:
290291
try:
291-
for option, value in self._options_dict[group].items():
292-
if option not in options or options[option][1] <= value[1]:
293-
options[option] = value
292+
for option, value in [(key, value,) for key, value in
293+
self._options_dict[group].items() if
294+
key != "__name__" and
295+
not key.startswith("!")]:
296+
if option not in options or priority[option] <= value[1]:
297+
priority[option] = value[1]
298+
options[option] = value[0]
294299
except KeyError:
295300
pass
296301

297-
for key in options.keys():
298-
if key == '__name__' or key.startswith('!'):
299-
del options[key]
300-
else:
301-
options[key] = options[key][0]
302302
return options
303303

304304
def get_groups_as_dict_with_priority(self, *args): # pylint: disable=C0103
@@ -321,14 +321,13 @@ def get_groups_as_dict_with_priority(self, *args): # pylint: disable=C0103
321321
options = dict()
322322
for group in args:
323323
try:
324-
options[group] = dict(self._options_dict[group])
324+
options[group] = {key: value for key, value in
325+
self._options_dict[group].items() if
326+
key != "__name__" and
327+
not key.startswith("!")}
325328
except KeyError:
326329
pass
327330

328-
for group in options.keys():
329-
for key in options[group].keys():
330-
if key == '__name__' or key.startswith('!'):
331-
del options[group][key]
332331
return options
333332

334333
def get_groups_as_dict(self, *args):
@@ -347,14 +346,11 @@ def get_groups_as_dict(self, *args):
347346
options = dict()
348347
for group in args:
349348
try:
350-
options[group] = dict(self._options_dict[group])
349+
options[group] = {key: value[0] for key, value in
350+
self._options_dict[group].items() if
351+
key != "__name__" and
352+
not key.startswith("!")}
351353
except KeyError:
352354
pass
353355

354-
for group in options.keys():
355-
for key in options[group].keys():
356-
if key == '__name__' or key.startswith('!'):
357-
del options[group][key]
358-
else:
359-
options[group][key] = options[group][key][0]
360356
return options

tests/test_bugs.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3119,6 +3119,46 @@ def test_unsupported_arguments(self):
31193119
self.assertEqual(exp, new_config)
31203120

31213121

3122+
class BugOra21530100(tests.MySQLConnectorTests):
3123+
"""BUG#21530100: CONNECT FAILS WHEN USING MULTIPLE OPTION_GROUPS WITH
3124+
PYTHON 3.3
3125+
"""
3126+
def test_option_files_with_option_groups(self):
3127+
temp_cnf_file = os.path.join(os.getcwd(), 'temp.cnf')
3128+
temp_include_file = os.path.join(os.getcwd(), 'include.cnf')
3129+
3130+
try:
3131+
cnf_file = open(temp_cnf_file, "w+")
3132+
include_file = open(temp_include_file, "w+")
3133+
3134+
config = tests.get_mysql_config()
3135+
3136+
cnf = "[group32]\n"
3137+
cnf += '\n'.join(['{0} = {1}'.format(key, value)
3138+
for key, value in config.items()])
3139+
3140+
cnf += "\n[group31]\n"
3141+
cnf += "!include {0}\n".format(temp_include_file)
3142+
3143+
include_cnf = "[group41]\n"
3144+
include_cnf += "charset=utf8\n"
3145+
3146+
cnf_file.write(cnf)
3147+
include_file.write(include_cnf)
3148+
3149+
cnf_file.close()
3150+
include_file.close()
3151+
3152+
conn = mysql.connector.connect(option_files=temp_cnf_file,
3153+
option_groups=['group31','group32','group41'])
3154+
except Exception as exc:
3155+
self.fail("Connection failed with option_files argument: {0}"
3156+
"".format(exc))
3157+
finally:
3158+
os.remove(temp_cnf_file)
3159+
os.remove(temp_include_file)
3160+
3161+
31223162
class BugOra19481761(tests.MySQLConnectorTests):
31233163
"""BUG#19481761: OPTION_FILES + !INCLUDE FAILS WITH TRAILING NEWLINE
31243164
"""

0 commit comments

Comments
 (0)