Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Implemented command-line parsing for the new command. |
---|---|
Timelines: | family | ancestors | descendants | both | dev |
Files: | files | file ages | folders |
SHA1: |
a855b05badd237aa22d2d91cf39220cb |
User & Date: | mvnathan 2014-09-20 07:51:22.812 |
Context
2014-09-20
| ||
08:38 | Disallow item creation without any accompanying properties. check-in: 49440f6e1f user: mvnathan tags: dev | |
07:51 | Implemented command-line parsing for the new command. check-in: a855b05bad user: mvnathan tags: dev | |
00:15 | Implemented morglib.database.add_item(). check-in: 0c1020da14 user: mvnathan tags: dev | |
Changes
Changes to py/morglib/args.py.
︙ | ︙ | |||
108 109 110 111 112 113 114 | parser.add_argument('command', nargs = argparse.REMAINDER, help = 'Morg command to run', metavar = 'CMD') args = parser.parse_args(argv) return args | < < < < < < < < < < < < < < < < | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | parser.add_argument('command', nargs = argparse.REMAINDER, help = 'Morg command to run', metavar = 'CMD') args = parser.parse_args(argv) return args #--------------------------- HELPER CLASSES ----------------------------- class argv_parser(argparse.ArgumentParser): '''Argument parser that raises an exception instead of exiting. When argparse.ArgumentParser encounters an error, it simply quits with an error message. This helper class changes that behaviour so that an exception is raised instead, which allows us to customize how |
︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 158 159 160 161 162 | this arguments parser raises an exception so that Morg's main function can react as it sees fit rather than being beholden to the argparse module's whims. ''' raise args_error('{}'.format(msg)) def _init_defaults(): '''Initialize default values for various command-line options. @return Dictionary containing default values. This function returns a dictionary of strings to strings with the | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | this arguments parser raises an exception so that Morg's main function can react as it sees fit rather than being beholden to the argparse module's whims. ''' raise args_error('{}'.format(msg)) class print_help(argparse.Action): '''An action to print help without exiting. By default, argparse.ArgumentParser exits after printing help. However, when Morg is in interactive mode, we don't want a command's --help option to end up quitting the application. This class helps accomplish that. To use it, a command's implementation should follow the argument parsing approach illustrated below: @verbatim import morglib.args as args def parse(argv): parser = args.argv_parser(add_help = False) parser.add_argument('-h', '--help', action = args.print_help, nargs = 0) # etc. @endverbatim The above will disable argparse's built-in help processing and use this one instead. ''' def __call__(self, parser, namespace, values, option_string = None): parser.print_help() #---------------------------- DEBUG SUPPORT ----------------------------- def dump(args): '''Dump command-line args to debug log. @param args argparse.Namespace object returned by parse() function. Be sure to call this function after logging has been initialized with morglib.log.init(). Otherwise, expect trouble. ''' for attr in dir(args): if (attr.startswith('_')): continue logger.debug('{} = {}'.format(attr, getattr(args, attr))) #--------------------------- PRIVATE HELPERS ---------------------------- def _init_defaults(): '''Initialize default values for various command-line options. @return Dictionary containing default values. This function returns a dictionary of strings to strings with the |
︙ | ︙ |
Changes to py/morglib/new.py.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | # along with Morg. If not, see <http://www.gnu.org/licenses/>. # #------------------------------- IMPORTS -------------------------------- # Morg import command # Standard library import logging #---------------------------- MODULE LOGGER ----------------------------- logger = logging.getLogger(__name__) #--------------------------- CREATE COMMAND ----------------------------- class new(command.base): | > > | > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | # along with Morg. If not, see <http://www.gnu.org/licenses/>. # #------------------------------- IMPORTS -------------------------------- # Morg import command import args # Standard library import logging import argparse #---------------------------- MODULE LOGGER ----------------------------- logger = logging.getLogger(__name__) #--------------------------- CREATE COMMAND ----------------------------- class new(command.base): '''Command for creating new items and properties.''' def __call__(self, argv, db): '''Execute new command. @param argv (string list) Command-line arguments. @param db (morglib.database) Items database. ''' arg = _parse(argv[1:]) print(arg) #------------------------ COMMAND-LINE PARSING -------------------------- def _parse(argv): fmt = argparse.RawDescriptionHelpFormatter parser = args.argv_parser(description = _help_before_options(), epilog = _help_after__options(), prog = 'new', add_help = False, formatter_class = fmt) parser.add_argument('-h', '--help', action = args.print_help, nargs = 0, help = 'print this help') parser.add_argument('-p', '--property', help = 'add a property instead of a task', metavar = 'NAME') parser.add_argument('-t', '--property-type', default = 'text', type = _validate_property_type, help = 'type of property to add (default: %(default)s)', metavar = 'TYPE') parser.add_argument('-r', '--property-range', help = 'range of values property may assume', metavar = 'RANGE') parser.add_argument('properties', nargs = argparse.REMAINDER, help = 'property specifications for new task', metavar = 'PROPERTIES') return parser.parse_args(argv) def _help_before_options(): help_text = ''' Use the new command to add items or properties to the Morg database. Without any options, this command will add a new item to the database, using the positional arguments as property specifications for the item. With the -p option, however, you can add a new property instead of a new item. You can use -t and -r to specify the new property's type and range. Positional arguments in this case will be ignored. Similarly, -t and -r will be ignored without -p. ''' return help_text def _help_after__options(): help_text = ''' Here is an example showing how to add a new item (it uses some of Morg's predefined properties): new name=test type=task status=wip notes='this is a test' As you can see, properties are specified as name-value pairs with the names and values being separated from each other by an equals sign. Moreover, you should quote names and values that have spaces in them. If you wish to surround the equals signs with spaces, you should enclose the entire property specification in quotes. Here is an example: new 'odd property name = value with spaces' If you supply incorrect types for various properties or exceed their defined ranges, the database will reject them and not add the requested item. For example, the predefined property day has a type of integer and a range of [1,7] and the predefined property price has type real without any range. Thus, assuming you haven't changed Morg's predefined defaults, the following command is doomed to failure: new day=10 price=foo You don't have to type out the property names in full. You can abbreviate them to unique prefixes. For example, Morg's default configuration includes two properties that begin with the letter 'n', viz., name and notes. Thus, you could just type: new na=foo no='well this is just dandy' However, trying the following will result in an error because Morg won't be able to tell whether you mean 'n' for name or 'n' for notes: new n=oops Text properties with defined ranges may also be abbreviated. To illustrate, consider this command: n na='what ever' t=t stat=w no='cryptic but less to type!' Assuming you're using Morg's default settings, the above would create a new item with the following properties: name what ever type task status wip notes cryptic but less to type! In the above command, the first 'n' stands for the new command. Since Morg strives to support shorthand wherever possible, its commands can also be abbreviated. The "t=t" construct specifies the property named "type," which has type text and range (task,shop). Thus, the 't' before the equals expands to "type" and the 't' after the equals to "task." Similarly, "stat" expands to "status" and 'w' to "wip" (the other supported values for the status property are "todo" and "done"). When you're adding a new property instead of a task, keep in mind that Morg only supports integer, real, and text as the possible property types. That is, the -t option will only accept one of the following strings: integer, real, text. For the sake of convenience, you may abbreviate the type strings to any acceptable unique prefix. Since the three types don't share any common initial substrings, you could get away with supplying just the first character of the type as shown below: new -p foo -t i That will create a new integer property named foo that can take on any integral value supported by the version of SQLite installed on your system. To restrict properties to specific ranges, use the -r option as shown below: new -p role -r president,glutton,buffoon That defines a new text property named role that can take on the values president, glutton, or buffoon. As usual, if the property name and/or values have spaces in them, use quotes: new -p 'Job Title' -r 'Vice President,Male Gigolo,One Hit Wonder' Numeric property ranges can also use commas: new -p foo -t i 1,3,5,7,9 Additionally, for numeric types, you can use double dots to specify a min and max values: new -p urgency -t r -r 1..-1 Note that we put the min value -1 at the right of the double dot. That's because it would have confused the new command's command-line parser into thinking of it as an option -1. But don't worry, Morg's database will do the right thing when it sees the above range and flip the bounds around as required. Any other syntax for property ranges will result in an error. ''' return help_text # Allow property types to be abbreviated and ensure they're restricted to # the ones that Morg supports. def _validate_property_type(optval): completions = filter(lambda s: s.startswith(optval), ('integer', 'real', 'text')) n = len(completions) if (n < 1): raise args.args_error('{}: unknown property type'.format(optval)) if (n > 1): msg = ('{}: ambiguous property type; can be: {}'. format(optval, ', '.join(completions))) raise args.args_error(msg) return completions[0] #------------------------------------------------------------------------ ############################################## # Editor config: # ############################################## # Local Variables: # |
︙ | ︙ |
Changes to wiki/todo.wiki.
︙ | ︙ | |||
22 23 24 25 26 27 28 29 30 31 | * Use the BETWEEN operator in property range constraints. * Implement a watermark class to ease verification and "Morgification." * The watermark table should be created and populated in a transaction. * Update doc strings to reflect recent changes about the watermark. * Pass database to all commands' <tt>__call__</tt> method. * Generalize Morg so it isn't necessarily task-centric. * Implement <tt>morglib.database.add_item()</tt>. <h2>PENDING</h2> | > < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | * Use the BETWEEN operator in property range constraints. * Implement a watermark class to ease verification and "Morgification." * The watermark table should be created and populated in a transaction. * Update doc strings to reflect recent changes about the watermark. * Pass database to all commands' <tt>__call__</tt> method. * Generalize Morg so it isn't necessarily task-centric. * Implement <tt>morglib.database.add_item()</tt>. * Implement <tt>new</tt> command-line processing. <h2>PENDING</h2> * Hook up <tt>new</tt> command to <tt>add_item()</tt>. * Hook up <tt>new</tt> command to <tt>add_property()</tt>. * Add some user documentation. |