Browse Source

Added GooeyParser - wrapper for Argparse to allow custom widget desclarations

pull/61/head
chriskiehl 10 years ago
parent
commit
c0318c7e97
7 changed files with 120 additions and 66 deletions
  1. 19
      gooey/_tmp/mockapp.py
  2. 7
      gooey/gui/controller.py
  3. 2
      gooey/gui/windows/base_window.py
  4. 18
      gooey/mockapplications/mockapp.py
  5. 87
      gooey/python_bindings/argparse_to_json.py
  6. 50
      gooey/python_bindings/gooey_decorator.py
  7. 3
      gooey/python_bindings/source_parser.py

19
gooey/_tmp/mockapp.py

@ -5,15 +5,15 @@ Created on Dec 21, 2013
'''
import sys
import hashlib
from time import time as _time
from time import time as _time, time
from time import sleep as _sleep
# from argparse import ArgumentParser
# import argparse
import argparse as ap
from argparse import ArgumentParser as AP
a = globals()
from gooey import Gooey
from gooey.python_bindings.gooey_decorator import GooeyParser
def main():
@ -22,9 +22,9 @@ def main():
'''
desc = "Mock application to test Gooey's functionality"
file_help_msg = "Name of the file you want to process"
my_cool_parser = ap.ArgumentParser(description=desc)
my_cool_parser.add_argument("filename", help=file_help_msg, metavar='asdf') # positional
my_cool_parser.add_argument("outfile", help="Name of the file where you'll save the output") # positional
my_cool_parser = GooeyParser(description=desc)
my_cool_parser.add_argument("filename", help=file_help_msg, widget="FileChooser") # positional
my_cool_parser.add_argument("outfile", help="Name of the file where you'll save the output", widget="FileChooser") # positional
my_cool_parser.add_argument('-c', '--countdown', default=10, type=int, help='sets the time to count down from you see its quite simple!')
my_cool_parser.add_argument("-s", "--showtime", action="store_true", help="display the countdown timer")
my_cool_parser.add_argument("-d", "--delay", action="store_true", help="Delay execution for a bit")
@ -36,8 +36,10 @@ def main():
verbosity = my_cool_parser.add_mutually_exclusive_group()
verbosity.add_argument('-t', '--verbozze', dest='verbose', action="store_true", help="Show more details")
verbosity.add_argument('-q', '--quiet', dest='quiet', action="store_true", help="Only output on error")
print my_cool_parser._actions
print 'inside of main(), my_cool_parser =', my_cool_parser
args = my_cool_parser.parse_args()
print sys.argv
@ -53,8 +55,11 @@ def main():
print 'printing message at: %s' % hashlib.md5(str(_time())).hexdigest()
_sleep(.5)
print 'Finished running the program. Byeeeeesss!'
raise ValueError("Something has gone wrong! AHHHHHHHHHHH")
def here_is_smore():
pass
# raise ValueError("Something has gone wrong! AHHHHHHHHHHH")
if __name__ == '__main__':
print sys.argv

7
gooey/gui/controller.py

