You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
8.5 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. from argparse import ArgumentParser, _SubParsersAction
  2. from argparse import _MutuallyExclusiveGroup, _ArgumentGroup
  3. class GooeySubParser(_SubParsersAction):
  4. def __init__(self, *args, **kwargs):
  5. super(GooeySubParser, self).__init__(*args, **kwargs)
  6. # TODO: figure out how to correctly dispatch all of these
  7. # so that the individual wrappers aren't needed
  8. class GooeyArgumentGroup(_ArgumentGroup):
  9. def __init__(self, parser, widgets, options, *args, **kwargs):
  10. self.parser = parser
  11. self.widgets = widgets
  12. self.options = options
  13. super(GooeyArgumentGroup, self).__init__(self.parser, *args, **kwargs)
  14. def add_argument(self, *args, **kwargs):
  15. widget = kwargs.pop('widget', None)
  16. metavar = kwargs.pop('metavar', None)
  17. options = kwargs.pop('gooey_options', None)
  18. action = super(GooeyArgumentGroup, self).add_argument(*args, **kwargs)
  19. self.parser._actions[-1].metavar = metavar
  20. self.widgets[self.parser._actions[-1].dest] = widget
  21. self.options[self.parser._actions[-1].dest] = options
  22. return action
  23. def add_argument_group(self, *args, **kwargs):
  24. options = kwargs.pop('gooey_options', {})
  25. group = GooeyArgumentGroup(self.parser, self.widgets, self.options, *args, **kwargs)
  26. group.gooey_options = options
  27. self._action_groups.append(group)
  28. return group
  29. def add_mutually_exclusive_group(self, *args, **kwargs):
  30. options = kwargs.pop('gooey_options', {})
  31. container = self
  32. group = GooeyMutuallyExclusiveGroup(container, self.parser, self.widgets, self.options, *args, **kwargs)
  33. group.gooey_options = options
  34. self.parser._mutually_exclusive_groups.append(group)
  35. return group
  36. class GooeyMutuallyExclusiveGroup(_MutuallyExclusiveGroup):
  37. def __init__(self, container, parser, widgets, options, *args, **kwargs):
  38. self.parser = parser
  39. self.widgets = widgets
  40. self.options = options
  41. super(GooeyMutuallyExclusiveGroup, self).__init__(container, *args, **kwargs)
  42. def add_argument(self, *args, **kwargs):
  43. widget = kwargs.pop('widget', None)
  44. metavar = kwargs.pop('metavar', None)
  45. options = kwargs.pop('gooey_options', None)
  46. super(GooeyMutuallyExclusiveGroup, self).add_argument(*args, **kwargs)
  47. self.parser._actions[-1].metavar = metavar
  48. self.widgets[self.parser._actions[-1].dest] = widget
  49. self.options[self.parser._actions[-1].dest] = options
  50. class MyArgumentParser(ArgumentParser):
  51. def __init__(self, **kwargs):
  52. self._errors = []
  53. super(MyArgumentParser, self).__init__(**kwargs)
  54. def error(self, message):
  55. self._errors.append(message)
  56. def lift_relevant(**kwargs):
  57. """
  58. Lifts the user's (likely) partial function into
  59. total one of type `String -> Either Error a`
  60. """
  61. try:
  62. # Not all Parser Actions accept a type function. Rather
  63. # than track what allows what explicitly, we just try to
  64. # pass the `type` var to constructor. If is doesn't
  65. # explode, then we're good and we use the lifted type. Otherwise
  66. # we use the original kwargs
  67. p = ArgumentParser()
  68. lifted_kwargs = {**kwargs, 'type': lift(kwargs.get('type', identity))}
  69. p.add_argument('-a', **lifted_kwargs)
  70. return lifted_kwargs
  71. except TypeError as e:
  72. return kwargs
  73. def cls_wrapper(cls, **options):
  74. def inner(*args, **kwargs):
  75. class ActionWrapper(cls):
  76. def __call__(self, p, namespace, values, option_string, **qkwargs):
  77. # print('hello from', options, namespace, values, option_string, qkwargs)
  78. super(ActionWrapper, self).__call__(p, namespace, values, option_string, **qkwargs)
  79. return ActionWrapper(*args, **kwargs)
  80. return inner
  81. class GooeyParser(object):
  82. def __init__(self, **kwargs):
  83. on_success = kwargs.pop('on_success', None)
  84. on_error = kwargs.pop('on_error', None)
  85. self.__dict__['parser'] = ArgumentParser(**kwargs)
  86. self.widgets = {}
  87. self.options = {}
  88. self.on_gooey_success = on_success
  89. self.on_gooey_error = on_error
  90. if 'parents' in kwargs:
  91. for parent in kwargs['parents']:
  92. if isinstance(parent, self.__class__):
  93. self.widgets.update(parent.widgets)
  94. self.options.update(parent.options)
  95. @property
  96. def _mutually_exclusive_groups(self):
  97. return self.parser._mutually_exclusive_groups
  98. @property
  99. def _actions(self):
  100. return self.parser._actions
  101. @property
  102. def description(self):
  103. return self.parser.description
  104. def add_argument(self, *args, **kwargs):
  105. widget = kwargs.pop('widget', None)
  106. metavar = kwargs.pop('metavar', None)
  107. options = kwargs.pop('gooey_options', None)
  108. # TODO: move this to the control module. No need to do it
  109. # at creation time.
  110. # lifted_kwargs = lift_relevant(**kwargs)
  111. #
  112. # action_cls = self.parser._pop_action_class(kwargs)
  113. # enhanced_action = cls_wrapper(action_cls, **(options if options else {}))
  114. #
  115. # action = self.parser.add_argument(*args, **{**lifted_kwargs, 'action': enhanced_action})
  116. action = self.parser.add_argument(*args, **kwargs)
  117. self.parser._actions[-1].metavar = metavar
  118. action_dest = self.parser._actions[-1].dest
  119. if action_dest not in self.widgets or self.widgets[action_dest] is None:
  120. self.widgets[action_dest] = widget
  121. if action_dest not in self.options or self.options[action_dest] is None:
  122. self.options[self.parser._actions[-1].dest] = options
  123. self._validate_constraints(
  124. self.parser._actions[-1],
  125. widget,
  126. options or {},
  127. **kwargs
  128. )
  129. return action
  130. def add_mutually_exclusive_group(self, *args, **kwargs):
  131. options = kwargs.pop('gooey_options', {})
  132. group = GooeyMutuallyExclusiveGroup(self, self.parser, self.widgets, self.options, *args, **kwargs)
  133. group.gooey_options = options
  134. self.parser._mutually_exclusive_groups.append(group)
  135. return group
  136. def add_argument_group(self, *args, **kwargs):
  137. options = kwargs.pop('gooey_options', {})
  138. group = GooeyArgumentGroup(self.parser, self.widgets, self.options, *args, **kwargs)
  139. group.gooey_options = options
  140. self.parser._action_groups.append(group)
  141. return group
  142. def parse_args(self, args=None, namespace=None):
  143. return self.parser.parse_args(args, namespace)
  144. def add_subparsers(self, **kwargs):
  145. if self._subparsers is not None:
  146. self.error(_('cannot have multiple subparser arguments'))
  147. # add the parser class to the arguments if it's not present
  148. kwargs.setdefault('parser_class', type(self))
  149. if 'title' in kwargs or 'description' in kwargs:
  150. title = kwargs.pop('title', 'subcommands')
  151. description = kwargs.pop('description', None)
  152. self._subparsers = self.add_argument_group(title, description)
  153. else:
  154. self._subparsers = self._positionals
  155. # prog defaults to the usage message of this parser, skipping
  156. # optional arguments and with no "usage:" prefix
  157. if kwargs.get('prog') is None:
  158. formatter = self._get_formatter()
  159. positionals = self._get_positional_actions()
  160. groups = self._mutually_exclusive_groups
  161. formatter.add_usage(self.usage, positionals, groups, '')
  162. kwargs['prog'] = formatter.format_help().strip()
  163. # create the parsers action and add it to the positionals list
  164. parsers_class = self._pop_action_class(kwargs, 'parsers')
  165. action = parsers_class(option_strings=[], **kwargs)
  166. self._subparsers._add_action(action)
  167. # return the created parsers action
  168. return action
  169. def _validate_constraints(self, parser_action, widget, options, **kwargs):
  170. from gooey.python_bindings import constraints
  171. constraints.assert_listbox_constraints(widget, **kwargs)
  172. constraints.assert_visibility_requirements(parser_action, options)
  173. def __getattr__(self, item):
  174. return getattr(self.parser, item)
  175. def __setattr__(self, key, value):
  176. return setattr(self.parser, key, value)