From 553f590e39a30f82ca1374d95d42a37d3cf2942b Mon Sep 17 00:00:00 2001 From: Chris Kiehl Date: Tue, 7 Jan 2014 01:07:30 -0500 Subject: [PATCH] Nightly work. --- src/app/dialogs/action_sorter.py | 40 +++++++---- src/app/dialogs/advanced_config.py | 47 +++++-------- src/app/dialogs/advanced_config.pyc | Bin 899 -> 1914 bytes src/app/dialogs/advanced_config_unittest.py | 41 +++++++++++ src/app/dialogs/component_factory.py | 74 +++++++++++--------- src/app/dialogs/component_factory.pyc | Bin 5939 -> 2725 bytes src/app/dialogs/components.py | 68 +++++++++++++----- src/app/dialogs/components_unittest.py | 23 ++++-- 8 files changed, 192 insertions(+), 101 deletions(-) create mode 100644 src/app/dialogs/advanced_config_unittest.py diff --git a/src/app/dialogs/action_sorter.py b/src/app/dialogs/action_sorter.py index 48ef84e..6296bf0 100644 --- a/src/app/dialogs/action_sorter.py +++ b/src/app/dialogs/action_sorter.py @@ -2,6 +2,7 @@ Created on Dec 8, 2013 @author: Chris + ''' import wx @@ -10,12 +11,14 @@ from argparse import ( _StoreFalseAction, _StoreTrueAction, _CountAction, _AppendAction) + +DEBUG = 1 + class ActionSorter(object): ''' - So this thing is the thing that will - pull out all of the "types" from the - argparse object and turn them into the - correct wx components + Sorts all of the actions into their appropriate containers. + + Containers are based on the following map: COMPONENT MAP Action WxWidget @@ -27,7 +30,16 @@ class ActionSorter(object): append TextCtrl count DropDown choice DropDown - + + Instance Variables: + self._positionals + self._choices + self._optionals + self._flags + self._counters + + Example Argparse Def + _HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None) _StoreAction(option_strings=[], dest='filename', nargs=None, const=None, default=None, type=None, choices=None, help='filename', metavar=None) _StoreTrueAction(option_strings=['-r', '--recursive'], dest='recurse', nargs=0, const=True, default=False, type=None, choices=None, help='recurse into subfolders [default: %(default)s]', metavar=None) @@ -40,21 +52,21 @@ class ActionSorter(object): usage: example_argparse_souce.py [-h] [-r] [-v] [-i RE] [-e RE] [-V] ''' - def __init__(self, parser): - self._parser = parser - self._actions = self._parser._actions[:] # Copy all of the actions + def __init__(self, actions): + self._actions = actions[:] # Copy all of the actions self._positionals = self.get_positionals(self._actions) self._choices = self.get_optionals_with_choices(self._actions) self._optionals = self.get_optionals_without_choices(self._actions) - self._booleans = self.get_flag_style_optionals(self._actions) + self._flags = self.get_flag_style_optionals(self._actions) self._counters = self.get_counter_actions(self._actions) - self._display('ActionSorter: positionals', self._positionals) - self._display('ActionSorter: choices', self._choices) - self._display('ActionSorter: optionals', self._optionals) - self._display('ActionSorter: booleans', self._booleans) - self._display('ActionSorter: counters', self._counters) + if DEBUG: + self._display('ActionSorter: positionals', self._positionals) + self._display('ActionSorter: choices', self._choices) + self._display('ActionSorter: optionals', self._optionals) + self._display('ActionSorter: booleans', self._flags) + self._display('ActionSorter: counters', self._counters) def _display(self, _type, something): for i in something: diff --git a/src/app/dialogs/advanced_config.py b/src/app/dialogs/advanced_config.py index d688968..e32e984 100644 --- a/src/app/dialogs/advanced_config.py +++ b/src/app/dialogs/advanced_config.py @@ -5,59 +5,48 @@ Created on Dec 28, 2013 ''' import wx + +from component_factory import ComponentFactory from wx.lib.scrolledpanel import ScrolledPanel + + class AdvancedConfigPanel(ScrolledPanel): ''' Abstract class for the Footer panels. ''' - def __init__(self, parent, **kwargs): + def __init__(self, parent, parser, **kwargs): ScrolledPanel.__init__(self, parent, **kwargs) self.SetupScrolling() - self.components = [] + self.components = ComponentFactory(parser) self.container = wx.BoxSizer(wx.VERTICAL) self.container.AddSpacer(10) + self.AddRequiredArgsHeaderMsg() - self.Add + self.AddWidgets(self.components.positionals) + + self.SetSizer(self.container) - def AddRequiredArgsHeaderMsg(self): required_msg = wx.StaticText(self, label="Required Arguments") self.container.Add(required_msg, 0, wx.LEFT | wx.RIGHT, 20) - def AddWidgets(self, actions, widget_type): - if len(actions) == 0: - return - action = actions.pop(0) - self.CreateHelpMsgWidget(action) - if self.hasNargs(action): - self.AddNargsMsg(action) - self.AddWidget(widget_type) - self.AddWidgets(actions, widget_type) + def AddWidgets(self, components): + if not components: + return + component = components[0] + widget_group = component.Build(parent=self) + self.container.Add(widget_group) + self.AddWidgets(components[1:]) - def CreateHelpMsgWidget(self, action): - help_msg = action.help - return wx.StaticText(self, label=help_msg) - - def HasNargs(self, action): - return action.nargs > 0 - - def AddNargsMsg(self, action): - msg = action.nargs - return wx.StaticText(self, label=msg) - - def AddWidget(self, _type): - widget = getattr(wx, _type) if __name__ == '__main__': - a = getattr(wx, 'StaticText') - print a - + pass diff --git a/src/app/dialogs/advanced_config.pyc b/src/app/dialogs/advanced_config.pyc index b54f7cb1f56e774088b59a69ff4100afd0610839..aa35c90763cde28719d85aac50021a844ca813b2 100644 GIT binary patch literal 1914 zcmcIl-EJF26h5D8~pIs-%(1dUjzRiquJLm8PO0{ zQRY#uXb1;?4az;5HE7r%#j#JhPqQWsn~0mFn>0pmi~bAU4tFXp( zVEW~3UKYA=$4TnS>arf$#mFG7$~@QE_er61w~wA)_G?n4I_sCk*i58@+DFbbVfOA0}w`&aA7DM40A@wc)s|LU*piNk4^hhC?dW@cO4Z4CS^JcG4@W;@f*pzKMo+48epW6=^GZ8+8BZ2w^sFrP<;Yg) zD4EYknMv|;Vn@kJVsR=OJDgueOgF2~vRp~+tH9gy4pher)V`N8$c$GLt&e6O!ED69 zmBqxXYvCSpm_iEZY{(o)0o*p}DD&yYU(v`roj@W)d2$BL-G#SCGX$KA89=ZGy=2~j z=`sir8-aJ=5@*s=y>t;11L+Ang5=Am$EUJ$^y1m`QxQzG$CGwosug4L%ua3(O{V-4 zG|SAAI#4O2#{nlQ2y#sUBO7o94;U>)?_YadLQ{EnP!Knyu7M=bQ(RbF5XQgRBr8Nc1r-lc3bKe?V`+o~OT}WZ(neyE6OWjL%YuT}ovlUK7xEc= z4=W4NMrXu@`Lo|Q^PBI%awQ2q*5jY_)#mtr0oO4{m-fki5~2(+B@_{!fhBNx6{1j> z7~Mae^l!(s>jyLp?Zhab($Tr%RY8OtXM#E4WsE^F5rfjjZLvYI;0O`FZx@n5Rkk?R}ci4NMLSeekjM~9^R zr_N5T;8$fp2s+SYB5thQaI*aH=(hjLsJgoub@{xhsE&Y D;8Zy? diff --git a/src/app/dialogs/advanced_config_unittest.py b/src/app/dialogs/advanced_config_unittest.py new file mode 100644 index 0000000..3942a35 --- /dev/null +++ b/src/app/dialogs/advanced_config_unittest.py @@ -0,0 +1,41 @@ +''' +Created on Jan 7, 2014 + +@author: Chris +''' + +import wx +import os +import sys +import unittest +import advanced_config +from argparse import ArgumentParser + +class Test(unittest.TestCase): + + + def setUp(self): + parser = ArgumentParser(description='Example Argparse Program') + parser.add_argument("filename", help="Name of the file you want to read") + parser.add_argument('-T', '--tester', choices=['yes','no']) + parser.add_argument('-o', '--outfile', help='Redirects output to the specified file') + parser.add_argument('-v', '--verbose', help='Toggles verbosity off') + parser.add_argument('-e', '--repeat', action='count', help='Set the number of times to repeat') + self.parser = parser + + def buildWindow(self): + app = wx.PySimpleApp() + module_name = os.path.split(sys.argv[0])[-1] + frame = wx.Frame(None, -1, module_name) + + panel = advanced_config.AdvancedConfigPanel(frame, self.parser) + frame.Show() + app.MainLoop() + + def testAdvancedConfigPanel(self): + self.buildWindow() + + +if __name__ == "__main__": + #import sys;sys.argv = ['', 'Test.testName'] + unittest.main() \ No newline at end of file diff --git a/src/app/dialogs/component_factory.py b/src/app/dialogs/component_factory.py index 443bcbc..98f1af8 100644 --- a/src/app/dialogs/component_factory.py +++ b/src/app/dialogs/component_factory.py @@ -5,48 +5,54 @@ Created on Dec 8, 2013 ''' import wx -from argparse import ( - _StoreAction, _StoreConstAction, - _StoreFalseAction, _StoreTrueAction, - _CountAction, _AppendAction) +import components +import action_sorter + class ComponentFactory(object): ''' - Generates Wx Components from the argparse action types - - COMPONENT MAP - Action WxWidget - -------------------------- - store TextCtrl - store_const CheckBox - store_true CheckBox - store_False CheckBox - append TextCtrl - count DropDown - choice DropDown - - _HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None) - _StoreAction(option_strings=[], dest='filename', nargs=None, const=None, default=None, type=None, choices=None, help='filename', metavar=None) - _StoreTrueAction(option_strings=['-r', '--recursive'], dest='recurse', nargs=0, const=True, default=False, type=None, choices=None, help='recurse into subfolders [default: %(default)s]', metavar=None) - _CountAction(option_strings=['-v', '--verbose'], dest='verbose', nargs=0, const=None, default=None, type=None, choices=None, help='set verbosity level [default: %(default)s]', metavar=None) - _AppendAction(option_strings=['-i', '--include'], dest='include', nargs=None, const=None, default=None, type=None, choices=None, help='only include paths matching this regex pattern. Note: exclude is given preference over include. [default: %(default)s]', metavar='RE') - _StoreAction(option_strings=['-e', '--exclude'], dest='exclude', nargs=None, const=None, default=None, type=None, choices=None, help='exclude paths matching this regex pattern. [default: %(default)s]', metavar='RE') - _VersionAction(option_strings=['-V', '--version'], dest='version', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help="show program's version number and exit", metavar=None) - _StoreAction(option_strings=['-T', '--tester'], dest='tester', nargs=None, const=None, default=None, type=None, choices=['yes', 'no'], help=None, metavar=None) - _StoreAction(option_strings=[], dest='paths', nargs='+', const=None, default=None, type=None, choices=None, help='paths to folder(s) with source file(s) [default: %(default)s]', metavar='path') - usage: example_argparse_souce.py [-h] [-r] [-v] [-i RE] [-e RE] [-V] + Aggregates all of the Widgets and dispatches + them to the caller. ''' def __init__(self, parser): - self._parser = parser - self._actions = self._parser._actions[:] # Copy all of the actions - self._positionals = self.get_positionals(self._actions) - self._choices = self.get_optionals_with_choices(self._actions) - self._optionals = self.get_optionals_without_choices(self._actions) - self._booleans = self.get_flag_style_optionals(self._actions) - self._counters = self.get_counter_actions(self._actions) + self._actions = action_sorter.ActionSorter(parser._actions[:]) + + self.positionals = self.BuildPositionals(self._actions) + self.choices = self.BuildChoices(self._actions) + self.optionals = self.BuildOptionals(self._actions) + self.booleans = self.BuildFlags(self._actions) + self.counters = self.BuildCounters(self._actions) + + self._components = [ + self.positionals, + self.choices, + self.optionals, + self.booleans, + self.counters + ] + + def BuildPositionals(self, actions): + return self._AssembleWidgetsFromActions(actions, 'Positional', '_positionals') + + def BuildChoices(self, actions): + return self._AssembleWidgetsFromActions(actions, 'Choice', '_choices') + + def BuildOptionals(self, actions): + return self._AssembleWidgetsFromActions(actions, 'Optional', '_optionals') + + def BuildFlags(self, actions): + return self._AssembleWidgetsFromActions(actions, 'Flag', '_flags') + + def BuildCounters(self, actions): + return self._AssembleWidgetsFromActions(actions, 'Counter', '_counters') + def _AssembleWidgetsFromActions(self, actions, classname, actiontype): + cls = getattr(components, classname) + actions_list = getattr(actions, actiontype) + return [cls(action) + for action in actions_list] if __name__ == '__main__': diff --git a/src/app/dialogs/component_factory.pyc b/src/app/dialogs/component_factory.pyc index 43005faedd661b3510ed56091099d23e36604946..6c2b340d637e8c687920fc2f75fb93c6d40d4da5 100644 GIT binary patch literal 2725 zcmc&0U2oeq@FdwvtU61ZHF+7Z>0w2UVGH{4Qlv%E)Io*;TRO-niW%w%MWSV;vZ#qP zS_AD<`XBZm_E+|E_5-%NqwFM)3t+?qPj|=T@xFMp_s>>v{O8|M3hmFs?+cuIgdhVL zBXl5hp>$x3h{atPyGz`Iu?Lw4vI7%b?Z9V%bAaE*U64LxU3lk0^9m|dEbjhx9hb$$e+gdti6N$3{na@j`kZmy1gJ?9^B(*;w z2zrNk-pCwn)?reXp_+tdD#JHLmP>=IDhsnh*NI7|C=v8rZE-r57hl!O{XJx<6%{N6j>{z1hK@f~s+38k z*<7nx%`3FlE~iU^3=!$F$n=1cWI716EGLF4w@w-@8!BI5pnpbeco4rvu8z52n4qpx{k9VDOIlH)k$Jv>v_Lku)RVQRbhnKLFIan4s-Y1 zU8fzM@7S>_Br=f;=}SbYWDqXz>bZv*^N@dHC^8pu=S+!9ap%06uTV%FYAt7{rEF{a zxKT5kQyY_L8-+M4ZC=+Hkcgc77N@3cfb)NyrmWdIvY~D3h@Fk@;v#36J&JaT#JQ&2 zMr6xJW+T;-kl87jh)KaP)QuKH*z{ zkAhE6&+jh$ac|Z9xigYpeEJe&8ZO6GKhpzRy0}vum$Xc@u9BH#S=%_wqLzl5Q;N?3 zncnsjQ5M>8U0B9CFD3PW$2c{WGdSBgJZC^f(e`4pSqOXK#7t%Ll1TDUh)ktIM0XJ9 zKE*dYB1I7?h{z?|WDr?vYa#t~nx_9re#duvJ3VhXT1RF{Q3+vlb05VFW%2!o=o|b* s^r&;h)#;f`O@t&w_Yhpfp0V}3c+YHHpVMC=O@8=p-@)PS?f0Gk0P7ics{jB1 literal 5939 zcmcgwUvnF`5yz1frK9B9Z4&p7Cn>6F!_!#exa~`;2|acw#eS$|%}KGRvecW?9Y~&i zf0zR(ku%Pd`@K5Tuh7rXhd$>6w7&)Jj+8}@>@*6=1Azsw*!^L5vAFtoH(LL^^A9&* z#ix${2Y6(JB4q3crNzP;i!FA93VwAK*H}_#M|GAo*inNeOYCTgB~5nJWXUo+T4u=# zJ6d5@*kHnDeau;6e`o9sV}CtrF|o?RCVN$5xnL>S*VuuxOiMZ_TD@HON`yR1`Hl$q zpEmg)?*0Cct=0p7tcF>>&3nTJs%U zKbGa#Th-XZd|VPW$6hv0%egmb)Wgw8q+!90=Jm26oe1bv% zML>YEM)&~;AP23f(jYjgvc$rMt~3jx#|X180TUeuuJUA7oq&BS}R% z;JPA;h8p^cpGR@bTlQ#-zih0yPyc<45PV%tM?$Xiex4K2+8W;O zE|>Q8o|nDV(we!Z24p4B$>uwGHrmO~({gGs%%Y%L_w8Pc@*azLWMFZ!5m~M$RgS%s z-52exVSAIex3-2D(>~ecp^&QE)~!vRVzXrT-X=Bxns@hLgfyb>k7Eq#b`QSZ-*(MH^%H^lMp`4}B7sfM6=KfuTPV-WdoRh<-pUP@Fxzo1qcbrB)R1OUR+tjM8K&As zu7t8+W}HQiPy1OMid^y+#nx=|-#JBfL!K-^b}r;B(BjN!aVGN9OwQ?05=x{i9WL6% zd%-N>l!jlVraTsBB7T4I=L6&d`6DBLlm_uQoRhyKl=AJQo8op&ljjw8Qr@CAPVkmgH~21H7ZovYz!ySweH{G`1_ zHV6MM)}2{oN%(=#DD`>|Ag(miQn6<+YDBAdhOTFoq0+FKYJgD_O4Z(Bs2>)<)^z|I z<=G(jleQ%5rA2r;PEN6Hbc|6PTmP^)*4{caN+`r#kH1KT@Lt^%#zSgI2^k;{=ANFvmb%WRy(4=4r`?P^0IM&tuy zI!nm8{A3ghugoz#FbqUzH03Y0h9@X;D$b~gxVuaLqWFJyQl6*CJZeaO=%FmNM~TqC zQM|U;Yh-7rF!mBZi+x6IO?_F@RExbagX+53xJX>m&E`eovTm+iB-*;!x=38r%{9vH zNP;?hQ)3p@Kr+iO&6A7>%kv~7k3CN^GOcP-$dDmZrn{$BQI0YhQL=y}R#Dzu9O}wO z-J}uJLwVw9mc_zHhCmISsK7TI%4PLLPv?8N?)7|~I!kpEy~xbG`Bii}JWu#lF{oP3 zBQxB%X|Ye zZW53r)kgjqDwChH*EP0ta+7@v1G3no*LC*j@i)utxwa0vaO@csXsY{56lw{DM`@Kd z4VfXl&>^U3aCD9Ox}@G0cqGZftQ(egT+)j~(mH*P%0T<>&dDA2ZH*~3P{LDjF@*Eg z*xzal`W-kVuDpk$W!tWxD~Z%snFxmM<9L?(QUf))H)H+vH_n?qVc#eT2M??svKP zW*p_XKRYvj-Qb0WgbAUkeuBdIRC(i=LE>_By1zkjohXn5kMX>X0&NcgqfyvJ1$F_W zP&L-C6AmRPceNkXDct6_8Jyu|gRPkwpnA1jP|1dFmp1etumc1S0aF18KOaWHko&k? zqQiFl4gOSL#Qb=ZpW@0)VU4cN6|6;w)1yx}D0d|5^Z9xalh*Zhi#z&iY3>k01)UDg zLhuj39~W?KtMkb+b>b17K?e!T)LiI|Y(pQ`onhy{^?qBj9R+gzR-6?}4T$90yJ`%wyS!FXgnawLMN9|gSF<&FkYW2iyX z7*c5caeRbcF@<=Hk1Sn?6co3#kL;jQI>n#g4y1CsjH@+@tFxv~QWk*sFK{EJ5l$8a z*>yUS3kx^U$_@rc9nmSEF7Xxc8zkT6y^U`Y(oLS_#M=-HYb)%z;Km*80tfWEhn#0a z@4zAaMQUp=-aX9j`e0Yk=HBVeh&_5ef~GO|Uqd 1: label += ' (%s)' % action.option_strings[0] text = wx.StaticText(parent, label=label) self.MakeBold(text) @@ -83,16 +83,12 @@ class AbstractComponent(object): @abstractmethod def BuildWidget(self, parent, action): - ''' - Must construct the main widget type for the Action - ''' + ''' Must construct the main widget type for the Action ''' pass @abstractmethod def GetValue(self): - ''' - Returns the state of the given widget - ''' + ''' Returns the state of the given widget ''' pass @@ -138,23 +134,57 @@ class Optional(AbstractComponent): self.contents = None def BuildWidget(self, parent, action): - pass + return wx.TextCtrl(parent) + + def GetValue(self): + self.AssertInitialization('Optional') + return self._widget.GetValue() + - - +class Flag(AbstractComponent): + def __init__(self, action): + self._action = action + self._widget = None + self.contents = None + + def BuildWidget(self, parent, action): + if len(action.option_strings) > 1: + label = action.option_strings[0] + else: + label = '' + return wx.CheckBox(parent, -1, label=label) + + def GetValue(self): + return self._widget.GetValue() - - - + + +class Counter(AbstractComponent): + def __init__(self, action): + self._action = action + self._widget = None + self.contents = None + + def BuildWidget(self, parent, action): + levels = [str(x) for x in range(1, 7)] + return wx.ComboBox( + parent=parent, + id=-1, + value='', + choices=levels, + style=wx.CB_DROPDOWN + ) + + def GetValue(self): + return self._widget.GetValue() + + + if __name__ == '__main__': - parser = ArgumentParser(description='Example Argparse Program') - parser.add_argument("filename", help="filename") - action = parser._actions[1] - positional = Positional(action) - - a = getattr + pass + diff --git a/src/app/dialogs/components_unittest.py b/src/app/dialogs/components_unittest.py index 289a265..a7a2631 100644 --- a/src/app/dialogs/components_unittest.py +++ b/src/app/dialogs/components_unittest.py @@ -22,16 +22,21 @@ class ComponentsTest(unittest.TestCase): parser = ArgumentParser(description='Example Argparse Program') parser.add_argument("filename", help="Name of the file you want to read") parser.add_argument('-T', '--tester', choices=['yes','no']) + parser.add_argument('-o', '--outfile', help='Redirects output to the specified file') + parser.add_argument('-v', '--verbose', help='Toggles verbosity off') + parser.add_argument('-e', '--repeat', action='count', help='Set the number of times to repeat') action = parser._actions self.actions = { 'help' : action[0], 'Positional' : action[1], - 'Choice' : action[2] + 'Choice' : action[2], + 'Optional' : action[3], + 'Flag' : action[4], + 'Counter' : action[5] } def BuildWindow(self, component): - app = wx.PySimpleApp() module_name = os.path.split(sys.argv[0])[-1] frame = wx.Frame(None, -1, module_name) @@ -42,17 +47,25 @@ class ComponentsTest(unittest.TestCase): frame.Show(True) - print component.GetValue() app.MainLoop() + def testPositionalWidgetBuild(self): self.SetupWidgetAndBuildWindow('Positional') -# component = components.Positional(self.actions['positional']) -# self.BuildWindow(component) def testChoiceWidgetBuild(self): self.SetupWidgetAndBuildWindow('Choice') + def testOptionalWidgetBuild(self): + self.SetupWidgetAndBuildWindow('Optional') + + def testFlagWidgetBuild(self): + self.SetupWidgetAndBuildWindow('Flag') + + def testCounterWidgetBuild(self): + self.SetupWidgetAndBuildWindow('Counter') + + def SetupWidgetAndBuildWindow(self, _type): component = getattr(components, _type)(self.actions[_type]) self.BuildWindow(component)