Package logilab-common-0 ::
Package 36 ::
Package 1 ::
Module optik_ext
|
|
1 """Add an abstraction level to transparently import optik classes from optparse
2 (python >= 2.3) or the optik package.
3
4 It also defines three new types for optik/optparse command line parser :
5
6 * regexp
7 argument of this type will be converted using re.compile
8 * csv
9 argument of this type will be converted using split(',')
10 * yn
11 argument of this type will be true if 'y' or 'yes', false if 'n' or 'no'
12 * named
13 argument of this type are in the form <NAME>=<VALUE> or <NAME>:<VALUE>
14
15
16 :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
17 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
18 :license: General Public License version 2 - http://www.gnu.org/licenses
19 """
20 __docformat__ = "restructuredtext en"
21
22 import re
23 import sys
24 import time
25 from copy import copy
26 from os.path import exists
27
28 try:
29
30 from optparse import OptionParser as BaseParser, Option as BaseOption, \
31 OptionGroup, OptionValueError, OptionError, Values, HelpFormatter, \
32 NO_DEFAULT, SUPPRESS_HELP
33 except ImportError:
34
35 from optik import OptionParser as BaseParser, Option as BaseOption, \
36 OptionGroup, OptionValueError, OptionError, Values, HelpFormatter
37 try:
38 from optik import NO_DEFAULT
39 except:
40 NO_DEFAULT = []
41
42 try:
43 from mx import DateTime
44 HAS_MX_DATETIME = True
45 except ImportError:
46 HAS_MX_DATETIME = False
47
48
49 OPTPARSE_FORMAT_DEFAULT = sys.version_info >= (2, 4)
50
51 from logilab.common.textutils import get_csv
52
54 """check a regexp value by trying to compile it
55 return the compiled regexp
56 """
57 if hasattr(value, 'pattern'):
58 return value
59 try:
60 return re.compile(value)
61 except ValueError:
62 raise OptionValueError(
63 "option %s: invalid regexp value: %r" % (opt, value))
64
66 """check a csv value by trying to split it
67 return the list of separated values
68 """
69 if isinstance(value, (list, tuple)):
70 return value
71 try:
72 return get_csv(value)
73 except ValueError:
74 raise OptionValueError(
75 "option %s: invalid csv value: %r" % (opt, value))
76
78 """check a yn value
79 return true for yes and false for no
80 """
81 if isinstance(value, int):
82 return bool(value)
83 if value in ('y', 'yes'):
84 return True
85 if value in ('n', 'no'):
86 return False
87 msg = "option %s: invalid yn value %r, should be in (y, yes, n, no)"
88 raise OptionValueError(msg % (opt, value))
89
91 """check a named value
92 return a dictionnary containing (name, value) associations
93 """
94 if isinstance(value, dict):
95 return value
96 values = []
97 for value in check_csv(option, opt, value):
98 if value.find('=') != -1:
99 values.append(value.split('=', 1))
100 elif value.find(':') != -1:
101 values.append(value.split(':', 1))
102 if values:
103 return dict(values)
104 msg = "option %s: invalid named value %r, should be <NAME>=<VALUE> or \
105 <NAME>:<VALUE>"
106 raise OptionValueError(msg % (opt, value))
107
109 """check a password value (can't be empty)
110 """
111
112 return value
113
115 """check a file value
116 return the filepath
117 """
118 if exists(value):
119 return value
120 msg = "option %s: file %r does not exist"
121 raise OptionValueError(msg % (opt, value))
122
124 """check a file value
125 return the filepath
126 """
127 try:
128 return DateTime.strptime(value, "%Y/%m/%d")
129 except DateTime.Error :
130 raise OptionValueError(
131 "expected format of %s is yyyy/mm/dd" % opt)
132
134 """check a color value and returns it
135 /!\ does *not* check color labels (like 'red', 'green'), only
136 checks hexadecimal forms
137 """
138
139 if re.match('[a-z0-9 ]+$', value, re.I):
140 return value
141
142 if re.match('#[a-f0-9]{6}', value, re.I):
143 return value
144
145 msg = "option %s: invalid color : %r, should be either hexadecimal \
146 value or predefinied color"
147 raise OptionValueError(msg % (opt, value))
148
149 import types
150
152 """override optik.Option to add some new option types
153 """
154 TYPES = BaseOption.TYPES + ('regexp', 'csv', 'yn', 'named', 'password',
155 'multiple_choice', 'file', 'font', 'color')
156 ATTRS = BaseOption.ATTRS + ['hide']
157 TYPE_CHECKER = copy(BaseOption.TYPE_CHECKER)
158 TYPE_CHECKER['regexp'] = check_regexp
159 TYPE_CHECKER['csv'] = check_csv
160 TYPE_CHECKER['yn'] = check_yn
161 TYPE_CHECKER['named'] = check_named
162 TYPE_CHECKER['multiple_choice'] = check_csv
163 TYPE_CHECKER['file'] = check_file
164 TYPE_CHECKER['color'] = check_color
165 TYPE_CHECKER['password'] = check_password
166 if HAS_MX_DATETIME:
167 TYPES += ('date',)
168 TYPE_CHECKER['date'] = check_date
169
171 BaseOption.__init__(self, *opts, **attrs)
172 if hasattr(self, "hide") and self.hide:
173 self.help = SUPPRESS_HELP
174
176 """FIXME: need to override this due to optik misdesign"""
177 if self.type in ("choice", "multiple_choice"):
178 if self.choices is None:
179 raise OptionError(
180 "must supply a list of choices for type 'choice'", self)
181 elif type(self.choices) not in (types.TupleType, types.ListType):
182 raise OptionError(
183 "choices must be a list of strings ('%s' supplied)"
184 % str(type(self.choices)).split("'")[1], self)
185 elif self.choices is not None:
186 raise OptionError(
187 "must not supply choices for type %r" % self.type, self)
188 BaseOption.CHECK_METHODS[2] = _check_choice
189
190
191 - def process(self, opt, value, values, parser):
192
193
194 try:
195 value = self.convert_value(opt, value)
196 except AttributeError:
197 value = self.check_value(opt, value)
198 if self.type == 'named':
199 existant = getattr(values, self.dest)
200 if existant:
201 existant.update(value)
202 value = existant
203
204
205
206 return self.take_action(
207 self.action, self.dest, opt, value, values, parser)
208
210 """override optik.OptionParser to use our Option class
211 """
214
215
318
319
320 -def generate_manpage(optparser, pkginfo, section=1, stream=sys.stdout):
321 """generate a man page from an optik parser"""
322 formatter = ManHelpFormatter()
323 formatter.parser = optparser
324 print >> stream, formatter.format_head(optparser, pkginfo, section)
325 print >> stream, optparser.format_option_help(formatter)
326 print >> stream, formatter.format_tail(pkginfo)
327
328
329 __all__ = ('OptionParser', 'Option', 'OptionGroup', 'OptionValueError',
330 'Values')
331