├── Lib └── site-packages │ ├── builder.py │ └── components │ ├── __init__.py │ ├── arginput.py │ └── argument.py ├── README.rst ├── brython_dist.js ├── index.html └── resources ├── gears.gif └── style.css /Lib/site-packages/builder.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # 3 | # Interpreter version: brython 4 | # 5 | from collections import OrderedDict 6 | 7 | from browser import document as doc 8 | 9 | from components import ArgInput 10 | from components import Argument 11 | from components import bind_links 12 | 13 | 14 | # Functions & objects ========================================================= 15 | def hide_help_frame(ev): 16 | """ 17 | Remove help popup from the HTML. 18 | """ 19 | doc["help_placeholder"].innerHTML = "" 20 | doc["black_overlay"].style.display = "none" 21 | 22 | 23 | def parse_arguments(ev): 24 | """ 25 | Parse arguments from inputs and save the result to the output textarea. 26 | """ 27 | text = a.__str__() 28 | 29 | if doc["output_use_spaces"].checked: 30 | text = text.replace("\t", " ") 31 | 32 | doc["output"].value = text 33 | 34 | 35 | # Object definitions ========================================================== 36 | class ArgParser: 37 | """ 38 | This object holds references to all argument tables and global argparse 39 | settings. 40 | 41 | Attr: 42 | arguments (ordered dict): References to :class:`Argument` objects. 43 | element (obj): Reference to `argument_parser` . 44 | inputs (ordered dict): Reference to global settings inputs. 45 | """ 46 | def __init__(self): 47 | self.arguments = OrderedDict() 48 | self.add_argument_callback() 49 | 50 | # parse all inputs belonging to the argparser objects 51 | self.element = doc["argument_parser"] 52 | arguments = self.element.get(selector="input") or [] 53 | arguments.extend(self.element.get(selector="textarea") or []) 54 | 55 | self.inputs = OrderedDict( 56 | (x.id.split("_")[-1], ArgInput(element=x, parent=self)) 57 | for x in arguments if x 58 | ) 59 | 60 | def new_argument(self): 61 | """ 62 | Create new :class:`Argument` object and bind events to the buttons. 63 | 64 | Returns: 65 | Argument object: Created object. 66 | """ 67 | arg = Argument() 68 | self.bind_argument(arg) 69 | return arg 70 | 71 | def bind_argument(self, argument): 72 | """ 73 | Bind buttons in `argument` object to callbacks methods in this object. 74 | """ 75 | doc[argument.ID + "_argument_button_add"].bind( 76 | "click", 77 | self.add_argument_callback 78 | ) 79 | doc[argument.ID + "_argument_button_rm"].bind( 80 | "click", 81 | self.remove_argument_callback 82 | ) 83 | doc[argument.ID + "_argument_button_up"].bind( 84 | "click", 85 | self.move_arg_up_callback 86 | ) 87 | doc[argument.ID + "_argument_button_down"].bind( 88 | "click", 89 | self.move_arg_down_callback 90 | ) 91 | 92 | def add_argument_callback(self, ev=None): 93 | """ 94 | Add new argument into HTML representation and internal dict. 95 | 96 | Note: 97 | This method is called asynchronously, when the button is pressed. 98 | """ 99 | arg = self.new_argument() 100 | self.arguments[arg.ID] = arg 101 | 102 | def remove_argument_callback(self, ev=None): 103 | """ 104 | Remove argument from HTML representation and internal dict. 105 | 106 | ID of the argument is parsed from `ev` parameter. 107 | 108 | Note: 109 | This method is called asynchronously, when the button is pressed. 110 | """ 111 | if len(self.arguments) > 1: 112 | ID = ev.target.id.split("_")[0] 113 | self.arguments[ID].remove() 114 | del self.arguments[ID] 115 | 116 | def move_arg_up_callback(self, ev): 117 | """ 118 | Switch two arguments - move the argument where the button was pressed 119 | down. 120 | 121 | Note: 122 | This method is called asynchronously, when the button is pressed. 123 | """ 124 | ID = ev.target.id.split("_")[0] 125 | keys = list(self.arguments.keys()) 126 | ioa = keys.index(ID) 127 | 128 | if len(self.arguments) > 1 and ioa > 0: 129 | arg1 = self.arguments[keys[ioa]] 130 | arg2 = self.arguments[keys[ioa - 1]] 131 | 132 | arg1.switch(arg2) 133 | 134 | def move_arg_down_callback(self, ev=None): 135 | """ 136 | Switch two arguments - move the argument where the button was pressed 137 | down. 138 | 139 | Note: 140 | This method is called asynchronously, when the button is pressed. 141 | """ 142 | ID = ev.target.id.split("_")[0] 143 | keys = list(self.arguments.keys()) 144 | ioa = keys.index(ID) 145 | 146 | if len(self.arguments) > 1 and ioa < len(self.arguments) - 1: 147 | arg1 = self.arguments[keys[ioa]] 148 | arg2 = self.arguments[keys[ioa + 1]] 149 | 150 | arg1.switch(arg2) 151 | 152 | def __str__(self): 153 | # read value of all inputs in this object, pick only inputs with value 154 | vals = [ 155 | str(x) 156 | for x in self.inputs.values() 157 | if x.wrapped_value is not None 158 | ] 159 | 160 | # add \n\t only if there are used inputs 161 | inp_string = ",\n\t".join(vals) 162 | if inp_string: 163 | inp_string = "\n\t" + inp_string + "\n" 164 | 165 | # put inputs to template 166 | ARG_PARSER_TEMPLATE = """import argparse 167 | 168 | # ... 169 | parser = argparse.ArgumentParser($parameters) 170 | $arguments 171 | args = parser.parse_args() 172 | 173 | """ 174 | out = ARG_PARSER_TEMPLATE.replace("$parameters", inp_string) 175 | 176 | # convert arguments to strings 177 | arguments = "" 178 | for item in self.arguments.values(): 179 | arguments += item.__str__() 180 | 181 | # put arguments to template 182 | return out.replace("$arguments", arguments) 183 | 184 | 185 | # Main program ================================================================ 186 | if __name__ == '__main__': 187 | a = ArgParser() 188 | 189 | # bind click on output textarea with generation of the source code 190 | doc["output"].bind("click", parse_arguments) 191 | doc["output_use_spaces"].bind("click", parse_arguments) 192 | 193 | # bind links with popup help 194 | doc["black_overlay"].bind("click", hide_help_frame) 195 | bind_links(doc["argument_parser"]) 196 | 197 | doc["loading_gears_background"].style.display = "none" -------------------------------------------------------------------------------- /Lib/site-packages/components/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # 3 | # Interpreter version: brython 4 | # 5 | 6 | from .arginput import ArgInput 7 | from .argument import Argument 8 | from .argument import bind_links 9 | -------------------------------------------------------------------------------- /Lib/site-packages/components/arginput.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # 3 | # Interpreter version: brython 4 | # 5 | from browser import document as doc 6 | 7 | 8 | def type_on_change_event(self, ev): 9 | """ 10 | This code switches select for input when user selects `Custom` in 11 | `type` select element. 12 | """ 13 | if ev.target.value == "custom": 14 | ID = self.element.id 15 | new_html = ', 37 | 38 | 39 |
40 | epilog 41 | 42 |
43 | 44 |
45 | add_help 46 |

