4
4
# See LICENSE for details.
7
import sys, os, shutil, random, gc, time, sets
7
import sys, os, random, gc, time, sets
9
9
from twisted.internet import defer
10
10
from twisted.application import app
11
from twisted.python import usage, reflect, failure, log
11
from twisted.python import usage, reflect, failure
12
12
from twisted import plugin
13
13
from twisted.python.util import spewer
14
14
from twisted.trial import runner, itrial, reporter
84
84
and os.path.splitext(basename)[1] == ('.py'))
87
class Options(usage.Options):
87
def _zshReporterAction():
88
return "(%s)" % (" ".join([p.longOpt for p in plugin.getPlugins(itrial.IReporter)]),)
90
class Options(usage.Options, app.ReactorSelectionMixin):
88
91
synopsis = """%s [options] [[file|package|module|TestCase|testmethod]...]
89
92
""" % (os.path.basename(sys.argv[0]),)
98
101
["nopm", None, "don't automatically jump into debugger for "
99
102
"postmorteming of exceptions"],
100
103
["dry-run", 'n', "do everything but run the tests"],
104
["force-gc", None, "Have Trial run gc.collect() before and "
105
"after each test case."],
101
106
["profile", None, "Run tests under the Python profiler"],
102
107
["until-failure", "u", "Repeat test until it fails"],
103
108
["no-recurse", "N", "Don't recurse into packages"],
104
['suppresswarnings', None,
105
'Only print warnings to log, not stdout. DEPRECATED.'],
106
109
['help-reporters', None,
107
110
"Help on available output plugins (reporters)"]
110
optParameters = [["reactor", "r", None,
111
"Which reactor to use out of: " + \
112
", ".join(app.reactorTypes.keys()) + "."],
113
["logfile", "l", "test.log", "log file name"],
114
["random", "z", None,
115
"Run tests in random order using the specified seed"],
116
['temp-directory', None, '_trial_temp',
117
'Path to use as working directory for tests.']]
114
["logfile", "l", "test.log", "log file name"],
115
["random", "z", None,
116
"Run tests in random order using the specified seed"],
117
['temp-directory', None, '_trial_temp',
118
'Path to use as working directory for tests.'],
119
['reporter', None, 'verbose',
120
'The reporter to use for this test run. See --help-reporters for '
119
zsh_actions = {"reactor":"(%s)" % " ".join(app.reactorTypes.keys()),
120
"tbformat":"(plain emacs cgitb)"}
123
zsh_actions = {"tbformat":"(plain emacs cgitb)",
124
"reporter":_zshReporterAction}
121
125
zsh_actionDescr = {"logfile":"log file name",
122
126
"random":"random seed"}
123
127
zsh_extras = ["*:file|module|package|TestCase|testMethod:_files -g '*.py'"]
129
133
def __init__(self):
130
134
self['tests'] = sets.Set()
131
self._loadReporters()
133
# Yes, I know I'm mutating a class variable.
134
self.zsh_actions["reporter"] = "(%s)" % " ".join(self.optToQual.keys())
135
135
usage.Options.__init__(self)
137
def _loadReporters(self):
138
if self._supportsColor():
141
default = 'bwverbose'
143
for p in plugin.getPlugins(itrial.IReporter):
144
qual = "%s.%s" % (p.module, p.klass)
145
self.optToQual[p.longOpt] = qual
146
if p.longOpt == default:
147
self['reporter'] = reflect.namedAny(qual)
149
def _supportsColor(self):
152
if not sys.stderr.isatty():
153
return False # auto color only on TTYs
157
return curses.tigetnum("colors") > 2
159
# guess false in case of error
162
def opt_reactor(self, reactorName):
163
# this must happen before parseArgs does lots of imports
164
app.installReactor(reactorName)
165
print "Using %s reactor" % app.reactorTypes[reactorName]
167
137
def opt_coverage(self):
169
Generate coverage information in the given directory (relative to
170
trial temporary working directory). Requires Python 2.3.3.
139
Generate coverage information in the _trial_temp/coverage. Requires
172
142
coverdir = 'coverage'
173
143
print "Setting coverage directory to %s." % (coverdir,)
229
199
"""Print an insanely verbose log of everything that happens. Useful
230
200
when debugging freezes or locks in complex code."""
231
201
sys.settrace(spewer)
233
def opt_reporter(self, opt):
234
"""The reporter to use for this test run. See --help-reporters
237
if opt in self.optToQual:
238
opt = self.optToQual[opt]
240
raise usage.UsageError("Only pass names of Reporter plugins to "
241
"--reporter. See --help-reporters for "
243
self['reporter'] = reflect.namedAny(opt)
245
204
def opt_help_reporters(self):
246
205
synopsis = ("Trial's output can be customized using plugins called "
302
261
if self.extra is not None:
303
262
self['tests'].update(self.extra)
264
def _loadReporterByName(self, name):
265
for p in plugin.getPlugins(itrial.IReporter):
266
qual = "%s.%s" % (p.module, p.klass)
267
if p.longOpt == name:
268
return reflect.namedAny(qual)
269
raise usage.UsageError("Only pass names of Reporter plugins to "
270
"--reporter. See --help-reporters for "
305
274
def postOptions(self):
306
if self['suppresswarnings']:
307
warnings.warn('--suppresswarnings deprecated. Is a no-op',
308
category=DeprecationWarning)
276
# Only load reporters now, as opposed to any earlier, to avoid letting
277
# application-defined plugins muck up reactor selecting by importing
278
# t.i.reactor and causing the default to be installed.
279
self['reporter'] = self._loadReporterByName(self['reporter'])
309
281
if not self.has_key('tbformat'):
310
282
self['tbformat'] = 'default'
326
298
def _getSuite(config):
327
299
loader = _getLoader(config)
328
suite = runner.TestSuite()
329
300
recurse = not config['no-recurse']
330
for test in config['tests']:
331
if isinstance(test, str):
332
suite.addTest(loader.loadByName(test, recurse))
334
suite.addTest(loader.loadAnything(test, recurse))
301
return loader.loadByNames(config['tests'], recurse)
338
304
def _getLoader(config):
339
305
loader = runner.TestLoader()