1 | import logging |
---|
2 | import optparse |
---|
3 | import os |
---|
4 | import re |
---|
5 | import sys |
---|
6 | import ConfigParser |
---|
7 | from optparse import OptionParser |
---|
8 | from nose.util import absdir, tolist |
---|
9 | from nose.plugins.manager import NoPlugins |
---|
10 | from warnings import warn |
---|
11 | |
---|
12 | log = logging.getLogger(__name__) |
---|
13 | |
---|
14 | # not allowed in config files |
---|
15 | option_blacklist = ['help', 'verbose'] |
---|
16 | |
---|
17 | config_files = [ |
---|
18 | # Linux users will prefer this |
---|
19 | "~/.noserc", |
---|
20 | # Windows users will prefer this |
---|
21 | "~/nose.cfg" |
---|
22 | ] |
---|
23 | |
---|
24 | # plaforms on which the exe check defaults to off |
---|
25 | # Windows and IronPython |
---|
26 | exe_allowed_platforms = ('win32', 'cli') |
---|
27 | |
---|
28 | |
---|
29 | class NoSuchOptionError(Exception): |
---|
30 | def __init__(self, name): |
---|
31 | Exception.__init__(self, name) |
---|
32 | self.name = name |
---|
33 | |
---|
34 | |
---|
35 | class ConfigError(Exception): |
---|
36 | pass |
---|
37 | |
---|
38 | |
---|
39 | class ConfiguredDefaultsOptionParser(object): |
---|
40 | """ |
---|
41 | Handler for options from commandline and config files. |
---|
42 | """ |
---|
43 | def __init__(self, parser, config_section, error=None, file_error=None): |
---|
44 | self._parser = parser |
---|
45 | self._config_section = config_section |
---|
46 | if error is None: |
---|
47 | error = self._parser.error |
---|
48 | self._error = error |
---|
49 | if file_error is None: |
---|
50 | file_error = lambda msg, **kw: error(msg) |
---|
51 | self._file_error = file_error |
---|
52 | |
---|
53 | def _configTuples(self, cfg, filename): |
---|
54 | config = [] |
---|
55 | if self._config_section in cfg.sections(): |
---|
56 | for name, value in cfg.items(self._config_section): |
---|
57 | config.append((name, value, filename)) |
---|
58 | return config |
---|
59 | |
---|
60 | def _readFromFilenames(self, filenames): |
---|
61 | config = [] |
---|
62 | for filename in filenames: |
---|
63 | cfg = ConfigParser.RawConfigParser() |
---|
64 | try: |
---|
65 | cfg.read(filename) |
---|
66 | except ConfigParser.Error, exc: |
---|
67 | raise ConfigError("Error reading config file %r: %s" % |
---|
68 | (filename, str(exc))) |
---|
69 | config.extend(self._configTuples(cfg, filename)) |
---|
70 | return config |
---|
71 | |
---|
72 | def _readFromFileObject(self, fh): |
---|
73 | cfg = ConfigParser.RawConfigParser() |
---|
74 | try: |
---|
75 | filename = fh.name |
---|
76 | except AttributeError: |
---|
77 | filename = '<???>' |
---|
78 | try: |
---|
79 | cfg.readfp(fh) |
---|
80 | except ConfigParser.Error, exc: |
---|
81 | raise ConfigError("Error reading config file %r: %s" % |
---|
82 | (filename, str(exc))) |
---|
83 | return self._configTuples(cfg, filename) |
---|
84 | |
---|
85 | def _readConfiguration(self, config_files): |
---|
86 | try: |
---|
87 | config_files.readline |
---|
88 | except AttributeError: |
---|
89 | filename_or_filenames = config_files |
---|
90 | if isinstance(filename_or_filenames, basestring): |
---|
91 | filenames = [filename_or_filenames] |
---|
92 | else: |
---|
93 | filenames = filename_or_filenames |
---|
94 | config = self._readFromFilenames(filenames) |
---|
95 | else: |
---|
96 | fh = config_files |
---|
97 | config = self._readFromFileObject(fh) |
---|
98 | return config |
---|
99 | |
---|
100 | def _processConfigValue(self, name, value, values, parser): |
---|
101 | opt_str = '--' + name |
---|
102 | option = parser.get_option(opt_str) |
---|
103 | if option is None: |
---|
104 | raise NoSuchOptionError(name) |
---|
105 | else: |
---|
106 | option.process(opt_str, value, values, parser) |
---|
107 | |
---|
108 | def _applyConfigurationToValues(self, parser, config, values): |
---|
109 | for name, value, filename in config: |
---|
110 | if name in option_blacklist: |
---|
111 | continue |
---|
112 | try: |
---|
113 | self._processConfigValue(name, value, values, parser) |
---|
114 | except NoSuchOptionError, exc: |
---|
115 | self._file_error( |
---|
116 | "Error reading config file %r: " |
---|
117 | "no such option %r" % (filename, exc.name), |
---|
118 | name=name, filename=filename) |
---|
119 | except optparse.OptionValueError, exc: |
---|
120 | msg = str(exc).replace('--' + name, repr(name), 1) |
---|
121 | self._file_error("Error reading config file %r: " |
---|
122 | "%s" % (filename, msg), |
---|
123 | name=name, filename=filename) |
---|
124 | |
---|
125 | def parseArgsAndConfigFiles(self, args, config_files): |
---|
126 | values = self._parser.get_default_values() |
---|
127 | try: |
---|
128 | config = self._readConfiguration(config_files) |
---|
129 | except ConfigError, exc: |
---|
130 | self._error(str(exc)) |
---|
131 | else: |
---|
132 | self._applyConfigurationToValues(self._parser, config, values) |
---|
133 | return self._parser.parse_args(args, values) |
---|
134 | |
---|
135 | |
---|
136 | class Config(object): |
---|
137 | """nose configuration. |
---|
138 | |
---|
139 | Instances of Config are used throughout nose to configure |
---|
140 | behavior, including plugin lists. Here are the default values for |
---|
141 | all config keys:: |
---|
142 | |
---|
143 | self.env = env = kw.pop('env', {}) |
---|
144 | self.args = () |
---|
145 | self.testMatch = re.compile(r'(?:^|[\\b_\\.%s-])[Tt]est' % os.sep) |
---|
146 | self.addPaths = not env.get('NOSE_NOPATH', False) |
---|
147 | self.configSection = 'nosetests' |
---|
148 | self.debug = env.get('NOSE_DEBUG') |
---|
149 | self.debugLog = env.get('NOSE_DEBUG_LOG') |
---|
150 | self.exclude = None |
---|
151 | self.getTestCaseNamesCompat = False |
---|
152 | self.includeExe = env.get('NOSE_INCLUDE_EXE', |
---|
153 | sys.platform in exe_allowed_platforms) |
---|
154 | self.ignoreFiles = (re.compile(r'^\.'), |
---|
155 | re.compile(r'^_'), |
---|
156 | re.compile(r'^setup\.py$') |
---|
157 | ) |
---|
158 | self.include = None |
---|
159 | self.loggingConfig = None |
---|
160 | self.logStream = sys.stderr |
---|
161 | self.options = NoOptions() |
---|
162 | self.parser = None |
---|
163 | self.plugins = NoPlugins() |
---|
164 | self.srcDirs = ('lib', 'src') |
---|
165 | self.runOnInit = True |
---|
166 | self.stopOnError = env.get('NOSE_STOP', False) |
---|
167 | self.stream = sys.stderr |
---|
168 | self.testNames = () |
---|
169 | self.verbosity = int(env.get('NOSE_VERBOSE', 1)) |
---|
170 | self.where = () |
---|
171 | self.workingDir = None |
---|
172 | """ |
---|
173 | |
---|
174 | def __init__(self, **kw): |
---|
175 | self.env = env = kw.pop('env', {}) |
---|
176 | self.args = () |
---|
177 | self.testMatchPat = env.get('NOSE_TESTMATCH', |
---|
178 | r'(?:^|[\b_\.%s-])[Tt]est' % os.sep) |
---|
179 | self.testMatch = re.compile(self.testMatchPat) |
---|
180 | self.addPaths = not env.get('NOSE_NOPATH', False) |
---|
181 | self.configSection = 'nosetests' |
---|
182 | self.debug = env.get('NOSE_DEBUG') |
---|
183 | self.debugLog = env.get('NOSE_DEBUG_LOG') |
---|
184 | self.exclude = None |
---|
185 | self.getTestCaseNamesCompat = False |
---|
186 | self.includeExe = env.get('NOSE_INCLUDE_EXE', |
---|
187 | sys.platform in exe_allowed_platforms) |
---|
188 | self.ignoreFiles = (re.compile(r'^\.'), |
---|
189 | re.compile(r'^_'), |
---|
190 | re.compile(r'^setup\.py$') |
---|
191 | ) |
---|
192 | self.include = None |
---|
193 | self.loggingConfig = None |
---|
194 | self.logStream = sys.stderr |
---|
195 | self.options = NoOptions() |
---|
196 | self.parser = None |
---|
197 | self.plugins = NoPlugins() |
---|
198 | self.srcDirs = ('lib', 'src') |
---|
199 | self.runOnInit = True |
---|
200 | self.stopOnError = env.get('NOSE_STOP', False) |
---|
201 | self.stream = sys.stderr |
---|
202 | self.testNames = [] |
---|
203 | self.verbosity = int(env.get('NOSE_VERBOSE', 1)) |
---|
204 | self.where = () |
---|
205 | self.workingDir = os.getcwd() |
---|
206 | self.traverseNamespace = False |
---|
207 | self.firstPackageWins = False |
---|
208 | self.parserClass = OptionParser |
---|
209 | |
---|
210 | self._default = self.__dict__.copy() |
---|
211 | self.update(kw) |
---|
212 | self._orig = self.__dict__.copy() |
---|
213 | |
---|
214 | def __repr__(self): |
---|
215 | d = self.__dict__.copy() |
---|
216 | # don't expose env, could include sensitive info |
---|
217 | d['env'] = {} |
---|
218 | keys = [ k for k in d.keys() |
---|
219 | if not k.startswith('_') ] |
---|
220 | keys.sort() |
---|
221 | return "Config(%s)" % ', '.join([ '%s=%r' % (k, d[k]) |
---|
222 | for k in keys ]) |
---|
223 | __str__ = __repr__ |
---|
224 | |
---|
225 | def _parseArgs(self, argv, cfg_files): |
---|
226 | def warn_sometimes(msg, name=None, filename=None): |
---|
227 | if (hasattr(self.plugins, 'excludedOption') and |
---|
228 | self.plugins.excludedOption(name)): |
---|
229 | msg = ("Option %r in config file %r ignored: " |
---|
230 | "excluded by runtime environment" % |
---|
231 | (name, filename)) |
---|
232 | warn(msg, RuntimeWarning) |
---|
233 | else: |
---|
234 | raise ConfigError(msg) |
---|
235 | parser = ConfiguredDefaultsOptionParser( |
---|
236 | self.getParser(), self.configSection, file_error=warn_sometimes) |
---|
237 | return parser.parseArgsAndConfigFiles(argv[1:], cfg_files) |
---|
238 | |
---|
239 | def configure(self, argv=None, doc=None): |
---|
240 | """Configure the nose running environment. Execute configure before |
---|
241 | collecting tests with nose.TestCollector to enable output capture and |
---|
242 | other features. |
---|
243 | """ |
---|
244 | env = self.env |
---|
245 | if argv is None: |
---|
246 | argv = sys.argv |
---|
247 | |
---|
248 | cfg_files = getattr(self, 'files', []) |
---|
249 | options, args = self._parseArgs(argv, cfg_files) |
---|
250 | # If -c --config has been specified on command line, |
---|
251 | # load those config files and reparse |
---|
252 | if getattr(options, 'files', []): |
---|
253 | options, args = self._parseArgs(argv, options.files) |
---|
254 | |
---|
255 | self.options = options |
---|
256 | if args: |
---|
257 | self.testNames = args |
---|
258 | if options.testNames is not None: |
---|
259 | self.testNames.extend(tolist(options.testNames)) |
---|
260 | |
---|
261 | # `where` is an append action, so it can't have a default value |
---|
262 | # in the parser, or that default will always be in the list |
---|
263 | if not options.where: |
---|
264 | options.where = env.get('NOSE_WHERE', None) |
---|
265 | |
---|
266 | # include and exclude also |
---|
267 | if not options.include: |
---|
268 | options.include = env.get('NOSE_INCLUDE', []) |
---|
269 | if not options.exclude: |
---|
270 | options.exclude = env.get('NOSE_EXCLUDE', []) |
---|
271 | |
---|
272 | self.addPaths = options.addPaths |
---|
273 | self.stopOnError = options.stopOnError |
---|
274 | self.verbosity = options.verbosity |
---|
275 | self.includeExe = options.includeExe |
---|
276 | self.traverseNamespace = options.traverseNamespace |
---|
277 | self.debug = options.debug |
---|
278 | self.debugLog = options.debugLog |
---|
279 | self.loggingConfig = options.loggingConfig |
---|
280 | self.firstPackageWins = options.firstPackageWins |
---|
281 | self.configureLogging() |
---|
282 | |
---|
283 | if options.where is not None: |
---|
284 | self.configureWhere(options.where) |
---|
285 | |
---|
286 | if options.testMatch: |
---|
287 | self.testMatch = re.compile(options.testMatch) |
---|
288 | |
---|
289 | if options.include: |
---|
290 | self.include = map(re.compile, tolist(options.include)) |
---|
291 | log.info("Including tests matching %s", options.include) |
---|
292 | |
---|
293 | if options.exclude: |
---|
294 | self.exclude = map(re.compile, tolist(options.exclude)) |
---|
295 | log.info("Excluding tests matching %s", options.exclude) |
---|
296 | |
---|
297 | # When listing plugins we don't want to run them |
---|
298 | if not options.showPlugins: |
---|
299 | self.plugins.configure(options, self) |
---|
300 | self.plugins.begin() |
---|
301 | |
---|
302 | def configureLogging(self): |
---|
303 | """Configure logging for nose, or optionally other packages. Any logger |
---|
304 | name may be set with the debug option, and that logger will be set to |
---|
305 | debug level and be assigned the same handler as the nose loggers, unless |
---|
306 | it already has a handler. |
---|
307 | """ |
---|
308 | if self.loggingConfig: |
---|
309 | from logging.config import fileConfig |
---|
310 | fileConfig(self.loggingConfig) |
---|
311 | return |
---|
312 | |
---|
313 | format = logging.Formatter('%(name)s: %(levelname)s: %(message)s') |
---|
314 | if self.debugLog: |
---|
315 | handler = logging.FileHandler(self.debugLog) |
---|
316 | else: |
---|
317 | handler = logging.StreamHandler(self.logStream) |
---|
318 | handler.setFormatter(format) |
---|
319 | |
---|
320 | logger = logging.getLogger('nose') |
---|
321 | logger.propagate = 0 |
---|
322 | |
---|
323 | # only add our default handler if there isn't already one there |
---|
324 | # this avoids annoying duplicate log messages. |
---|
325 | if handler not in logger.handlers: |
---|
326 | logger.addHandler(handler) |
---|
327 | |
---|
328 | # default level |
---|
329 | lvl = logging.WARNING |
---|
330 | if self.verbosity >= 5: |
---|
331 | lvl = 0 |
---|
332 | elif self.verbosity >= 4: |
---|
333 | lvl = logging.DEBUG |
---|
334 | elif self.verbosity >= 3: |
---|
335 | lvl = logging.INFO |
---|
336 | logger.setLevel(lvl) |
---|
337 | |
---|
338 | # individual overrides |
---|
339 | if self.debug: |
---|
340 | # no blanks |
---|
341 | debug_loggers = [ name for name in self.debug.split(',') |
---|
342 | if name ] |
---|
343 | for logger_name in debug_loggers: |
---|
344 | l = logging.getLogger(logger_name) |
---|
345 | l.setLevel(logging.DEBUG) |
---|
346 | if not l.handlers and not logger_name.startswith('nose'): |
---|
347 | l.addHandler(handler) |
---|
348 | |
---|
349 | def configureWhere(self, where): |
---|
350 | """Configure the working directory or directories for the test run. |
---|
351 | """ |
---|
352 | from nose.importer import add_path |
---|
353 | self.workingDir = None |
---|
354 | where = tolist(where) |
---|
355 | warned = False |
---|
356 | for path in where: |
---|
357 | if not self.workingDir: |
---|
358 | abs_path = absdir(path) |
---|
359 | if abs_path is None: |
---|
360 | raise ValueError("Working directory %s not found, or " |
---|
361 | "not a directory" % path) |
---|
362 | log.info("Set working dir to %s", abs_path) |
---|
363 | self.workingDir = abs_path |
---|
364 | if self.addPaths and \ |
---|
365 | os.path.exists(os.path.join(abs_path, '__init__.py')): |
---|
366 | log.info("Working directory %s is a package; " |
---|
367 | "adding to sys.path" % abs_path) |
---|
368 | add_path(abs_path) |
---|
369 | continue |
---|
370 | if not warned: |
---|
371 | warn("Use of multiple -w arguments is deprecated and " |
---|
372 | "support may be removed in a future release. You can " |
---|
373 | "get the same behavior by passing directories without " |
---|
374 | "the -w argument on the command line, or by using the " |
---|
375 | "--tests argument in a configuration file.", |
---|
376 | DeprecationWarning) |
---|
377 | self.testNames.append(path) |
---|
378 | |
---|
379 | def default(self): |
---|
380 | """Reset all config values to defaults. |
---|
381 | """ |
---|
382 | self.__dict__.update(self._default) |
---|
383 | |
---|
384 | def getParser(self, doc=None): |
---|
385 | """Get the command line option parser. |
---|
386 | """ |
---|
387 | if self.parser: |
---|
388 | return self.parser |
---|
389 | env = self.env |
---|
390 | parser = self.parserClass(doc) |
---|
391 | parser.add_option( |
---|
392 | "-V","--version", action="store_true", |
---|
393 | dest="version", default=False, |
---|
394 | help="Output nose version and exit") |
---|
395 | parser.add_option( |
---|
396 | "-p", "--plugins", action="store_true", |
---|
397 | dest="showPlugins", default=False, |
---|
398 | help="Output list of available plugins and exit. Combine with " |
---|
399 | "higher verbosity for greater detail") |
---|
400 | parser.add_option( |
---|
401 | "-v", "--verbose", |
---|
402 | action="count", dest="verbosity", |
---|
403 | default=self.verbosity, |
---|
404 | help="Be more verbose. [NOSE_VERBOSE]") |
---|
405 | parser.add_option( |
---|
406 | "--verbosity", action="store", dest="verbosity", |
---|
407 | metavar='VERBOSITY', |
---|
408 | type="int", help="Set verbosity; --verbosity=2 is " |
---|
409 | "the same as -v") |
---|
410 | parser.add_option( |
---|
411 | "-q", "--quiet", action="store_const", const=0, dest="verbosity", |
---|
412 | help="Be less verbose") |
---|
413 | parser.add_option( |
---|
414 | "-c", "--config", action="append", dest="files", |
---|
415 | metavar="FILES", |
---|
416 | help="Load configuration from config file(s). May be specified " |
---|
417 | "multiple times; in that case, all config files will be " |
---|
418 | "loaded and combined") |
---|
419 | parser.add_option( |
---|
420 | "-w", "--where", action="append", dest="where", |
---|
421 | metavar="WHERE", |
---|
422 | help="Look for tests in this directory. " |
---|
423 | "May be specified multiple times. The first directory passed " |
---|
424 | "will be used as the working directory, in place of the current " |
---|
425 | "working directory, which is the default. Others will be added " |
---|
426 | "to the list of tests to execute. [NOSE_WHERE]" |
---|
427 | ) |
---|
428 | parser.add_option( |
---|
429 | "-m", "--match", "--testmatch", action="store", |
---|
430 | dest="testMatch", metavar="REGEX", |
---|
431 | help="Files, directories, function names, and class names " |
---|
432 | "that match this regular expression are considered tests. " |
---|
433 | "Default: %s [NOSE_TESTMATCH]" % self.testMatchPat, |
---|
434 | default=self.testMatchPat) |
---|
435 | parser.add_option( |
---|
436 | "--tests", action="store", dest="testNames", default=None, |
---|
437 | metavar='NAMES', |
---|
438 | help="Run these tests (comma-separated list). This argument is " |
---|
439 | "useful mainly from configuration files; on the command line, " |
---|
440 | "just pass the tests to run as additional arguments with no " |
---|
441 | "switch.") |
---|
442 | parser.add_option( |
---|
443 | "-l", "--debug", action="store", |
---|
444 | dest="debug", default=self.debug, |
---|
445 | help="Activate debug logging for one or more systems. " |
---|
446 | "Available debug loggers: nose, nose.importer, " |
---|
447 | "nose.inspector, nose.plugins, nose.result and " |
---|
448 | "nose.selector. Separate multiple names with a comma.") |
---|
449 | parser.add_option( |
---|
450 | "--debug-log", dest="debugLog", action="store", |
---|
451 | default=self.debugLog, metavar="FILE", |
---|
452 | help="Log debug messages to this file " |
---|
453 | "(default: sys.stderr)") |
---|
454 | parser.add_option( |
---|
455 | "--logging-config", "--log-config", |
---|
456 | dest="loggingConfig", action="store", |
---|
457 | default=self.loggingConfig, metavar="FILE", |
---|
458 | help="Load logging config from this file -- bypasses all other" |
---|
459 | " logging config settings.") |
---|
460 | parser.add_option( |
---|
461 | "-e", "--exclude", action="append", dest="exclude", |
---|
462 | metavar="REGEX", |
---|
463 | help="Don't run tests that match regular " |
---|
464 | "expression [NOSE_EXCLUDE]") |
---|
465 | parser.add_option( |
---|
466 | "-i", "--include", action="append", dest="include", |
---|
467 | metavar="REGEX", |
---|
468 | help="This regular expression will be applied to files, " |
---|
469 | "directories, function names, and class names for a chance " |
---|
470 | "to include additional tests that do not match TESTMATCH. " |
---|
471 | "Specify this option multiple times " |
---|
472 | "to add more regular expressions [NOSE_INCLUDE]") |
---|
473 | parser.add_option( |
---|
474 | "-x", "--stop", action="store_true", dest="stopOnError", |
---|
475 | default=self.stopOnError, |
---|
476 | help="Stop running tests after the first error or failure") |
---|
477 | parser.add_option( |
---|
478 | "-P", "--no-path-adjustment", action="store_false", |
---|
479 | dest="addPaths", |
---|
480 | default=self.addPaths, |
---|
481 | help="Don't make any changes to sys.path when " |
---|
482 | "loading tests [NOSE_NOPATH]") |
---|
483 | parser.add_option( |
---|
484 | "--exe", action="store_true", dest="includeExe", |
---|
485 | default=self.includeExe, |
---|
486 | help="Look for tests in python modules that are " |
---|
487 | "executable. Normal behavior is to exclude executable " |
---|
488 | "modules, since they may not be import-safe " |
---|
489 | "[NOSE_INCLUDE_EXE]") |
---|
490 | parser.add_option( |
---|
491 | "--noexe", action="store_false", dest="includeExe", |
---|
492 | help="DO NOT look for tests in python modules that are " |
---|
493 | "executable. (The default on the windows platform is to " |
---|
494 | "do so.)") |
---|
495 | parser.add_option( |
---|
496 | "--traverse-namespace", action="store_true", |
---|
497 | default=self.traverseNamespace, dest="traverseNamespace", |
---|
498 | help="Traverse through all path entries of a namespace package") |
---|
499 | parser.add_option( |
---|
500 | "--first-package-wins", "--first-pkg-wins", "--1st-pkg-wins", |
---|
501 | default=False, dest="firstPackageWins", |
---|
502 | help="nose's importer will normally evict a package from sys." |
---|
503 | "modules if it sees a package with the same name in a different " |
---|
504 | "location. Set this option to disable that behavior.") |
---|
505 | |
---|
506 | self.plugins.loadPlugins() |
---|
507 | self.pluginOpts(parser) |
---|
508 | |
---|
509 | self.parser = parser |
---|
510 | return parser |
---|
511 | |
---|
512 | def help(self, doc=None): |
---|
513 | """Return the generated help message |
---|
514 | """ |
---|
515 | return self.getParser(doc).format_help() |
---|
516 | |
---|
517 | def pluginOpts(self, parser): |
---|
518 | self.plugins.addOptions(parser, self.env) |
---|
519 | |
---|
520 | def reset(self): |
---|
521 | self.__dict__.update(self._orig) |
---|
522 | |
---|
523 | def todict(self): |
---|
524 | return self.__dict__.copy() |
---|
525 | |
---|
526 | def update(self, d): |
---|
527 | self.__dict__.update(d) |
---|
528 | |
---|
529 | |
---|
530 | class NoOptions(object): |
---|
531 | """Options container that returns None for all options. |
---|
532 | """ |
---|
533 | def __getattr__(self, attr): |
---|
534 | return None |
---|
535 | |
---|
536 | def __nonzero__(self): |
---|
537 | return False |
---|
538 | |
---|
539 | |
---|
540 | def user_config_files(): |
---|
541 | """Return path to any existing user config files |
---|
542 | """ |
---|
543 | return filter(os.path.exists, |
---|
544 | map(os.path.expanduser, config_files)) |
---|
545 | |
---|
546 | |
---|
547 | def all_config_files(): |
---|
548 | """Return path to any existing user config files, plus any setup.cfg |
---|
549 | in the current working directory. |
---|
550 | """ |
---|
551 | user = user_config_files() |
---|
552 | if os.path.exists('setup.cfg'): |
---|
553 | return user + ['setup.cfg'] |
---|
554 | return user |
---|
555 | |
---|
556 | |
---|
557 | # used when parsing config files |
---|
558 | def flag(val): |
---|
559 | """Does the value look like an on/off flag?""" |
---|
560 | if val == 1: |
---|
561 | return True |
---|
562 | elif val == 0: |
---|
563 | return False |
---|
564 | val = str(val) |
---|
565 | if len(val) > 5: |
---|
566 | return False |
---|
567 | return val.upper() in ('1', '0', 'F', 'T', 'TRUE', 'FALSE', 'ON', 'OFF') |
---|
568 | |
---|
569 | |
---|
570 | def _bool(val): |
---|
571 | return str(val).upper() in ('1', 'T', 'TRUE', 'ON') |
---|