47 | 48 | Add a -h/–help option to the parser. 49 |

50 |
51 |
52 | 53 |

Arguments

54 | 55 | 56 | 57 | 58 | 65 | 162 | 163 |
59 |
60 |
61 |
62 |
63 | 64 |
66 | 67 | 68 | 74 | 80 | 95 | 96 | 97 | 98 | 104 | 110 | 116 | 117 | 118 | 119 | 130 | 136 | 142 | 143 | 144 | 145 | 151 | 157 | 158 | 159 |
69 | 70 | flag: 71 | 72 | 73 | 75 | 76 | name: 77 | 78 | 79 | 81 | 82 | action: 83 | 84 | 94 |
99 | 100 | nargs: 101 | 102 | 103 | 105 | 106 | const: 107 | 108 | 109 | 111 | 112 | default: 113 | 114 | 115 |
120 | type: 121 | 122 | 129 | 131 | 132 | choices: 133 | 134 | 135 | 137 | 138 | required: 139 | 140 | 141 |
146 | 147 | metavar: 148 | 149 | 150 | 152 | 153 | dest: 154 | 155 | 156 |
160 | 161 |
164 |
165 | 166 |

Output

167 | 168 |

169 | 170 | Use spaces for indentation. 171 |

172 | 173 | 174 | 175 |
176 | 177 | 178 | 179 |
180 |
181 | 182 |
183 |
184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /resources/gears.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bystroushaak/argparse_builder/85031d2d9e35cdb8fe9ee52dc7acf4028ef9dbe0/resources/gears.gif -------------------------------------------------------------------------------- /resources/style.css: -------------------------------------------------------------------------------- 1 | html{ 2 | background-color: #CCCCCC; 3 | } 4 | 5 | body { 6 | display: block; 7 | margin: 0 auto; 8 | 9 | margin-top: 1em; 10 | margin-bottom: 1em; 11 | 12 | width: 57em; /* ~900px */ 13 | padding: 1em; 14 | background-color: #FFFFFF; 15 | 16 | border: 1px solid black; 17 | text-align: justify; 18 | } 19 | 20 | h1 a, h2 a, h3 a { 21 | text-decoration: none; 22 | color: black; 23 | } 24 | 25 | h1 a:hover, h2 a:hover, h3 a:hover { 26 | text-decoration: underline; 27 | } 28 | 29 | .perex { 30 | font-style: italic; 31 | } 32 | 33 | fieldset p { 34 | font-style: italic; 35 | margin: 0; 36 | } 37 | 38 | fieldset { 39 | border: 0; 40 | } 41 | 42 | fieldset legend { 43 | font-weight: bold; 44 | font-family: monospace; 45 | } 46 | 47 | fieldset textarea { 48 | width: 100%; 49 | } 50 | 51 | fieldset input { 52 | width: 100%; 53 | } 54 | 55 | fieldset p input { 56 | width: auto; 57 | } 58 | 59 | .buttons { 60 | width: 0.8em; 61 | font-size: 3em; 62 | 63 | margin: 0; 64 | padding: 0; 65 | 66 | line-height: 0.8em; 67 | text-align: center; 68 | } 69 | 70 | .remove_button { 71 | padding: 0; 72 | margin: 0.1em; 73 | } 74 | 75 | .argument { 76 | word-wrap: break-word; 77 | word-break: break-all; 78 | } 79 | 80 | .argument_table { 81 | border: 1px solid lightgray; 82 | margin-bottom: 1em; 83 | } 84 | 85 | .argument_table input[type="button"] { 86 | height: 2.9em; 87 | font-weight: bold; 88 | } 89 | 90 | #argument_template { 91 | display: none; 92 | } 93 | 94 | textarea { 95 | width: 100%; 96 | } 97 | 98 | table { 99 | width: 100%; 100 | } 101 | 102 | .descr { 103 | float: left; 104 | width: 30%; 105 | font-family: monospace; 106 | } 107 | 108 | #output { 109 | min-height: 40em; 110 | } 111 | 112 | q { 113 | margin-left: -0.5em; 114 | } 115 | 116 | #black_overlay { 117 | display: none; 118 | position: absolute; 119 | top: 0%; 120 | left: 0%; 121 | width: 100%; 122 | height: 200%; 123 | background-color: black; 124 | z-index: 1001; 125 | -moz-opacity: 0.8; 126 | opacity:.80; 127 | filter: alpha(opacity=80); 128 | } 129 | 130 | #white_content { 131 | display: none; 132 | position: absolute; 133 | top: 10%; 134 | left: 15%; 135 | width: 70%; 136 | height: 80%; 137 | border: 1px solid orange; 138 | z-index: 1002; 139 | overflow: auto; 140 | background-color: white; 141 | } 142 | 143 | #loading_gears_background { 144 | position: absolute; 145 | top: 0%; 146 | left: 0%; 147 | width: 100%; 148 | height: 200%; 149 | background: rgba(0, 0, 0, 0.8); 150 | z-index:1001; 151 | } 152 | 153 | #loading_gears_foreground { 154 | display: block; 155 | margin: 0 auto; 156 | 157 | margin-top: 20%; 158 | 159 | width: 15em; /* ~900px */ 160 | padding: 1em; 161 | background-color: #FFFFFF; 162 | 163 | color: rgba(255, 255, 255, 1); 164 | border: 2px solid black; 165 | 166 | text-align: center; 167 | } --------------------------------------------------------------------------------