summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--clcommands.py12
-rw-r--r--configuration.py11
-rw-r--r--optik_ext.py41
-rw-r--r--testlib.py3
5 files changed, 53 insertions, 19 deletions
diff --git a/ChangeLog b/ChangeLog
index 06042ad..e27fe72 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,10 @@ ChangeLog for logilab.common
============================
--
-
+ * new "date" otion type in optik_ext
+ * new clcommands module to handle commands based command line tool
+ (based on the configuration module)
+ * new AttrObject in testlib to create objects in test with arbitrary attributes
* add pytest to run project's tests and get rid of all runtests.py
* add pytest option to enable design-by-contract using aspects
diff --git a/clcommands.py b/clcommands.py
index c30e0a6..54bd6ff 100644
--- a/clcommands.py
+++ b/clcommands.py
@@ -40,7 +40,9 @@ class Command(Configuration):
"""base class for command line commands"""
arguments = ''
name = ''
-
+ # max/min args, None meaning unspecified
+ min_args = None
+ max_args = None
def __init__(self, __doc__=None, version=None):
if __doc__:
usage = __doc__ % (self.name, self.arguments,
@@ -48,6 +50,13 @@ class Command(Configuration):
else:
usage = self.__doc__.replace(' ', '')
Configuration.__init__(self, usage=usage, version=version)
+
+ def check_args(self, args):
+ """check command's arguments are provided"""
+ if self.min_args is not None and len(args) < self.min_args:
+ raise BadCommandUsage('missing argument')
+ if self.max_args is not None and len(args) > self.max_args:
+ raise BadCommandUsage('too many arguments')
def run(self, args):
"""run the command with its specific arguments"""
@@ -96,6 +105,7 @@ def cmd_run(cmdname, *args):
except KeyError:
raise BadCommandUsage('no %s command' % cmdname)
args = command.load_command_line_configuration(args)
+ command.check_args(args)
try:
command.run(args)
except KeyboardInterrupt:
diff --git a/configuration.py b/configuration.py
index 76b1384..f513a94 100644
--- a/configuration.py
+++ b/configuration.py
@@ -88,7 +88,7 @@ from ConfigParser import ConfigParser, NoOptionError, NoSectionError
from logilab.common.textutils import normalize_text, unquote
from logilab.common.optik_ext import OptionParser, OptionGroup, Values, \
- OptionValueError, OptionError, HelpFormatter, generate_manpage, \
+ OptionValueError, OptionError, HelpFormatter, generate_manpage, check_date, \
check_yn, check_csv, check_file, check_color, check_named, check_password,\
NO_DEFAULT, OPTPARSE_FORMAT_DEFAULT
@@ -138,11 +138,15 @@ def file_validator(opt_dict, name, value):
return check_file(None, name, value)
def color_validator(opt_dict, name, value):
- """validate and return a filepath for option of type 'file'"""
+ """validate and return a valid color for option of type 'color'"""
return check_color(None, name, value)
def password_validator(opt_dict, name, value):
- """validate and return a filepath for option of type 'file'"""
+ """validate and return a string for option of type 'password'"""
+ return check_password(None, name, value)
+
+def date_validator(opt_dict, name, value):
+ """validate and return a mx DateTime object for option of type 'date'"""
return check_password(None, name, value)
@@ -158,6 +162,7 @@ VALIDATORS = {'string' : unquote,
'bool': yn_validator,
'named': named_validator,
'password': password_validator,
+ 'date': date_validator,
'choice': choice_validator,
'multiple_choice': multiple_choice_validator,
}
diff --git a/optik_ext.py b/optik_ext.py
index fdaf9fd..17f0513 100644
--- a/optik_ext.py
+++ b/optik_ext.py
@@ -1,7 +1,7 @@
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
@@ -50,6 +50,8 @@ except ImportError:
except:
NO_DEFAULT = []
+from mx import DateTime
+
OPTPARSE_FORMAT_DEFAULT = sys.version_info >= (2, 4)
from logilab.common.textutils import get_csv
@@ -121,6 +123,16 @@ def check_file(option, opt, value):
msg = "option %s: file %r does not exist"
raise OptionValueError(msg % (opt, value))
+def check_date(option, opt, value):
+ """check a file value
+ return the filepath
+ """
+ try:
+ return DateTime.strptime(value, "%Y/%m/%d")
+ except DateTime.Error :
+ raise OptionValueError(
+ "expected format of %s is yyyy/mm/dd" % opt)
+
def check_color(option, opt, value):
"""check a color value and returns it
/!\ does *not* check color labels (like 'red', 'green'), only
@@ -142,17 +154,18 @@ import types
class Option(BaseOption):
"""override optik.Option to add some new option types
"""
- TYPES = BaseOption.TYPES + ("regexp", "csv", 'yn', 'named', "password",
- "multiple_choice", "file", "font", "color")
+ TYPES = BaseOption.TYPES + ('regexp', 'csv', 'yn', 'date', 'named', 'password',
+ 'multiple_choice', 'file', 'font', 'color')
TYPE_CHECKER = copy(BaseOption.TYPE_CHECKER)
- TYPE_CHECKER["regexp"] = check_regexp
- TYPE_CHECKER["csv"] = check_csv
- TYPE_CHECKER["yn"] = check_yn
- TYPE_CHECKER["named"] = check_named
- TYPE_CHECKER["multiple_choice"] = check_csv
- TYPE_CHECKER["file"] = check_file
- TYPE_CHECKER["color"] = check_color
- TYPE_CHECKER["password"] = check_password
+ TYPE_CHECKER['regexp'] = check_regexp
+ TYPE_CHECKER['csv'] = check_csv
+ TYPE_CHECKER['yn'] = check_yn
+ TYPE_CHECKER['named'] = check_named
+ TYPE_CHECKER['multiple_choice'] = check_csv
+ TYPE_CHECKER['file'] = check_file
+ TYPE_CHECKER['color'] = check_color
+ TYPE_CHECKER['password'] = check_password
+ TYPE_CHECKER['date'] = check_date
def _check_choice(self):
"""FIXME: need to override this due to optik misdesign"""
diff --git a/testlib.py b/testlib.py
index b7a4744..b69359f 100644
--- a/testlib.py
+++ b/testlib.py
@@ -1063,3 +1063,6 @@ def enable_dbc(*args):
return True
+class AttrObject:
+ def __init__(self, **kwargs):
+ self.__dict__.update(kwargs)