gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / pylint / config.py @ 745
History | View | Annotate | Download (29.5 KB)
1 |
# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
|
---|---|
2 |
# This program is free software; you can redistribute it and/or modify it under
|
3 |
# the terms of the GNU General Public License as published by the Free Software
|
4 |
# Foundation; either version 2 of the License, or (at your option) any later
|
5 |
# version.
|
6 |
#
|
7 |
# This program is distributed in the hope that it will be useful, but WITHOUT
|
8 |
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
9 |
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
|
10 |
#
|
11 |
# You should have received a copy of the GNU General Public License along with
|
12 |
# this program; if not, write to the Free Software Foundation, Inc.,
|
13 |
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
14 |
"""utilities for Pylint configuration :
|
15 |
|
16 |
* pylintrc
|
17 |
* pylint.d (PYLINTHOME)
|
18 |
"""
|
19 |
from __future__ import print_function |
20 |
|
21 |
# TODO(cpopa): this module contains the logic for the
|
22 |
# configuration parser and for the command line parser,
|
23 |
# but it's really coupled to optparse's internals.
|
24 |
# The code was copied almost verbatim from logilab.common,
|
25 |
# in order to not depend on it anymore and it will definitely
|
26 |
# need a cleanup. It could be completely reengineered as well.
|
27 |
|
28 |
import contextlib |
29 |
import copy |
30 |
import optparse |
31 |
import os |
32 |
import pickle |
33 |
import re |
34 |
import sys |
35 |
import time |
36 |
|
37 |
from six.moves import configparser |
38 |
from six.moves import range |
39 |
|
40 |
from pylint import utils |
41 |
|
42 |
|
43 |
USER_HOME = os.path.expanduser('~')
|
44 |
if 'PYLINTHOME' in os.environ: |
45 |
PYLINT_HOME = os.environ['PYLINTHOME']
|
46 |
if USER_HOME == '~': |
47 |
USER_HOME = os.path.dirname(PYLINT_HOME) |
48 |
elif USER_HOME == '~': |
49 |
PYLINT_HOME = ".pylint.d"
|
50 |
else:
|
51 |
PYLINT_HOME = os.path.join(USER_HOME, '.pylint.d')
|
52 |
|
53 |
|
54 |
def _get_pdata_path(base_name, recurs): |
55 |
base_name = base_name.replace(os.sep, '_')
|
56 |
return os.path.join(PYLINT_HOME, "%s%s%s"%(base_name, recurs, '.stats')) |
57 |
|
58 |
|
59 |
def load_results(base): |
60 |
data_file = _get_pdata_path(base, 1)
|
61 |
try:
|
62 |
with open(data_file, _PICK_LOAD) as stream: |
63 |
return pickle.load(stream)
|
64 |
except Exception: # pylint: disable=broad-except |
65 |
return {}
|
66 |
|
67 |
if sys.version_info < (3, 0): |
68 |
_PICK_DUMP, _PICK_LOAD = 'w', 'r' |
69 |
else:
|
70 |
_PICK_DUMP, _PICK_LOAD = 'wb', 'rb' |
71 |
|
72 |
def save_results(results, base): |
73 |
if not os.path.exists(PYLINT_HOME): |
74 |
try:
|
75 |
os.mkdir(PYLINT_HOME) |
76 |
except OSError: |
77 |
print('Unable to create directory %s' % PYLINT_HOME, file=sys.stderr)
|
78 |
data_file = _get_pdata_path(base, 1)
|
79 |
try:
|
80 |
with open(data_file, _PICK_DUMP) as stream: |
81 |
pickle.dump(results, stream) |
82 |
except (IOError, OSError) as ex: |
83 |
print('Unable to create file %s: %s' % (data_file, ex), file=sys.stderr)
|
84 |
|
85 |
|
86 |
def find_pylintrc(): |
87 |
"""search the pylint rc file and return its path if it find it, else None
|
88 |
"""
|
89 |
# is there a pylint rc file in the current directory ?
|
90 |
if os.path.exists('pylintrc'): |
91 |
return os.path.abspath('pylintrc') |
92 |
if os.path.exists('.pylintrc'): |
93 |
return os.path.abspath('.pylintrc') |
94 |
if os.path.isfile('__init__.py'): |
95 |
curdir = os.path.abspath(os.getcwd()) |
96 |
while os.path.isfile(os.path.join(curdir, '__init__.py')): |
97 |
curdir = os.path.abspath(os.path.join(curdir, '..'))
|
98 |
if os.path.isfile(os.path.join(curdir, 'pylintrc')): |
99 |
return os.path.join(curdir, 'pylintrc') |
100 |
if os.path.isfile(os.path.join(curdir, '.pylintrc')): |
101 |
return os.path.join(curdir, '.pylintrc') |
102 |
if 'PYLINTRC' in os.environ and os.path.exists(os.environ['PYLINTRC']): |
103 |
pylintrc = os.environ['PYLINTRC']
|
104 |
else:
|
105 |
user_home = os.path.expanduser('~')
|
106 |
if user_home == '~' or user_home == '/root': |
107 |
pylintrc = ".pylintrc"
|
108 |
else:
|
109 |
pylintrc = os.path.join(user_home, '.pylintrc')
|
110 |
if not os.path.isfile(pylintrc): |
111 |
pylintrc = os.path.join(user_home, '.config', 'pylintrc') |
112 |
if not os.path.isfile(pylintrc): |
113 |
if os.path.isfile('/etc/pylintrc'): |
114 |
pylintrc = '/etc/pylintrc'
|
115 |
else:
|
116 |
pylintrc = None
|
117 |
return pylintrc
|
118 |
|
119 |
PYLINTRC = find_pylintrc() |
120 |
|
121 |
ENV_HELP = '''
|
122 |
The following environment variables are used:
|
123 |
* PYLINTHOME
|
124 |
Path to the directory where the persistent for the run will be stored. If
|
125 |
not found, it defaults to ~/.pylint.d/ or .pylint.d (in the current working
|
126 |
directory).
|
127 |
* PYLINTRC
|
128 |
Path to the configuration file. See the documentation for the method used
|
129 |
to search for configuration file.
|
130 |
''' % globals() |
131 |
|
132 |
|
133 |
class UnsupportedAction(Exception): |
134 |
"""raised by set_option when it doesn't know what to do for an action"""
|
135 |
|
136 |
|
137 |
def _choice_validator(optdict, name, value): |
138 |
if value not in optdict['choices']: |
139 |
msg = "option %s: invalid value: %r, should be in %s"
|
140 |
raise optparse.OptionValueError(msg % (name, value, optdict['choices'])) |
141 |
return value
|
142 |
|
143 |
|
144 |
def _multiple_choice_validator(optdict, name, value): |
145 |
choices = optdict['choices']
|
146 |
values = utils._check_csv(value) |
147 |
for value in values: |
148 |
if value not in choices: |
149 |
msg = "option %s: invalid value: %r, should be in %s"
|
150 |
raise optparse.OptionValueError(msg % (name, value, choices))
|
151 |
return values
|
152 |
|
153 |
|
154 |
# pylint: disable=unused-argument
|
155 |
def _csv_validator(_, name, value): |
156 |
return utils._check_csv(value)
|
157 |
|
158 |
|
159 |
# pylint: disable=unused-argument
|
160 |
def _regexp_validator(_, name, value): |
161 |
if hasattr(value, 'pattern'): |
162 |
return value
|
163 |
return re.compile(value)
|
164 |
|
165 |
|
166 |
def _yn_validator(opt, _, value): |
167 |
if isinstance(value, int): |
168 |
return bool(value) |
169 |
if value in ('y', 'yes'): |
170 |
return True |
171 |
if value in ('n', 'no'): |
172 |
return False |
173 |
msg = "option %s: invalid yn value %r, should be in (y, yes, n, no)"
|
174 |
raise optparse.OptionValueError(msg % (opt, value))
|
175 |
|
176 |
|
177 |
VALIDATORS = { |
178 |
'string': utils._unquote,
|
179 |
'int': int, |
180 |
'regexp': re.compile,
|
181 |
'csv': _csv_validator,
|
182 |
'yn': _yn_validator,
|
183 |
'choice': _choice_validator,
|
184 |
'multiple_choice': _multiple_choice_validator,
|
185 |
} |
186 |
|
187 |
def _call_validator(opttype, optdict, option, value): |
188 |
if opttype not in VALIDATORS: |
189 |
raise Exception('Unsupported type "%s"' % opttype) |
190 |
try:
|
191 |
return VALIDATORS[opttype](optdict, option, value)
|
192 |
except TypeError: |
193 |
try:
|
194 |
return VALIDATORS[opttype](value)
|
195 |
except Exception: |
196 |
raise optparse.OptionValueError('%s value (%r) should be of type %s' % |
197 |
(option, value, opttype)) |
198 |
|
199 |
|
200 |
def _validate(value, optdict, name=''): |
201 |
"""return a validated value for an option according to its type
|
202 |
|
203 |
optional argument name is only used for error message formatting
|
204 |
"""
|
205 |
try:
|
206 |
_type = optdict['type']
|
207 |
except KeyError: |
208 |
# FIXME
|
209 |
return value
|
210 |
return _call_validator(_type, optdict, name, value)
|
211 |
|
212 |
|
213 |
def _level_options(group, outputlevel): |
214 |
return [option for option in group.option_list |
215 |
if (getattr(option, 'level', 0) or 0) <= outputlevel |
216 |
and option.help is not optparse.SUPPRESS_HELP] |
217 |
|
218 |
|
219 |
def _expand_default(self, option): |
220 |
"""Patch OptionParser.expand_default with custom behaviour
|
221 |
|
222 |
This will handle defaults to avoid overriding values in the
|
223 |
configuration file.
|
224 |
"""
|
225 |
if self.parser is None or not self.default_tag: |
226 |
return option.help
|
227 |
optname = option._long_opts[0][2:] |
228 |
try:
|
229 |
provider = self.parser.options_manager._all_options[optname]
|
230 |
except KeyError: |
231 |
value = None
|
232 |
else:
|
233 |
optdict = provider.get_option_def(optname) |
234 |
optname = provider.option_attrname(optname, optdict) |
235 |
value = getattr(provider.config, optname, optdict)
|
236 |
value = utils._format_option_value(optdict, value) |
237 |
if value is optparse.NO_DEFAULT or not value: |
238 |
value = self.NO_DEFAULT_VALUE
|
239 |
return option.help.replace(self.default_tag, str(value)) |
240 |
|
241 |
|
242 |
@contextlib.contextmanager
|
243 |
def _patch_optparse(): |
244 |
orig_default = optparse.HelpFormatter |
245 |
try:
|
246 |
optparse.HelpFormatter.expand_default = _expand_default |
247 |
yield
|
248 |
finally:
|
249 |
optparse.HelpFormatter.expand_default = orig_default |
250 |
|
251 |
|
252 |
class Option(optparse.Option): |
253 |
TYPES = optparse.Option.TYPES + ('regexp', 'csv', 'yn', 'multiple_choice') |
254 |
ATTRS = optparse.Option.ATTRS + ['hide', 'level'] |
255 |
TYPE_CHECKER = copy.copy(optparse.Option.TYPE_CHECKER) |
256 |
TYPE_CHECKER['regexp'] = _regexp_validator
|
257 |
TYPE_CHECKER['csv'] = _csv_validator
|
258 |
TYPE_CHECKER['yn'] = _yn_validator
|
259 |
TYPE_CHECKER['multiple_choice'] = _multiple_choice_validator
|
260 |
|
261 |
def __init__(self, *opts, **attrs): |
262 |
optparse.Option.__init__(self, *opts, **attrs)
|
263 |
if hasattr(self, "hide") and self.hide: |
264 |
self.help = optparse.SUPPRESS_HELP
|
265 |
|
266 |
def _check_choice(self): |
267 |
if self.type in ("choice", "multiple_choice"): |
268 |
if self.choices is None: |
269 |
raise optparse.OptionError(
|
270 |
"must supply a list of choices for type 'choice'", self) |
271 |
elif not isinstance(self.choices, (tuple, list)): |
272 |
raise optparse.OptionError(
|
273 |
"choices must be a list of strings ('%s' supplied)"
|
274 |
% str(type(self.choices)).split("'")[1], self) |
275 |
elif self.choices is not None: |
276 |
raise optparse.OptionError(
|
277 |
"must not supply choices for type %r" % self.type, self) |
278 |
optparse.Option.CHECK_METHODS[2] = _check_choice
|
279 |
|
280 |
def process(self, opt, value, values, parser): |
281 |
# First, convert the value(s) to the right type. Howl if any
|
282 |
# value(s) are bogus.
|
283 |
value = self.convert_value(opt, value)
|
284 |
if self.type == 'named': |
285 |
existant = getattr(values, self.dest) |
286 |
if existant:
|
287 |
existant.update(value) |
288 |
value = existant |
289 |
# And then take whatever action is expected of us.
|
290 |
# This is a separate method to make life easier for
|
291 |
# subclasses to add new actions.
|
292 |
return self.take_action( |
293 |
self.action, self.dest, opt, value, values, parser) |
294 |
|
295 |
|
296 |
class OptionParser(optparse.OptionParser): |
297 |
|
298 |
def __init__(self, option_class=Option, *args, **kwargs): |
299 |
optparse.OptionParser.__init__(self, option_class=Option, *args, **kwargs)
|
300 |
|
301 |
def format_option_help(self, formatter=None): |
302 |
if formatter is None: |
303 |
formatter = self.formatter
|
304 |
outputlevel = getattr(formatter, 'output_level', 0) |
305 |
formatter.store_option_strings(self)
|
306 |
result = [] |
307 |
result.append(formatter.format_heading("Options"))
|
308 |
formatter.indent() |
309 |
if self.option_list: |
310 |
result.append(optparse.OptionContainer.format_option_help(self, formatter))
|
311 |
result.append("\n")
|
312 |
for group in self.option_groups: |
313 |
if group.level <= outputlevel and ( |
314 |
group.description or _level_options(group, outputlevel)):
|
315 |
result.append(group.format_help(formatter)) |
316 |
result.append("\n")
|
317 |
formatter.dedent() |
318 |
# Drop the last "\n", or the header if no options or option groups:
|
319 |
return "".join(result[:-1]) |
320 |
|
321 |
def _match_long_opt(self, opt): |
322 |
"""Disable abbreviations."""
|
323 |
if opt not in self._long_opt: |
324 |
raise optparse.BadOptionError(opt)
|
325 |
return opt
|
326 |
|
327 |
|
328 |
# pylint: disable=abstract-method; by design?
|
329 |
class _ManHelpFormatter(optparse.HelpFormatter): |
330 |
|
331 |
def __init__(self, indent_increment=0, max_help_position=24, |
332 |
width=79, short_first=0): |
333 |
optparse.HelpFormatter.__init__( |
334 |
self, indent_increment, max_help_position, width, short_first)
|
335 |
|
336 |
def format_heading(self, heading): |
337 |
return '.SH %s\n' % heading.upper() |
338 |
|
339 |
def format_description(self, description): |
340 |
return description
|
341 |
|
342 |
def format_option(self, option): |
343 |
try:
|
344 |
optstring = option.option_strings |
345 |
except AttributeError: |
346 |
optstring = self.format_option_strings(option)
|
347 |
if option.help:
|
348 |
help_text = self.expand_default(option)
|
349 |
help = ' '.join([l.strip() for l in help_text.splitlines()]) |
350 |
else:
|
351 |
help = ''
|
352 |
return '''.IP "%s" |
353 |
%s
|
354 |
''' % (optstring, help)
|
355 |
|
356 |
def format_head(self, optparser, pkginfo, section=1): |
357 |
long_desc = ""
|
358 |
try:
|
359 |
pgm = optparser._get_prog_name() |
360 |
except AttributeError: |
361 |
# py >= 2.4.X (dunno which X exactly, at least 2)
|
362 |
pgm = optparser.get_prog_name() |
363 |
short_desc = self.format_short_description(pgm, pkginfo.description)
|
364 |
if hasattr(pkginfo, "long_desc"): |
365 |
long_desc = self.format_long_description(pgm, pkginfo.long_desc)
|
366 |
return '%s\n%s\n%s\n%s' % (self.format_title(pgm, section), |
367 |
short_desc, self.format_synopsis(pgm),
|
368 |
long_desc) |
369 |
|
370 |
@staticmethod
|
371 |
def format_title(pgm, section): |
372 |
date = '-'.join(str(num) for num in time.localtime()[:3]) |
373 |
return '.TH %s %s "%s" %s' % (pgm, section, date, pgm) |
374 |
|
375 |
@staticmethod
|
376 |
def format_short_description(pgm, short_desc): |
377 |
return '''.SH NAME |
378 |
.B %s
|
379 |
\- %s
|
380 |
''' % (pgm, short_desc.strip())
|
381 |
|
382 |
@staticmethod
|
383 |
def format_synopsis(pgm): |
384 |
return '''.SH SYNOPSIS |
385 |
.B %s
|
386 |
[
|
387 |
.I OPTIONS
|
388 |
] [
|
389 |
.I <arguments>
|
390 |
]
|
391 |
''' % pgm
|
392 |
|
393 |
@staticmethod
|
394 |
def format_long_description(pgm, long_desc): |
395 |
long_desc = '\n'.join(line.lstrip()
|
396 |
for line in long_desc.splitlines()) |
397 |
long_desc = long_desc.replace('\n.\n', '\n\n') |
398 |
if long_desc.lower().startswith(pgm):
|
399 |
long_desc = long_desc[len(pgm):]
|
400 |
return '''.SH DESCRIPTION |
401 |
.B %s
|
402 |
%s
|
403 |
''' % (pgm, long_desc.strip())
|
404 |
|
405 |
@staticmethod
|
406 |
def format_tail(pkginfo): |
407 |
tail = '''.SH SEE ALSO
|
408 |
/usr/share/doc/pythonX.Y-%s/
|
409 |
|
410 |
.SH BUGS
|
411 |
Please report bugs on the project\'s mailing list:
|
412 |
%s
|
413 |
|
414 |
.SH AUTHOR
|
415 |
%s <%s>
|
416 |
''' % (getattr(pkginfo, 'debian_name', pkginfo.modname), |
417 |
pkginfo.mailinglist, pkginfo.author, pkginfo.author_email) |
418 |
|
419 |
if hasattr(pkginfo, "copyright"): |
420 |
tail += '''
|
421 |
.SH COPYRIGHT
|
422 |
%s
|
423 |
''' % pkginfo.copyright
|
424 |
|
425 |
return tail
|
426 |
|
427 |
|
428 |
class OptionsManagerMixIn(object): |
429 |
"""Handle configuration from both a configuration file and command line options"""
|
430 |
|
431 |
def __init__(self, usage, config_file=None, version=None, quiet=0): |
432 |
self.config_file = config_file
|
433 |
self.reset_parsers(usage, version=version)
|
434 |
# list of registered options providers
|
435 |
self.options_providers = []
|
436 |
# dictionary associating option name to checker
|
437 |
self._all_options = {}
|
438 |
self._short_options = {}
|
439 |
self._nocallback_options = {}
|
440 |
self._mygroups = {}
|
441 |
# verbosity
|
442 |
self.quiet = quiet
|
443 |
self._maxlevel = 0 |
444 |
|
445 |
def reset_parsers(self, usage='', version=None): |
446 |
# configuration file parser
|
447 |
self.cfgfile_parser = configparser.ConfigParser()
|
448 |
# command line parser
|
449 |
self.cmdline_parser = OptionParser(usage=usage, version=version)
|
450 |
self.cmdline_parser.options_manager = self |
451 |
self._optik_option_attrs = set(self.cmdline_parser.option_class.ATTRS) |
452 |
|
453 |
def register_options_provider(self, provider, own_group=True): |
454 |
"""register an options provider"""
|
455 |
assert provider.priority <= 0, "provider's priority can't be >= 0" |
456 |
for i in range(len(self.options_providers)): |
457 |
if provider.priority > self.options_providers[i].priority: |
458 |
self.options_providers.insert(i, provider)
|
459 |
break
|
460 |
else:
|
461 |
self.options_providers.append(provider)
|
462 |
non_group_spec_options = [option for option in provider.options |
463 |
if 'group' not in option[1]] |
464 |
groups = getattr(provider, 'option_groups', ()) |
465 |
if own_group and non_group_spec_options: |
466 |
self.add_option_group(provider.name.upper(), provider.__doc__,
|
467 |
non_group_spec_options, provider) |
468 |
else:
|
469 |
for opt, optdict in non_group_spec_options: |
470 |
self.add_optik_option(provider, self.cmdline_parser, opt, optdict) |
471 |
for gname, gdoc in groups: |
472 |
gname = gname.upper() |
473 |
goptions = [option for option in provider.options |
474 |
if option[1].get('group', '').upper() == gname] |
475 |
self.add_option_group(gname, gdoc, goptions, provider)
|
476 |
|
477 |
def add_option_group(self, group_name, _, options, provider): |
478 |
# add option group to the command line parser
|
479 |
if group_name in self._mygroups: |
480 |
group = self._mygroups[group_name]
|
481 |
else:
|
482 |
group = optparse.OptionGroup(self.cmdline_parser,
|
483 |
title=group_name.capitalize()) |
484 |
self.cmdline_parser.add_option_group(group)
|
485 |
group.level = provider.level |
486 |
self._mygroups[group_name] = group
|
487 |
# add section to the config file
|
488 |
if group_name != "DEFAULT": |
489 |
self.cfgfile_parser.add_section(group_name)
|
490 |
# add provider's specific options
|
491 |
for opt, optdict in options: |
492 |
self.add_optik_option(provider, group, opt, optdict)
|
493 |
|
494 |
def add_optik_option(self, provider, optikcontainer, opt, optdict): |
495 |
args, optdict = self.optik_option(provider, opt, optdict)
|
496 |
option = optikcontainer.add_option(*args, **optdict) |
497 |
self._all_options[opt] = provider
|
498 |
self._maxlevel = max(self._maxlevel, option.level or 0) |
499 |
|
500 |
def optik_option(self, provider, opt, optdict): |
501 |
"""get our personal option definition and return a suitable form for
|
502 |
use with optik/optparse
|
503 |
"""
|
504 |
optdict = copy.copy(optdict) |
505 |
if 'action' in optdict: |
506 |
self._nocallback_options[provider] = opt
|
507 |
else:
|
508 |
optdict['action'] = 'callback' |
509 |
optdict['callback'] = self.cb_set_provider_option |
510 |
# default is handled here and *must not* be given to optik if you
|
511 |
# want the whole machinery to work
|
512 |
if 'default' in optdict: |
513 |
if ('help' in optdict |
514 |
and optdict.get('default') is not None |
515 |
and optdict['action'] not in ('store_true', 'store_false')): |
516 |
optdict['help'] += ' [current: %default]' |
517 |
del optdict['default'] |
518 |
args = ['--' + str(opt)] |
519 |
if 'short' in optdict: |
520 |
self._short_options[optdict['short']] = opt |
521 |
args.append('-' + optdict['short']) |
522 |
del optdict['short'] |
523 |
# cleanup option definition dict before giving it to optik
|
524 |
for key in list(optdict.keys()): |
525 |
if key not in self._optik_option_attrs: |
526 |
optdict.pop(key) |
527 |
return args, optdict
|
528 |
|
529 |
def cb_set_provider_option(self, option, opt, value, parser): |
530 |
"""optik callback for option setting"""
|
531 |
if opt.startswith('--'): |
532 |
# remove -- on long option
|
533 |
opt = opt[2:]
|
534 |
else:
|
535 |
# short option, get its long equivalent
|
536 |
opt = self._short_options[opt[1:]] |
537 |
# trick since we can't set action='store_true' on options
|
538 |
if value is None: |
539 |
value = 1
|
540 |
self.global_set_option(opt, value)
|
541 |
|
542 |
def global_set_option(self, opt, value): |
543 |
"""set option on the correct option provider"""
|
544 |
self._all_options[opt].set_option(opt, value)
|
545 |
|
546 |
def generate_config(self, stream=None, skipsections=(), encoding=None): |
547 |
"""write a configuration file according to the current configuration
|
548 |
into the given stream or stdout
|
549 |
"""
|
550 |
options_by_section = {} |
551 |
sections = [] |
552 |
for provider in self.options_providers: |
553 |
for section, options in provider.options_by_section(): |
554 |
if section is None: |
555 |
section = provider.name |
556 |
if section in skipsections: |
557 |
continue
|
558 |
options = [(n, d, v) for (n, d, v) in options |
559 |
if d.get('type') is not None |
560 |
and not d.get('deprecated')] |
561 |
if not options: |
562 |
continue
|
563 |
if section not in sections: |
564 |
sections.append(section) |
565 |
alloptions = options_by_section.setdefault(section, []) |
566 |
alloptions += options |
567 |
stream = stream or sys.stdout
|
568 |
encoding = utils._get_encoding(encoding, stream) |
569 |
printed = False
|
570 |
for section in sections: |
571 |
if printed:
|
572 |
print('\n', file=stream)
|
573 |
utils.format_section(stream, section.upper(), |
574 |
options_by_section[section], |
575 |
encoding) |
576 |
printed = True
|
577 |
|
578 |
def generate_manpage(self, pkginfo, section=1, stream=None): |
579 |
with _patch_optparse():
|
580 |
_generate_manpage(self.cmdline_parser, pkginfo,
|
581 |
section, stream=stream or sys.stdout,
|
582 |
level=self._maxlevel)
|
583 |
|
584 |
def load_provider_defaults(self): |
585 |
"""initialize configuration using default values"""
|
586 |
for provider in self.options_providers: |
587 |
provider.load_defaults() |
588 |
|
589 |
def read_config_file(self, config_file=None): |
590 |
"""read the configuration file but do not load it (i.e. dispatching
|
591 |
values to each options provider)
|
592 |
"""
|
593 |
helplevel = 1
|
594 |
while helplevel <= self._maxlevel: |
595 |
opt = '-'.join(['long'] * helplevel) + '-help' |
596 |
if opt in self._all_options: |
597 |
break # already processed |
598 |
# pylint: disable=unused-argument
|
599 |
def helpfunc(option, opt, val, p, level=helplevel): |
600 |
print(self.help(level))
|
601 |
sys.exit(0)
|
602 |
helpmsg = '%s verbose help.' % ' '.join(['more'] * helplevel) |
603 |
optdict = {'action': 'callback', 'callback': helpfunc, |
604 |
'help': helpmsg}
|
605 |
provider = self.options_providers[0] |
606 |
self.add_optik_option(provider, self.cmdline_parser, opt, optdict) |
607 |
provider.options += ((opt, optdict),) |
608 |
helplevel += 1
|
609 |
if config_file is None: |
610 |
config_file = self.config_file
|
611 |
if config_file is not None: |
612 |
config_file = os.path.expanduser(config_file) |
613 |
if config_file and os.path.exists(config_file): |
614 |
parser = self.cfgfile_parser
|
615 |
parser.read([config_file]) |
616 |
# normalize sections'title
|
617 |
for sect, values in list(parser._sections.items()): |
618 |
if not sect.isupper() and values: |
619 |
parser._sections[sect.upper()] = values |
620 |
elif not self.quiet: |
621 |
msg = 'No config file found, using default configuration'
|
622 |
#print(msg, file=sys.stderr)
|
623 |
return
|
624 |
|
625 |
def load_config_file(self): |
626 |
"""dispatch values previously read from a configuration file to each
|
627 |
options provider)
|
628 |
"""
|
629 |
parser = self.cfgfile_parser
|
630 |
for section in parser.sections(): |
631 |
for option, value in parser.items(section): |
632 |
try:
|
633 |
self.global_set_option(option, value)
|
634 |
except (KeyError, optparse.OptionError): |
635 |
# TODO handle here undeclared options appearing in the config file
|
636 |
continue
|
637 |
|
638 |
def load_configuration(self, **kwargs): |
639 |
"""override configuration according to given parameters"""
|
640 |
for opt, opt_value in kwargs.items(): |
641 |
opt = opt.replace('_', '-') |
642 |
provider = self._all_options[opt]
|
643 |
provider.set_option(opt, opt_value) |
644 |
|
645 |
def load_command_line_configuration(self, args=None): |
646 |
"""Override configuration according to command line parameters
|
647 |
|
648 |
return additional arguments
|
649 |
"""
|
650 |
with _patch_optparse():
|
651 |
if args is None: |
652 |
args = sys.argv[1:]
|
653 |
else:
|
654 |
args = list(args)
|
655 |
(options, args) = self.cmdline_parser.parse_args(args=args)
|
656 |
for provider in self._nocallback_options.keys(): |
657 |
config = provider.config |
658 |
for attr in config.__dict__.keys(): |
659 |
value = getattr(options, attr, None) |
660 |
if value is None: |
661 |
continue
|
662 |
setattr(config, attr, value)
|
663 |
return args
|
664 |
|
665 |
def add_help_section(self, title, description, level=0): |
666 |
"""add a dummy option section for help purpose """
|
667 |
group = optparse.OptionGroup(self.cmdline_parser,
|
668 |
title=title.capitalize(), |
669 |
description=description) |
670 |
group.level = level |
671 |
self._maxlevel = max(self._maxlevel, level) |
672 |
self.cmdline_parser.add_option_group(group)
|
673 |
|
674 |
def help(self, level=0): |
675 |
"""return the usage string for available options """
|
676 |
self.cmdline_parser.formatter.output_level = level
|
677 |
with _patch_optparse():
|
678 |
return self.cmdline_parser.format_help() |
679 |
|
680 |
|
681 |
class OptionsProviderMixIn(object): |
682 |
"""Mixin to provide options to an OptionsManager"""
|
683 |
|
684 |
# those attributes should be overridden
|
685 |
priority = -1
|
686 |
name = 'default'
|
687 |
options = () |
688 |
level = 0
|
689 |
|
690 |
def __init__(self): |
691 |
self.config = optparse.Values()
|
692 |
self.load_defaults()
|
693 |
|
694 |
def load_defaults(self): |
695 |
"""initialize the provider using default values"""
|
696 |
for opt, optdict in self.options: |
697 |
action = optdict.get('action')
|
698 |
if action != 'callback': |
699 |
# callback action have no default
|
700 |
if optdict is None: |
701 |
optdict = self.get_option_def(opt)
|
702 |
default = optdict.get('default')
|
703 |
self.set_option(opt, default, action, optdict)
|
704 |
|
705 |
def option_attrname(self, opt, optdict=None): |
706 |
"""get the config attribute corresponding to opt"""
|
707 |
if optdict is None: |
708 |
optdict = self.get_option_def(opt)
|
709 |
return optdict.get('dest', opt.replace('-', '_')) |
710 |
|
711 |
def option_value(self, opt): |
712 |
"""get the current value for the given option"""
|
713 |
return getattr(self.config, self.option_attrname(opt), None) |
714 |
|
715 |
def set_option(self, opt, value, action=None, optdict=None): |
716 |
"""method called to set an option (registered in the options list)"""
|
717 |
if optdict is None: |
718 |
optdict = self.get_option_def(opt)
|
719 |
if value is not None: |
720 |
value = _validate(value, optdict, opt) |
721 |
if action is None: |
722 |
action = optdict.get('action', 'store') |
723 |
if action == 'store': |
724 |
setattr(self.config, self.option_attrname(opt, optdict), value) |
725 |
elif action in ('store_true', 'count'): |
726 |
setattr(self.config, self.option_attrname(opt, optdict), 0) |
727 |
elif action == 'store_false': |
728 |
setattr(self.config, self.option_attrname(opt, optdict), 1) |
729 |
elif action == 'append': |
730 |
opt = self.option_attrname(opt, optdict)
|
731 |
_list = getattr(self.config, opt, None) |
732 |
if _list is None: |
733 |
if isinstance(value, (list, tuple)): |
734 |
_list = value |
735 |
elif value is not None: |
736 |
_list = [] |
737 |
_list.append(value) |
738 |
setattr(self.config, opt, _list) |
739 |
elif isinstance(_list, tuple): |
740 |
setattr(self.config, opt, _list + (value,)) |
741 |
else:
|
742 |
_list.append(value) |
743 |
elif action == 'callback': |
744 |
optdict['callback'](None, opt, value, None) |
745 |
else:
|
746 |
raise UnsupportedAction(action)
|
747 |
|
748 |
def get_option_def(self, opt): |
749 |
"""return the dictionary defining an option given its name"""
|
750 |
assert self.options |
751 |
for option in self.options: |
752 |
if option[0] == opt: |
753 |
return option[1] |
754 |
raise optparse.OptionError('no such option %s in section %r' |
755 |
% (opt, self.name), opt)
|
756 |
|
757 |
def options_by_section(self): |
758 |
"""return an iterator on options grouped by section
|
759 |
|
760 |
(section, [list of (optname, optdict, optvalue)])
|
761 |
"""
|
762 |
sections = {} |
763 |
for optname, optdict in self.options: |
764 |
sections.setdefault(optdict.get('group'), []).append(
|
765 |
(optname, optdict, self.option_value(optname)))
|
766 |
if None in sections: |
767 |
yield None, sections.pop(None) |
768 |
for section, options in sorted(sections.items()): |
769 |
yield section.upper(), options
|
770 |
|
771 |
def options_and_values(self, options=None): |
772 |
if options is None: |
773 |
options = self.options
|
774 |
for optname, optdict in options: |
775 |
yield (optname, optdict, self.option_value(optname)) |
776 |
|
777 |
|
778 |
class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn): |
779 |
"""basic mixin for simple configurations which don't need the
|
780 |
manager / providers model
|
781 |
"""
|
782 |
def __init__(self, *args, **kwargs): |
783 |
if not args: |
784 |
kwargs.setdefault('usage', '') |
785 |
kwargs.setdefault('quiet', 1) |
786 |
OptionsManagerMixIn.__init__(self, *args, **kwargs)
|
787 |
OptionsProviderMixIn.__init__(self)
|
788 |
if not getattr(self, 'option_groups', None): |
789 |
self.option_groups = []
|
790 |
for _, optdict in self.options: |
791 |
try:
|
792 |
gdef = (optdict['group'].upper(), '') |
793 |
except KeyError: |
794 |
continue
|
795 |
if gdef not in self.option_groups: |
796 |
self.option_groups.append(gdef)
|
797 |
self.register_options_provider(self, own_group=False) |
798 |
|
799 |
|
800 |
def _generate_manpage(optparser, pkginfo, section=1, |
801 |
stream=sys.stdout, level=0):
|
802 |
formatter = _ManHelpFormatter() |
803 |
formatter.output_level = level |
804 |
formatter.parser = optparser |
805 |
print(formatter.format_head(optparser, pkginfo, section), file=stream) |
806 |
print(optparser.format_option_help(formatter), file=stream) |
807 |
print(formatter.format_tail(pkginfo), file=stream) |