diff --git a/gooey/python_bindings/argparse_to_json.py b/gooey/python_bindings/argparse_to_json.py index 1e54c05..35dd150 100644 --- a/gooey/python_bindings/argparse_to_json.py +++ b/gooey/python_bindings/argparse_to_json.py @@ -287,9 +287,12 @@ def categorize(actions, widget_dict, options): elif is_standard(action): yield action_to_json(action, _get_widget(action, 'TextField'), options) - elif is_file(action): + elif is_writemode_file(action): yield action_to_json(action, _get_widget(action, 'FileSaver'), options) + elif is_readmode_file(action): + yield action_to_json(action, _get_widget(action, 'FileChooser'), options) + elif is_choice(action): yield action_to_json(action, _get_widget(action, 'Dropdown'), options) @@ -355,6 +358,16 @@ def is_file(action): ''' action with FileType ''' return isinstance(action.type, argparse.FileType) +def is_readmode_file(action): + return is_file(action) and 'r' in action.type._mode + +def is_writemode_file(action): + # FileType uses the same modes as the builtin `open` + # as such, all modes that aren't explicitly `r` (which is + # also the default) are writable or read/writable, thus + # making a FileChooser a good choice. + return is_file(action) and 'r' not in action.type._mode + def is_version(action): return isinstance(action, _VersionAction) diff --git a/gooey/tests/test_argparse_to_json.py b/gooey/tests/test_argparse_to_json.py index 225d743..1d50c22 100644 --- a/gooey/tests/test_argparse_to_json.py +++ b/gooey/tests/test_argparse_to_json.py @@ -1,12 +1,15 @@ import argparse import sys import unittest -from argparse import ArgumentParser +from argparse import ArgumentParser, FileType from gooey import GooeyParser from gooey.python_bindings import argparse_to_json from gooey.util.functional import getin from gooey.tests import * +from gui.components.options.options import FileChooser +from gui.components.widgets import FileSaver + class TestArgparse(unittest.TestCase): @@ -259,3 +262,31 @@ class TestArgparse(unittest.TestCase): choices=["one", "two"], default="one", ) + + + def test_filetype_chooses_good_widget(self): + """ + #743 chose the picker type based on the FileType mode + when available. + """ + cases = [ + (FileType(), 'FileChooser'), + (FileType('r'), 'FileChooser'), + (FileType('rb'), 'FileChooser'), + (FileType('rt'), 'FileChooser'), + (FileType('w'), 'FileSaver'), + (FileType('wt'), 'FileSaver'), + (FileType('wb'), 'FileSaver'), + (FileType('a'), 'FileSaver'), + (FileType('x'), 'FileSaver'), + (FileType('+'), 'FileSaver'), + ] + + for filetype, expected_widget in cases: + with self.subTest(f'expect {filetype} to produce {expected_widget})'): + parser = ArgumentParser() + parser.add_argument('foo', type=filetype) + action = [parser._actions[-1]] + result = next(argparse_to_json.categorize(action, {}, {})) + self.assertEqual(result['type'], expected_widget) +