code cleanup for argparse support (addresses #33)
* remove unused code from CliCommand class * improve parameter handling in BackendTo constructor * return entity in BackendEntityHandler's create method * add a default value for country in ClientCli * pass dictionary from parsed arguments to ClientHandler's create method * correctly handle special chars in ClientCli output
This commit is contained in:
		
							parent
							
								
									b8139e91f2
								
							
						
					
					
						commit
						45b2865e8e
					
				
					 4 changed files with 33 additions and 174 deletions
				
			
		|  | @ -58,6 +58,7 @@ class BackendEntityHandler(object): | |||
|             sess.rollback() | ||||
|             self.logger.exception("Exception in create.") | ||||
|             raise | ||||
|         return entity | ||||
| 
 | ||||
|     def fetchall(self, **kwargs): | ||||
|         """Fetches all entities of the managed entity type.""" | ||||
|  |  | |||
|  | @ -26,13 +26,14 @@ class BackendTo(object): | |||
|     """Backend transfer object class.""" | ||||
| 
 | ||||
|     def __init__(self, config, **kwargs): | ||||
|         cols = object_mapper(self).local_table.columns.keys() | ||||
|         for (key, value) in kwargs.items(): | ||||
|             self.__setattr__(key, unicode(value, 'utf8')) | ||||
|             if key in cols and value is not None: | ||||
|                 self.__setattr__(key, unicode(value, 'utf8')) | ||||
| 
 | ||||
|     def __repr__(self, **kwargs): | ||||
|         if 'verbose' in kwargs and kwargs['verbose']: | ||||
|             cols = [col for col in \ | ||||
|                     object_mapper(self).local_table.columns.keys()] | ||||
|             cols = object_mapper(self).local_table.columns.keys() | ||||
|             format = "%(class)s:" | ||||
|             format = format + ", ".join([col + "=%(" + col + ")s" for col in \ | ||||
|                                          cols]) | ||||
|  |  | |||
|  | @ -25,181 +25,38 @@ from gnuviechadmin.exceptions import GnuviechadminError | |||
| 
 | ||||
| 
 | ||||
| class CliCommand(object): | ||||
|     """Base class for command line interface. | ||||
|     """ | ||||
|     Base class for command line interface. | ||||
| 
 | ||||
|     A specific implementation class must define the fields name, | ||||
|     description and _optionmap. | ||||
| 
 | ||||
|     The field name is the name of the subcommand. | ||||
| 
 | ||||
|     The field description is a short, one line description of the | ||||
|     command. | ||||
| 
 | ||||
|     The field _optionmap is a map which maps the subcommand names to | ||||
|     lists of tuples. Each tuple consists of four elements. The first | ||||
|     element is a list of command line arguments, short arguments start | ||||
|     with dash, long arguments with a double dash. The second element | ||||
|     is the name of the field in the data map of the command, it will | ||||
|     directly be sent to the underlying entity. The third field is a | ||||
|     description for the group of command line options in field | ||||
|     one. The fourth field is True for mandatory fields and False | ||||
|     otherwise. | ||||
|     A specific implementation class must implement the static | ||||
|     setup_arparser method and the _execute method. | ||||
|     """ | ||||
| 
 | ||||
|     def _usage(self): | ||||
|         """This method shows usage information. The implementation | ||||
|         relies on the information in the fields name, description and | ||||
|         _optionmap in the implementation classes.""" | ||||
|         return """GNUViechAdmin command line interface | ||||
|     @staticmethod | ||||
|     def setup_argparser(subparsers): | ||||
|         """ | ||||
|         This static method is used to initialize the command line | ||||
|         argument parser. | ||||
| 
 | ||||
| Subcommand: %(command)s | ||||
| 
 | ||||
|  %(description)s | ||||
| 
 | ||||
| Usage: | ||||
| 
 | ||||
| %(called)s %(command)s -h|--help | ||||
| 
 | ||||
|  gives this usage information. | ||||
| 
 | ||||
| Common options: | ||||
| 
 | ||||
|  %(option)s | ||||
|     %(mandatory)s %(optiondesc)s | ||||
| """ % {'called': sys.argv[0], | ||||
|        'command': self.name, | ||||
|        'description': self.description, | ||||
|        'option': '-v, --verbose', | ||||
|        'optiondesc': 'verbose operation', | ||||
|        'mandatory': " "} | ||||
|         for commandname in self._optionmap.keys(): | ||||
|             cmdl = "%(called)s %(command)s %(subcommand)s [-v|--verbose]" % { | ||||
|                 'called': sys.argv[0], | ||||
|                 'command': self.name, | ||||
|                 'subcommand': commandname} | ||||
|             desc = """ | ||||
|  %s | ||||
| """ % (self._optionmap[commandname][0]) | ||||
|             for (options, field, optiondesc, mandatory) in \ | ||||
|                     self._optionmap[commandname][1]: | ||||
|                 cmd = " " | ||||
|                 pairs = [] | ||||
|                 for option in options: | ||||
|                     if field: | ||||
|                         if option.startswith("--"): | ||||
|                             pairs.append("%s=<%s>" % (option, field)) | ||||
|                         else: | ||||
|                             pairs.append("%s <%s>" % (option, field)) | ||||
|                     else: | ||||
|                         pairs.append(option) | ||||
|                 if not mandatory: | ||||
|                     cmd = cmd + "[" | ||||
|                 cmd = cmd + "|".join(pairs) | ||||
|                 if not mandatory: | ||||
|                     cmd = cmd + "]" | ||||
|                 descmap = { | ||||
|                     'option': ", ".join(pairs), | ||||
|                     'optiondesc': optiondesc, | ||||
|                     'mandatory': ' '} | ||||
|                 if mandatory: | ||||
|                     descmap['mandatory'] = '*' | ||||
|                 desc = desc + """ %(option)s | ||||
|     %(mandatory)s %(optiondesc)s | ||||
| """ % descmap | ||||
|                 if (len(cmdl) + len(cmd)) > 79: | ||||
|                     print cmdl | ||||
|                     cmdl = cmd | ||||
|                 else: | ||||
|                     cmdl = cmdl + cmd | ||||
|             print cmdl | ||||
|             print desc | ||||
|         print "Mandatory options are marked with *" | ||||
| 
 | ||||
|     def _subcommands(self): | ||||
|         """Convenience method for retrieving the subcommand names from | ||||
|         the _optionmap field.""" | ||||
|         return self._optionmap.keys() | ||||
| 
 | ||||
|     def _longopts(self, subcommand): | ||||
|         """This method retrieves available long options in a format | ||||
|         valid for getopt.gnu_getopt(...) from the _optionmap field.""" | ||||
|         longopts = [] | ||||
|         for cur in [(option[0], option[1]) for option in \ | ||||
|                     self._optionmap[subcommand][1]]: | ||||
|             for command in cur[0]: | ||||
|                 if command.startswith("--"): | ||||
|                     if cur[1]: | ||||
|                         longopts.append(command[2:] + "=") | ||||
|                     else: | ||||
|                         longopts.append(command[2:]) | ||||
|         return longopts | ||||
| 
 | ||||
|     def _shortopts(self, subcommand): | ||||
|         """This method retrieves available short options in a format | ||||
|         valid for getopt.gnu_getopt(...) from the _optionmap field.""" | ||||
|         shortopts = "" | ||||
|         for cur in [(option[0], option[1]) for option in \ | ||||
|                     self._optionmap[subcommand][1]]: | ||||
|             for command in cur[0]: | ||||
|                 if not command.startswith("--"): | ||||
|                     if cur[1]: | ||||
|                         shortopts = shortopts + command[1:] + ":" | ||||
|                     else: | ||||
|                         shortopts = shortopts + command[1:] | ||||
|         return shortopts | ||||
| 
 | ||||
|     def _checkrequired(self, subcommand): | ||||
|         """Checks whether the required fields of the given subcommand | ||||
|         are set.""" | ||||
|         reqcheck = [True, []] | ||||
|         for req in [option for option in \ | ||||
|                     self._optionmap[subcommand][1] if option[3]]: | ||||
|             if not req[1] in self._data: | ||||
|                 reqcheck[0] = False | ||||
|                 reqcheck[1].append(""" %s | ||||
|     * %s""" % (", ".join(req[0]), req[2])) | ||||
|         return reqcheck | ||||
| 
 | ||||
|     def _handleoption(self, subcommand, o, a): | ||||
|         """Handles a command line option by assigning it to the | ||||
|         matching key as defined in the _optionmap property of the | ||||
|         implementation class.""" | ||||
|         optionmap = [(option[0], option[1]) for option in \ | ||||
|                      self._optionmap[subcommand][1]] | ||||
|         if optionmap: | ||||
|             for (options, datakey) in optionmap: | ||||
|                 if o in options: | ||||
|                     self._data[datakey] = a | ||||
| 
 | ||||
|     def _execute(self, subcommand): | ||||
|         """This method is called when the subcommand of the command is | ||||
|         executed.""" | ||||
|         The method has to be overridden by subclasses. | ||||
|         """ | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
|     def _parseopts(self, subcommand, args): | ||||
|         """This method parses the options given on the command line.""" | ||||
|         longopts = ["help", "verbose"] | ||||
|         longopts.extend(self._longopts(subcommand)) | ||||
|         try: | ||||
|             opts, args = getopt.gnu_getopt( | ||||
|                 args, | ||||
|                 "hv" + self._shortopts(subcommand), | ||||
|                 longopts) | ||||
|         except getopt.GetoptError: | ||||
|             self._usage() | ||||
|             sys.exit(2) | ||||
|         self._verbose = False | ||||
|         for o, a in opts: | ||||
|             if o in ("-v", "--verbose"): | ||||
|                 self._verbose = True | ||||
|             if o in ("-h", "--help"): | ||||
|                 self._usage() | ||||
|                 sys.exit() | ||||
|             self._handleoption(subcommand, o, a) | ||||
| 
 | ||||
|     def _execute(self): | ||||
|         """ | ||||
|         This method is called when the subcommand of the command is | ||||
|         executed. | ||||
| 
 | ||||
|         The method has to be overridden by subclasses. | ||||
|         """ | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
|     def __init__(self, args, config): | ||||
|         """This initializes the command with the given command line | ||||
|         arguments and executes it.""" | ||||
|         """ | ||||
|         This initializes the command with the given command line | ||||
|         arguments and executes it. | ||||
|         """ | ||||
|         self.config = config | ||||
|         self.args = args | ||||
|         self.logger = logging.getLogger("%s.%s" % ( | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ class ClientCli(CliCommand.CliCommand): | |||
|             help = _("the city of the client's address")) | ||||
|         cmdparser.add_argument( | ||||
|             '--country', | ||||
|             help = _("the client's country")) | ||||
|             help = _("the client's country"), default='de') | ||||
|         cmdparser.add_argument( | ||||
|             '-e', '--email', required = True, | ||||
|             help = _("the client's email address")) | ||||
|  | @ -91,9 +91,9 @@ class ClientCli(CliCommand.CliCommand): | |||
|         ch = ClientHandler(self.config, self.args.verbose) | ||||
|         if self.args.subcommand == "create": | ||||
|             try: | ||||
|                 myclient = ch.create(**self.args) | ||||
|                 myclient = ch.create(**self.args.__dict__) | ||||
|                 if self.args.verbose: | ||||
|                     print myclient | ||||
|                     print unicode(myclient).encode('utf8') | ||||
|             except CreationFailedError, cfe: | ||||
|                 self._usage() | ||||
|                 print cfe | ||||
|  | @ -101,7 +101,7 @@ class ClientCli(CliCommand.CliCommand): | |||
|         elif self.args.subcommand == "list": | ||||
|             clients = ch.fetchall() | ||||
|             for client in clients: | ||||
|                 print client | ||||
|                 print unicode(client).encode('utf8') | ||||
|         elif self.args.subcommand == "delete": | ||||
|             ch.delete(self.args.clientid) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue