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.

226 lines
7.0 KiB

  1. import os
  2. from collections import OrderedDict, namedtuple
  3. from itertools import chain
  4. from gooey.gui.lang.i18n import _
  5. from gooey.gui.util.quoting import quote
  6. # class ArgumentGroup(object):
  7. # def __init__(self, name, data):
  8. # self.name = name
  9. # self.command = data['command']
  10. # self.required_args = data['contents']
  11. # self.optional_args = data['contents']
  12. ArgumentGroup = namedtuple('ArgumentGroup', 'name command required_args optional_args')
  13. class MyWidget(object):
  14. def __init__(self, type, title, help, default, nargs, commands, choices):
  15. self.type = type
  16. self.title = title
  17. self.help = help
  18. self.default = default
  19. self._value = default
  20. self.nargs = nargs
  21. self.commands = commands
  22. self.choices = choices
  23. @property
  24. def value(self):
  25. # TODO: split into stategy or subclass thingie
  26. if self.type == 'CheckBox':
  27. return self.commands[0] if self._value else None
  28. if self.type == 'RadioGroup':
  29. try:
  30. return self.commands[self._value.index(True)][0]
  31. except ValueError:
  32. return None
  33. if self.type == 'MultiFileChooser':
  34. value = ' '.join(quote(x) for x in self._value.split(os.pathsep) if x)
  35. if self.commands and value:
  36. return '{} {}'.format(self.commands[0], value)
  37. return value or None
  38. # if self.type == 'TextField':
  39. # if self.commands and self._value:
  40. # return '{} {}'.format(self.commands[0], quote(self._value))
  41. # else:
  42. # return quote(self._value) if self._value else ''
  43. if self.type == 'CommandField':
  44. if self.commands and self._value:
  45. return '{} {}'.format(self.commands[0], self._value)
  46. else:
  47. return self._value or None
  48. if self.type == 'Counter':
  49. '''
  50. Returns
  51. str(option_string * DropDown Value)
  52. e.g.
  53. -vvvvv
  54. '''
  55. if not str(self._value).isdigit():
  56. return None
  57. arg = str(self.commands[0]).replace('-', '')
  58. repeated_args = arg * int(self._value)
  59. return '-' + repeated_args
  60. if self.type == 'Dropdown':
  61. if self._value == self.default:
  62. return ''
  63. elif self.commands and self._value:
  64. return '{} {}'.format(self.commands[0], quote(self._value))
  65. else:
  66. return quote(self._value) if self._value else ''
  67. else:
  68. if self.commands and self._value:
  69. return '{0} {1}'.format(self.commands[0], quote(self._value))
  70. else:
  71. return quote(self._value) if self._value else None
  72. @value.setter
  73. def value(self, val):
  74. self._value = val
  75. class States(object):
  76. CONFIGURING = 'configuring'
  77. RUNNNING = 'running'
  78. SUCCESS = 'success'
  79. ERROR = 'error'
  80. STOPPED = 'stopped'
  81. class MyModel(object):
  82. '''
  83. '''
  84. def wrap(self, groups):
  85. output = OrderedDict()
  86. for name, group in groups.items():
  87. output[name] = ArgumentGroup(
  88. name,
  89. group['command'],
  90. *self.group_arguments(group['contents'])
  91. )
  92. return output
  93. def __init__(self, build_spec):
  94. self.current_state = States.CONFIGURING
  95. self.build_spec = build_spec
  96. self.layout_type = self.build_spec.get('layout_type')
  97. self.auto_start = self.build_spec.get('auto_start')
  98. self.progress_regex = self.build_spec.get('progress_regex')
  99. self.progress_expr = self.build_spec.get('progress_expr')
  100. self.program_name = self.build_spec.get('program_name')
  101. self.default_size = self.build_spec.get('default_size')
  102. self.heading_title = _("settings_title")
  103. self.heading_subtitle = self.build_spec['program_description'] or ''
  104. self.use_monospace_font = self.build_spec.get('monospace_display')
  105. self.stop_button_disabled = self.build_spec['disable_stop_button']
  106. self.argument_groups = self.wrap(self.build_spec.get('widgets', {}))
  107. self.active_group = iter(self.argument_groups).next()
  108. self.text_states = {
  109. States.CONFIGURING: {
  110. 'title': _("settings_title"),
  111. 'subtitle': self.build_spec['program_description'] or ''
  112. },
  113. States.RUNNNING: {
  114. 'title': _("running_title"),
  115. 'subtitle': _('running_msg')
  116. },
  117. States.SUCCESS: {
  118. 'title': _('finished_title'),
  119. 'subtitle': _('finished_msg')
  120. },
  121. States.ERROR: {
  122. 'title': _('finished_title'),
  123. 'subtitle': _('finished_error')
  124. }
  125. }
  126. @property
  127. def required_args(self):
  128. return self.argument_groups[self.active_group].required_args
  129. @property
  130. def optional_args(self):
  131. return self.argument_groups[self.active_group].optional_args
  132. def update_state(self, state):
  133. self.current_state = state
  134. text = self.text_states[state]
  135. self.heading_title = text['title']
  136. self.heading_subtitle = text['subtitle']
  137. def is_valid(self):
  138. # TODO: fix skipping_config.. whatever that did
  139. # currently breaks when you supply it as a decorator option
  140. # return self.skipping_config() and self.required_section_complete()
  141. return self.is_required_section_complete()
  142. def skipping_config(self):
  143. return self.build_spec['manual_start']
  144. def is_required_section_complete(self):
  145. completed_values = filter(None, [arg.value for arg in self.required_args])
  146. return len(self.required_args) == len(completed_values)
  147. def build_command_line_string(self):
  148. optional_args = [arg.value for arg in self.optional_args]
  149. required_args = [c.value for c in self.required_args if c.commands]
  150. position_args = [c.value for c in self.required_args if not c.commands]
  151. if position_args:
  152. position_args.insert(0, "--")
  153. cmd_string = ' '.join(filter(None, chain(required_args, optional_args, position_args)))
  154. return '{} --ignore-gooey {}'.format(self.build_spec['target'], cmd_string)
  155. def group_arguments(self, widget_list):
  156. is_required = lambda widget: widget['required']
  157. not_checkbox = lambda widget: widget['type'] != 'CheckBox'
  158. required_args, optional_args = self.partition(widget_list, is_required)
  159. if self.build_spec['group_by_type']:
  160. optional_args = chain(*self.partition(optional_args, not_checkbox))
  161. return map(self.to_object, required_args), map(self.to_object, optional_args)
  162. @staticmethod
  163. def partition(collection, condition):
  164. return filter(condition, collection), filter(lambda x: not condition(x), collection)
  165. def to_object(self, data):
  166. details = data['data']
  167. return MyWidget(
  168. data['type'],
  169. self.maybe_unpack(details, 'display_name'),
  170. self.maybe_unpack(details, 'help'),
  171. self.maybe_unpack(details, 'default'),
  172. self.maybe_unpack(details, 'nargs'),
  173. self.maybe_unpack(details, 'commands'),
  174. self.maybe_unpack(details, 'choices')
  175. )
  176. @staticmethod
  177. def maybe_unpack(collection, attr):
  178. # TODO: RadioGroups need to support defaults
  179. try:
  180. if isinstance(collection, list):
  181. return [item[attr] for item in collection]
  182. return collection[attr]
  183. except:
  184. return None