diff --git a/commandr/commandr.py b/commandr/commandr.py index 82c3202..a84ad07 100644 --- a/commandr/commandr.py +++ b/commandr/commandr.py @@ -122,12 +122,19 @@ # main: # If set, Commandr will use the supplied value as the command name to run # if no command name is supplied. It will override any previous values. +# +# extra_options: +# If True, extra options will be made available to commands. +# Default is False. + from collections import namedtuple import inspect import itertools from optparse import OptionParser, SUPPRESS_HELP import sys +from timeit import Timer +from datetime import timedelta class CommandInfo( namedtuple('BaseCommandInfo', @@ -158,6 +165,7 @@ def __init__(self): self.ignore_self = False self.main_docs = True self.main = None + self.extra_options = False # Internal flag indicating whether to expect the command name as the first # command line argument. @@ -240,7 +248,8 @@ def SetOptions(self, show_all_help_variants=None, ignore_self=None, main_docs=None, - main=None): + main=None, + extra_options=None): """Set commandr options. Any argument not set to None will be applied (otherwise it will retain its current value). @@ -258,6 +267,8 @@ def SetOptions(self, command is specified. Default is True. main - If set, it will use the supplied value as the command name to run if no command name is supplied. It will override any previous values. + extra_options - If True, extra options will be made available to commands. + Default is False. """ # Anything added here should also be added to the RunFunction interface. if hyphenate is not None: @@ -270,6 +281,8 @@ def SetOptions(self, self.main_docs = main_docs if main is not None: self.main = main + if extra_options is not None: + self.extra_options = extra_options def Run(self, *args, **kwargs): """Main function to take command line arguments, and parse them into a @@ -314,7 +327,8 @@ def RunFunction(self, show_all_help_variants=None, ignore_self=None, main_doc=None, - main=None): + main=None, + extra_options=None): """Method to explicitly execute a given function against the command line arguments. If this method is called directly, the command name will not be expected in the arguments. @@ -332,6 +346,8 @@ def RunFunction(self, command is specified. Default is True. main - If set, it will use the supplied value as the command name to run if no command name is supplied. It will override any previous values. + extra_options - If True, extra options will be made available to commands. + Default is False. """ info = self._all_commands.get(cmd_name) if not info: @@ -353,6 +369,11 @@ def RunFunction(self, elif 'help' in options_dict: del options_dict['help'] + timeit = False + if 'timeit' in options_dict: + timeit = options_dict['timeit'] + del options_dict['timeit'] + ignore = (info.ignore_self if info.ignore_self is not None else self.ignore_self) @@ -410,15 +431,24 @@ def RunFunction(self, for key, value in options_dict.iteritems(): if value is None: if key not in defaults_dict: - self._HelpExitCommand( - "All options without default values must be specified", + self._HelpExitCommand("Option '" + key + "' is missing.\n" + + "All options without default values must be specified.", info.name, info.callable, options_dict, argspec.args) elif defaults_dict[key] is not None: options_dict[key] = defaults_dict[key] self.current_command = info try: - result = info.callable(**options_dict) + self.temp_result = "" # use an instance var to store result from wrapper + if timeit: + def wrapper(): + self.temp_result = info.callable(**options_dict) + timer = Timer(wrapper) + delta = timer.timeit(1) + print "Time taken is: ", timedelta(seconds = delta) + result=self.temp_result + else: + result = info.callable(**options_dict) except CommandrUsageError as e: self.Usage(str(e) or None) @@ -516,6 +546,11 @@ def _BuildOptParse(self, info): else: self._AddOption(args, dest=arg) + if self.extra_options: + defaults_dict["timeit"]=False + self._AddOption(['--timeit'], dest='timeit', action='store_true', + default=False, help="Time the duration of the command.") + return argspec, defaults_dict def _AddOption(self, args, **kwargs): diff --git a/example_extra.py b/example_extra.py new file mode 100755 index 0000000..8bd5909 --- /dev/null +++ b/example_extra.py @@ -0,0 +1,55 @@ +#!/usr/bin/python +# +# Copyright 2013 TellApart, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============================================================================= +""" + Example usage of commandr with extra options. + + To time a command, try running the example with + ./example_extra.py greet --timeit John + + Output: + Hi Mr. John! + Time taken is: 0:00:00.000027 + + This indicates that it took 27 microseconds to execute the command + + The timeit command is only available when the extra_options parameter + is set to True +""" + +from commandr import command, Run, CommandrUsageError, wraps + +@command('greet') +def SayGreeting(name, title='Mr.', times=1, comma=False, caps_lock=False): + """Greet someone. + + Arguments: + name - Name to greet. + title - Title of the person to greet. + times - Number of time to say the greeting. + comma - Whether to add a comma after the greeting. + caps_lock - Whether to output in ALL CAPS. + """ + message = 'Hi%s %s %s!' % (',' if comma else '', title, name) + if caps_lock: + message = message.upper() + + for _ in xrange(times): + print message + +if __name__ == '__main__': + Run(hyphenate=True, extra_options=True)