Update setuptools command option normalization

We were very naively "normalizing" options parsed and provided by
setuptools. This updates our handling to store the Option instance
from optparse so we can inspect the type, action, and option name for
more intelligent option normalization.

Closes #121
This commit is contained in:
Ian Cordasco 2016-02-14 13:41:33 -06:00
parent 388db0d811
commit a8aac56092
3 changed files with 92 additions and 50 deletions

View file

@ -93,18 +93,18 @@ class Flake8Command(setuptools.Command):
for opt in parser.option_list:
cmd_name = opt._long_opts[0][2:]
option_name = cmd_name.replace('-', '_')
self.option_to_cmds[option_name] = cmd_name
self.option_to_cmds[option_name] = opt
setattr(self, option_name, None)
def finalize_options(self):
self.options_dict = {}
for (option_name, cmd_name) in self.option_to_cmds.items():
for (option_name, opt) in self.option_to_cmds.items():
if option_name in ['help', 'verbose']:
continue
value = getattr(self, option_name)
if value is None:
continue
value = option_normalizer(value)
value = option_normalizer(value, opt, option_name)
# Check if there's any values that need to be fixed.
if option_name == "include" and isinstance(value, str):
value = re.findall('[^,;\s]+', value)

View file

@ -1,85 +1,119 @@
import optparse
import unittest
from flake8.util import option_normalizer
class TestOptionSerializer(unittest.TestCase):
class TestOptionSerializerParsesTrue(unittest.TestCase):
def setUp(self):
self.option = optparse.Option('--foo', action='store_true')
self.option_name = 'fake_option'
def test_1_is_true(self):
option = option_normalizer('1')
self.assertTrue(option)
value = option_normalizer('1', self.option, self.option_name)
self.assertTrue(value)
def test_T_is_true(self):
option = option_normalizer('T')
self.assertTrue(option)
value = option_normalizer('T', self.option, self.option_name)
self.assertTrue(value)
def test_TRUE_is_true(self):
option = option_normalizer('TRUE')
self.assertTrue(option, True)
value = option_normalizer('TRUE', self.option, self.option_name)
self.assertTrue(value, True)
def test_ON_is_true(self):
option = option_normalizer('ON')
self.assertTrue(option)
value = option_normalizer('ON', self.option, self.option_name)
self.assertTrue(value)
def test_t_is_true(self):
option = option_normalizer('t')
self.assertTrue(option)
value = option_normalizer('t', self.option, self.option_name)
self.assertTrue(value)
def test_true_is_true(self):
option = option_normalizer('true')
self.assertTrue(option)
value = option_normalizer('true', self.option, self.option_name)
self.assertTrue(value)
def test_on_is_true(self):
option = option_normalizer('on')
self.assertTrue(option)
value = option_normalizer('on', self.option, self.option_name)
self.assertTrue(value)
class TestOptionSerializerParsesFalse(unittest.TestCase):
def setUp(self):
self.option = optparse.Option('--foo', action='store_true')
self.option_name = 'fake_option'
def test_0_is_false(self):
option = option_normalizer('0')
self.assertFalse(option)
value = option_normalizer('0', self.option, self.option_name)
self.assertFalse(value)
def test_F_is_false(self):
option = option_normalizer('F')
self.assertFalse(option)
value = option_normalizer('F', self.option, self.option_name)
self.assertFalse(value)
def test_FALSE_is_false(self):
option = option_normalizer('FALSE')
self.assertFalse(option)
value = option_normalizer('FALSE', self.option, self.option_name)
self.assertFalse(value)
def test_OFF_is_false(self):
option = option_normalizer('OFF')
self.assertFalse(option)
value = option_normalizer('OFF', self.option, self.option_name)
self.assertFalse(value)
def test_f_is_false(self):
option = option_normalizer('f')
self.assertFalse(option)
value = option_normalizer('f', self.option, self.option_name)
self.assertFalse(value)
def test_false_is_false(self):
option = option_normalizer('false')
self.assertFalse(option)
value = option_normalizer('false', self.option, self.option_name)
self.assertFalse(value)
def test_off_is_false(self):
option = option_normalizer('off')
self.assertFalse(option)
value = option_normalizer('off', self.option, self.option_name)
self.assertFalse(value)
def test_parses_lists(self):
answer = ['F401', 'F402', 'F403', 'F404']
option = option_normalizer('F401,F402,F403,F404')
self.assertEqual(option, answer)
class TestOptionSerializerParsesLists(unittest.TestCase):
option = option_normalizer('F401 ,F402 ,F403 ,F404')
self.assertEqual(option, answer)
def setUp(self):
self.option = optparse.Option('--select')
self.option_name = 'select'
self.answer = ['F401', 'F402', 'F403', 'F404']
option = option_normalizer('F401, F402, F403, F404')
self.assertEqual(option, answer)
def test_parses_simple_comma_separated_lists(self):
value = option_normalizer('F401,F402,F403,F404', self.option,
self.option_name)
self.assertEqual(value, self.answer)
option = option_normalizer('''\
def test_parses_less_simple_comma_separated_lists(self):
value = option_normalizer('F401 ,F402 ,F403 ,F404', self.option,
self.option_name)
self.assertEqual(value, self.answer)
value = option_normalizer('F401, F402, F403, F404', self.option,
self.option_name)
self.assertEqual(value, self.answer)
def test_parses_comma_separated_lists_with_newlines(self):
value = option_normalizer('''\
F401,
F402,
F403,
F404,
''')
self.assertEqual(option, answer)
''', self.option, self.option_name)
self.assertEqual(value, self.answer)
class TestOptionSerializerParsesInts(unittest.TestCase):
def setUp(self):
self.option = optparse.Option('--max-complexity', type='int')
self.option_name = 'max_complexity'
def test_parses_an_int(self):
value = option_normalizer('2', self.option, self.option_name)
self.assertEqual(value, 2)
if __name__ == '__main__':

View file

@ -57,13 +57,21 @@ def force_disable_jobs(styleguide):
return is_windows() or is_using_stdin(styleguide.paths)
def option_normalizer(value):
if str(value).upper() in ('1', 'T', 'TRUE', 'ON'):
value = True
if str(value).upper() in ('0', 'F', 'FALSE', 'OFF'):
value = False
INT_TYPES = ('int', 'count')
BOOL_TYPES = ('store_true', 'store_false')
LIST_OPTIONS = ('select', 'ignore', 'exclude', 'enable_extensions')
if isinstance(value, str):
value = [opt.strip() for opt in value.split(',') if opt.strip()]
def option_normalizer(value, option, option_name):
if option.action in BOOL_TYPES:
if str(value).upper() in ('1', 'T', 'TRUE', 'ON'):
value = True
if str(value).upper() in ('0', 'F', 'FALSE', 'OFF'):
value = False
elif option.type in INT_TYPES:
value = int(value)
elif option_name in LIST_OPTIONS:
if isinstance(value, str):
value = [opt.strip() for opt in value.split(',') if opt.strip()]
return value