diff --git a/gooey/python_bindings/argparse_to_json.py b/gooey/python_bindings/argparse_to_json.py index 13a1d7b..5f76b3a 100644 --- a/gooey/python_bindings/argparse_to_json.py +++ b/gooey/python_bindings/argparse_to_json.py @@ -16,8 +16,7 @@ from functools import partial from uuid import uuid4 from gooey.python_bindings.gooey_parser import GooeyParser -from gooey.util.functional import merge, getin - +from gooey.util.functional import merge, getin, identity VALID_WIDGETS = ( 'FileChooser', @@ -347,12 +346,7 @@ def action_to_json(action, widget, options): }, }) - # Issue #321: - # Defaults for choice types must be coerced to strings - # to be able to match the stringified `choices` used by `wx.ComboBox` - default = (safe_string(clean_default(action.default)) - if widget in dropdown_types - else clean_default(action.default)) + default = coerce_default(action.default, widget) return { 'id': action.option_strings[0] if action.option_strings else action.dest, @@ -373,12 +367,47 @@ def action_to_json(action, widget, options): } + + + def choose_cli_type(action): return 'positional' \ if action.required and not action.option_strings \ else 'optional' +def coerce_default(default, widget): + """coerce a default value to the best appropriate type for + ingestion into wx""" + dispatcher = { + 'Listbox': clean_list_defaults, + 'Dropdown': safe_string, + 'Counter': safe_string + } + + # Issue #321: + # Defaults for choice types must be coerced to strings + # to be able to match the stringified `choices` used by `wx.ComboBox` + cleaned = clean_default(default) + + # dispatch to the appropriate cleaning function, or return the value + # as is if no special handler is present + return dispatcher.get(widget, identity)(cleaned) + + + +def clean_list_defaults(default_values): + """ + Listbox's default's can be passed as a single value + or a list of values (due to multiple selections). The list interface + is standardized on for ease. + """ + wrapped_values = ([default_values] + if isinstance(default_values, str) + else default_values) + return [safe_string(value) for value in wrapped_values] + + def clean_default(default): ''' Attemps to safely coalesce the default value down to diff --git a/gooey/tests/test_argparse_to_json.py b/gooey/tests/test_argparse_to_json.py index fe47fff..a955204 100644 --- a/gooey/tests/test_argparse_to_json.py +++ b/gooey/tests/test_argparse_to_json.py @@ -1,14 +1,12 @@ import unittest from argparse import ArgumentParser - +from gooey import GooeyParser from python_bindings import argparse_to_json from util.functional import getin class TestArgparse(unittest.TestCase): - """ - TODO: - """ + def test_json_iterable_conversion(self): """ @@ -59,3 +57,39 @@ class TestArgparse(unittest.TestCase): self.assertEqual(getin(result, ['data', 'default']), None) + def test_listbox_defaults_cast_correctly(self): + """ + Issue XXX - defaults supplied in a list were turned into a string + wholesale (list and all). The defaults should be stored as a list + proper with only the _internal_ values coerced to strings. + """ + parser = GooeyParser() + parser.add_argument('--foo', widget="Listbox", nargs="*", choices=[1, 2, 3], default=[1, 2]) + + choice_action = parser._actions[-1] + result = argparse_to_json.action_to_json(choice_action, 'Listbox', {}) + self.assertEqual(getin(result, ['data', 'default']), ['1', '2']) + + + def test_listbox_single_default_cast_correctly(self): + """ + Single arg defaults to listbox should be wrapped in a list and + their contents coerced as usual. + """ + parser = GooeyParser() + parser.add_argument('--foo', widget="Listbox", + nargs="*", choices=[1, 2, 3], default="sup") + + choice_action = parser._actions[-1] + result = argparse_to_json.action_to_json(choice_action, 'Listbox', {}) + self.assertEqual(getin(result, ['data', 'default']), ['sup']) + + def test_callables_as_default_args_are_cast_to_their_name(self): + """ Issue 147 """ + parser = ArgumentParser() + parser.add_argument('--foo', default=max) + + choice_action = parser._actions[-1] + result = argparse_to_json.action_to_json(choice_action, 'Textfield', {}) + self.assertEqual(getin(result, ['data', 'default']), 'max') +