@ -55,10 +55,11 @@ class Controller(object):
self.ShowDialog(i18n.translate('error_title'), "Must fill in all fields in the Required section!", wx.ICON_ERROR)
return
command = '{0} {1}'.format(self.build_spec['target'], cmd_line_args)
self.core_gui.NextPage()
self.RunClientCode(None)
self.RunClientCode(command)
def RunClientCode(self, process):
def RunClientCode(self, command):
def doInBackground(process, callback):
while True:
line = process.stdout.readline()
@ -67,7 +68,7 @@ class Controller(object):
self.core_gui.PublishConsoleMsg(line)
callback(process)
p = subprocess.Popen(r'python C:\Users\Chris\Desktop\Untitled\prog.py', bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p = subprocess.Popen(command, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
_pool = Pool(1)
_pool.apply_async(doInBackground, (p, self.HandleResult))

2
gooey/gui/windows/base_window.py

@ -55,7 +55,7 @@ class BaseWindow(wx.Frame):
_desc = self.build_spec['program_description']
self.head_panel = header.FrameHeader(
heading=i18n.translate("settings_title"),
subheading=_desc if _desc is not None else '',
subheading=_desc or '',
parent=self)
self.config_panel = BodyPanel(self)
self.runtime_display = RuntimeDisplay(self)

18
gooey/mockapplications/mockapp.py

@ -5,7 +5,7 @@ Created on Dec 21, 2013
'''
import sys
import hashlib
from time import time as _time
from time import time as _time, time
from time import sleep as _sleep
# from argparse import ArgumentParser
# import argparse
@ -13,8 +13,7 @@ import argparse as ap
from argparse import ArgumentParser as AP
from gooey import Gooey
a = globals()
from gooey.python_bindings.gooey_decorator import GooeyParser
@Gooey
@ -24,9 +23,9 @@ def main():
'''
desc = "Mock application to test Gooey's functionality"
file_help_msg = "Name of the file you want to process"
my_cool_parser = ap.ArgumentParser(description=desc)
my_cool_parser.add_argument("filename", help=file_help_msg, metavar='asdf') # positional
my_cool_parser.add_argument("outfile", help="Name of the file where you'll save the output") # positional
my_cool_parser = GooeyParser(description=desc)
my_cool_parser.add_argument("filename", help=file_help_msg, widget="FileChooser") # positional
my_cool_parser.add_argument("outfile", help="Name of the file where you'll save the output", widget="FileChooser") # positional
my_cool_parser.add_argument('-c', '--countdown', default=10, type=int, help='sets the time to count down from you see its quite simple!')
my_cool_parser.add_argument("-s", "--showtime", action="store_true", help="display the countdown timer")
my_cool_parser.add_argument("-d", "--delay", action="store_true", help="Delay execution for a bit")
@ -38,8 +37,10 @@ def main():
verbosity = my_cool_parser.add_mutually_exclusive_group()
verbosity.add_argument('-t', '--verbozze', dest='verbose', action="store_true", help="Show more details")
verbosity.add_argument('-q', '--quiet', dest='quiet', action="store_true", help="Only output on error")
print my_cool_parser._actions
print 'inside of main(), my_cool_parser =', my_cool_parser
args = my_cool_parser.parse_args()
print sys.argv
@ -55,8 +56,11 @@ def main():
print 'printing message at: %s' % hashlib.md5(str(_time())).hexdigest()
_sleep(.5)
print 'Finished running the program. Byeeeeesss!'
raise ValueError("Something has gone wrong! AHHHHHHHHHHH")
def here_is_smore():
pass
# raise ValueError("Something has gone wrong! AHHHHHHHHHHH")
if __name__ == '__main__':
print sys.argv

87
gooey/python_bindings/argparse_to_json.py

@ -7,33 +7,42 @@ from argparse import (
_HelpAction,
_StoreConstAction,
_StoreFalseAction,
_StoreTrueAction
)
_StoreTrueAction,
ArgumentParser)
import itertools
VALID_WIDGETS = (
'@FileChooser',
'@DirChooser',
'@DateChooser',
'@TextField',
'@Dropdown',
'@Counter',
'@RadioGroup'
'FileChooser',
'DirChooser',
'DateChooser',
'TextField',
'Dropdown',
'Counter',
'RadioGroup',
'CheckBox'
)
class UnknownWidgetType(Exception):
pass
def convert(argparser):
def convert(parser):
widget_dict = getattr(parser, 'widgets', None)
mutually_exclusive_group = [
mutex_action
for group_actions in argparser._mutually_exclusive_groups
for group_actions in parser._mutually_exclusive_groups
for mutex_action in group_actions._group_actions]
base_actions = [action for action in argparser._actions
base_actions = [(action, widget_dict.get(action.dest, None))
for action in parser._actions
if action not in mutually_exclusive_group]
positional_args = get_required_and_positional_args(base_actions)
choice_args = get_optionals_with_choices(base_actions)
@ -63,12 +72,13 @@ def get_required_and_positional_args(actions):
In argparse, positionals are defined by either an empty option_strings
or by the option_strings parameters being sans a leading hyphen
"""
filtered_actions = [action for action in actions
if not action.option_strings
or action.required == True]
filtered_actions = [(action, widget)
for action, widget in actions
if not action.option_strings
or action.required == True]
return [as_json(action, default_widget='TextField')
for action in filtered_actions]
return [as_json(action, widget=widget or 'TextField')
for action, widget in filtered_actions]
def get_optionals_with_choices(actions):
@ -76,12 +86,12 @@ def get_optionals_with_choices(actions):
All optional arguments which are constrained
to specific choices.
"""
filtered_actions = [action
for action in actions
filtered_actions = [(action, widget)
for action, widget in actions
if action.choices]
return [as_json(action, default_widget='Dropdown')
for action in filtered_actions]
return [as_json(action, widget=widget or 'Dropdown')
for action, widget in filtered_actions]
def get_optionals_without_choices(actions):
@ -99,8 +109,8 @@ def get_optionals_without_choices(actions):
_StoreTrueAction
)
filtered_actions = [
action
for action in actions
(action, widget)
for action, widget in actions
if action.option_strings
and not action.choices
and not isinstance(action, _CountAction)
@ -108,8 +118,8 @@ def get_optionals_without_choices(actions):
and type(action) not in boolean_actions
]
return [as_json(action, default_widget='TextField')
for action in filtered_actions]
return [as_json(action, widget=widget or 'TextField')
for action, widget in filtered_actions]
def get_flag_style_optionals(actions):
@ -123,27 +133,27 @@ def get_flag_style_optionals(actions):
_StoreConst
"""
filtered_actions = [
action
for action in actions
(action, widget)
for action, widget in actions
if isinstance(action, _StoreTrueAction)
or isinstance(action, _StoreFalseAction)
or isinstance(action, _StoreConstAction)
]
return [as_json(action, default_widget='CheckBox')
for action in filtered_actions]
return [as_json(action, widget=widget or 'CheckBox')
for action, widget in filtered_actions]
def get_counter_style_optionals(actions):
"""
Returns all instances of type _CountAction
"""
filtered_actions = [action
for action in actions
filtered_actions = [(action, widget)
for action, widget in actions
if isinstance(action, _CountAction)]
_json_options = [as_json(action, default_widget='Counter')
for action in filtered_actions]
_json_options = [as_json(action, widget=widget or 'Counter')
for action, widget in filtered_actions]
# Counter should show as Dropdowns, so pre-populare with numeric choices
for opt in _json_options:
@ -172,12 +182,15 @@ def get_mutually_exclusive_optionals(mutex_group):
}]
def as_json(action, default_widget):
def as_json(action, widget):
print 'widget:', widget
if widget not in VALID_WIDGETS:
raise UnknownWidgetType('Widget Type {0} is unrecognized'.format(widget))
option_strings = action.option_strings
_type = option_strings[-1] if option_strings else None
return {
'type': widget_type(_type) if is_widget_spec(_type) else default_widget,
'data' : {
'type': widget,
'data': {
'display_name': action.dest,
'help': action.help,
'nargs': action.nargs or '',

50
gooey/python_bindings/gooey_decorator.py

@ -41,11 +41,13 @@ to us. No more complicated ast stuff. Just a little bit of string parsing and we
done.
'''
from argparse import ArgumentParser
from argparse import ArgumentParser as RealArgParser, ArgumentParser
from functools import partial
import os
import sys
import types
import wx
@ -57,7 +59,6 @@ import source_parser
ROOT_DIR = os.path.dirname(__import__(__name__.split('.')[0]).__file__)
TMP_DIR = os.path.join(ROOT_DIR, '_tmp')
def Gooey(f=None, advanced=True,
language='english', show_config=True,
program_name=None, program_description=None):
@ -142,13 +143,7 @@ def clean_source(module_path):
with open(module_path, 'r') as f:
return ''.join(
line for line in f.readlines()
if '@gooey' not in line.lower()
and 'import gooey' not in line.lower())
def run():
parser = source_parser.extract_parser(module_path)
client_module = create_cleaned_backup()
if '@gooey' not in line.lower())
def get_parser(module_path):
@ -159,5 +154,42 @@ def get_caller_path():
return tmp_sys.argv[0]
class GooeyParser(object):
def __init__(self, **kwargs):
self.__dict__['parser'] = ArgumentParser(**kwargs)
self.widgets = {}
@property
def _mutually_exclusive_groups(self):
return self.parser._mutually_exclusive_groups
@property
def _actions(self):
return self.parser._actions
@property
def description(self):
return self.parser.description
def add_argument(self, *args, **kwargs):
widget = kwargs.pop('widget', None)
self.parser.add_argument(*args, **kwargs)
self.widgets[self.parser._actions[-1].dest] = widget
def add_mutually_exclusive_group(self, **kwargs):
return self.parser.add_mutually_exclusive_group(**kwargs)
def add_argument_group(self, *args, **kwargs):
return self.parser.add_argument_group(*args, **kwargs)
def parse_args(self, args=None, namespace=None):
return self.parser.parse_args(args, namespace)
def __getattr__(self, item):
return getattr(self.parser, item)
def __setattr__(self, key, value):
return setattr(self.parser, key, value)
if __name__ == '__main__':
pass

3
gooey/python_bindings/source_parser.py

@ -123,8 +123,7 @@ def format_source_to_return_parser(source, cutoff_line, restart_line, col_offset
# stitch it all back together excluding the Gooey decorator
new_source = (line for line in chain(top, return_statement, bottom)
if '@gooey' not in line.lower()
and 'import gooey' not in line.lower())
if '@gooey' not in line.lower())
return ''.join(new_source)

Loading…
Cancel
Save