3
<title>nose: Writing Plugins</title>
4
<link rel="stylesheet" href="site.css" type="text/css"></link>
9
<p>This document covers nose version <b>0.10.3</b></p>
10
<p>Last update: <b>Tue Jun 3 11:50:26 2008</b></p>
11
<h2>Plugins</h2><ul><li><a href="plugin_attrib.html">Builtin Plugin: attrib</a></li><li><a href="plugin_capture.html">Builtin Plugin: capture</a></li><li><a href="plugin_cover.html">Builtin Plugin: cover</a></li><li><a href="plugin_debug.html">Builtin Plugin: debug</a></li><li><a href="plugin_deprecated.html">Builtin Plugin: deprecated</a></li><li><a href="plugin_doctests.html">Builtin Plugin: doctests</a></li><li><a href="plugin_failuredetail.html">Builtin Plugin: failuredetail</a></li><li><a href="plugin_isolate.html">Builtin Plugin: isolate</a></li><li><a href="plugin_prof.html">Builtin Plugin: prof</a></li><li><a href="plugin_skip.html">Builtin Plugin: skip</a></li><li><a href="plugin_testid.html">Builtin Plugin: testid</a></li><li><a href="error_class_plugin.html">ErrorClass Plugins</a></li><li><a href="plugin_interface.html">Plugin Interface</a></li><li><a href="writing_plugins.html">Writing Plugins</a></li></ul><h2>Modules</h2><ul><li><a href="module_nose.case.html">Module: nose.case</a></li><li><a href="module_nose.commands.html">Module: nose.commands</a></li><li><a href="module_nose.config.html">Module: nose.config</a></li><li><a href="module_nose.core.html">Module: nose.core</a></li><li><a href="module_nose.exc.html">Module: nose.exc</a></li><li><a href="module_nose.failure.html">Module: nose.failure</a></li><li><a href="module_nose.importer.html">Module: nose.importer</a></li><li><a href="module_nose.inspector.html">Module: nose.inspector</a></li><li><a href="module_nose.loader.html">Module: nose.loader</a></li><li><a href="module_nose.plugins.manager.html">Module: nose.plugins.manager</a></li><li><a href="module_nose.plugins.plugintest.html">Module: nose.plugins.plugintest</a></li><li><a href="module_nose.proxy.html">Module: nose.proxy</a></li><li><a href="module_nose.result.html">Module: nose.result</a></li><li><a href="module_nose.selector.html">Module: nose.selector</a></li><li><a href="module_nose.suite.html">Module: nose.suite</a></li><li><a href="module_nose.tools.html">Module: nose.tools</a></li><li><a href="module_nose.twistedtools.html">Module: nose.twistedtools</a></li><li><a href="module_nose.util.html">Module: nose.util</a></li></ul><h2>Plugin Examples</h2><ul><li><a href="unwanted_package.html">Excluding Unwanted Packages</a></li><li><a href="errorclass_failure.html">Failure of Errorclasses</a></li><li><a href="imported_tests.html">Importing Tests</a></li><li><a href="empty_plugin.html">Minimal plugin</a></li><li><a href="restricted_plugin_options.html">Restricted Plugin Managers</a></li><li><a href="init_plugin.html">Running Initialization Code Before the Test Run</a></li><li><a href="selector_plugin.html">Using a Custom Selector</a></li><li><a href="plugin_exceptions.html">When Plugins Fail</a></li><li><a href="plugintest_environment.html">nose.plugins.plugintest, os.environ and sys.argv</a></li></ul>
16
<h1>nose: Writing Plugins</h1>
18
<p>nose supports plugins for test collection, selection, observation and
19
reporting. There are two basic rules for plugins:</p>
21
<li>Plugin classes should subclass <a class="reference" href="http://python-nose.googlecode.com/svn/trunk/nose/plugins/base.py">nose.plugins.Plugin</a>.</li>
22
<li>Plugins may implement any of the methods described in the class
23
<a class="reference" href="plugin_interface.html">PluginInterface</a> in nose.plugins.base. Please note that this class is for
24
documentary purposes only; plugins may not subclass PluginInterface.</li>
27
<h1><a id="registering" name="registering">Registering</a></h1>
29
<p class="first admonition-title">Note</p>
30
<p class="last">Important note: the following applies only to the default plugin manager. Other plugin managers may use different means to locate and load plugins.</p>
32
<p>For nose to find a plugin, it must be part of a package that uses
33
<a class="reference" href="http://peak.telecommunity.com/DevCenter/setuptools">setuptools</a>, and the plugin must be included in the entry points defined
34
in the setup.py for the package:</p>
35
<pre class="literal-block">
36
setup(name='Some plugin',
39
'nose.plugins.0.10': [
40
'someplugin = someplugin:SomePlugin'
46
<p>Once the package is installed with install or develop, nose will be able
47
to load the plugin.</p>
50
<h1><a id="defining-options" name="defining-options">Defining options</a></h1>
51
<p>All plugins must implement the methods <tt class="docutils literal"><span class="pre">options(self,</span> <span class="pre">parser,</span> <span class="pre">env)</span></tt>
52
and <tt class="docutils literal"><span class="pre">configure(self,</span> <span class="pre">options,</span> <span class="pre">conf)</span></tt>. Subclasses of nose.plugins.Plugin
53
that want the standard options should call the superclass methods.</p>
54
<p>nose uses optparse.OptionParser from the standard library to parse
55
arguments. A plugin's <tt class="docutils literal"><span class="pre">options()</span></tt> method receives a parser
56
instance. It's good form for a plugin to use that instance only to add
57
additional arguments that take only long arguments (--like-this). Most
58
of nose's built-in arguments get their default value from an environment
60
<p>A plugin's <tt class="docutils literal"><span class="pre">configure()</span></tt> method receives the parsed <tt class="docutils literal"><span class="pre">OptionParser</span></tt> options
61
object, as well as the current config object. Plugins should configure their
62
behavior based on the user-selected settings, and may raise exceptions
63
if the configured behavior is nonsensical.</p>
66
<h1><a id="logging" name="logging">Logging</a></h1>
67
<p>nose uses the logging classes from the standard library. To enable users
68
to view debug messages easily, plugins should use <tt class="docutils literal"><span class="pre">logging.getLogger()</span></tt> to
69
acquire a logger in the <tt class="docutils literal"><span class="pre">nose.plugins</span></tt> namespace.</p>
72
<h1><a id="recipes" name="recipes">Recipes</a></h1>
74
<li><p class="first">Writing a plugin that monitors or controls test result output</p>
75
<p>Implement any or all of <tt class="docutils literal"><span class="pre">addError</span></tt>, <tt class="docutils literal"><span class="pre">addFailure</span></tt>, etc., to monitor test
76
results. If you also want to monitor output, implement
77
<tt class="docutils literal"><span class="pre">setOutputStream</span></tt> and keep a reference to the output stream. If you
78
want to prevent the builtin <tt class="docutils literal"><span class="pre">TextTestResult</span></tt> output, implement
79
<tt class="docutils literal"><span class="pre">setOutputSteam</span></tt> and <em>return a dummy stream</em>. The default output will go
80
to the dummy stream, while you send your desired output to the real stream.</p>
81
<p>Example: <a class="reference" href="http://python-nose.googlecode.com/svn/trunk/examples/html_plugin/htmlplug.py">examples/html_plugin/htmlplug.py</a></p>
83
<li><p class="first">Writing a plugin that handles exceptions</p>
84
<p>Subclass <a class="reference" href="error_class_plugin.html">ErrorClassPlugin</a>.</p>
85
<p>Examples: <a class="reference" href="plugin_deprecated.html">nose.plugins.deprecated</a>, <a class="reference" href="plugin_skip.html">nose.plugins.skip</a></p>
87
<li><p class="first">Writing a plugin that adds detail to error reports</p>
88
<p>Implement <tt class="docutils literal"><span class="pre">formatError</span></tt> and/or <tt class="docutils literal"><span class="pre">formatFailture</span></tt>. The error tuple
89
you return (error class, error message, traceback) will replace the
90
original error tuple.</p>
91
<p>Examples: <a class="reference" href="plugin_capture.html">nose.plugins.capture</a>, <a class="reference" href="plugin_failuredetail.html">nose.plugins.failuredetail</a></p>
93
<li><p class="first">Writing a plugin that loads tests from files other than python modules</p>
94
<p>Implement <tt class="docutils literal"><span class="pre">wantFile</span></tt> and <tt class="docutils literal"><span class="pre">loadTestsFromFile</span></tt>. In <tt class="docutils literal"><span class="pre">wantFile</span></tt>,
95
return True for files that you want to examine for tests. In
96
<tt class="docutils literal"><span class="pre">loadTestsFromFile</span></tt>, for those files, return an iterable
97
containing TestCases (or yield them as you find them;
98
<tt class="docutils literal"><span class="pre">loadTestsFromFile</span></tt> may also be a generator).</p>
99
<p>Example: <a class="reference" href="plugin_doctests.html">nose.plugins.doctests</a></p>
101
<li><p class="first">Writing a plugin that prints a report</p>
102
<p>Implement begin if you need to perform setup before testing
103
begins. Implement <tt class="docutils literal"><span class="pre">report</span></tt> and output your report to the provided stream.</p>
104
<p>Examples: <a class="reference" href="plugin_cover.html">nose.plugins.cover</a>, <a class="reference" href="plugin_prof.html">nose.plugins.prof</a></p>
106
<li><p class="first">Writing a plugin that selects or rejects tests</p>
107
<p>Implement any or all <tt class="docutils literal"><span class="pre">want*</span></tt> methods. Return False to reject the test
108
candidate, True to accept it -- which means that the test candidate
109
will pass through the rest of the system, so you must be prepared to
110
load tests from it if tests can't be loaded by the core loader or
111
another plugin -- and None if you don't care.</p>
112
<p>Examples: <a class="reference" href="plugin_attrib.html">nose.plugins.attrib</a>, <a class="reference" href="plugin_doctests.html">nose.plugins.doctests</a>,
113
<a class="reference" href="plugin_testid.html">nose.plugins.testid</a></p>
117
<div class="section">
118
<h1><a id="more-examples" name="more-examples">More Examples</a></h1>
119
<p>See any builtin plugin or example plugin in the <a class="reference" href="http://python-nose.googlecode.com/svn/trunk/examples">examples</a> directory in
120
the nose source distribution.</p>
122
<div class="section">
123
<h1><a id="testing-plugins" name="testing-plugins">Testing Plugins</a></h1>
124
<p>The plugin interface is well-tested enough so that you can safely unit
125
test your use of its hooks with some level of confidence. However,
126
there is a mixin for unittest.TestCase called PluginTester that's
127
designed to test plugins in their native runtime environment.</p>
128
<p>Here's a simple example with a do-nothing plugin and a composed suite.</p>
130
<div class="highlight"><pre><span class="gp">>>> </span><span class="k">import</span> <span class="nn">unittest</span>
131
<span class="gp">>>> </span><span class="k">from</span> <span class="nn">nose.plugins</span> <span class="k">import</span> <span class="n">Plugin</span><span class="p">,</span> <span class="n">PluginTester</span>
132
<span class="gp">>>> </span><span class="k">class</span> <span class="nc">FooPlugin</span><span class="p">(</span><span class="n">Plugin</span><span class="p">):</span>
133
<span class="gp">... </span> <span class="k">pass</span>
134
<span class="gp">>>> </span><span class="k">class</span> <span class="nc">TestPluginFoo</span><span class="p">(</span><span class="n">PluginTester</span><span class="p">,</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
135
<span class="gp">... </span> <span class="n">activate</span> <span class="o">=</span> <span class="s">'--with-foo'</span>
136
<span class="gp">... </span> <span class="n">plugins</span> <span class="o">=</span> <span class="p">[</span><span class="n">FooPlugin</span><span class="p">()]</span>
137
<span class="gp">... </span> <span class="k">def</span> <span class="nf">test_foo</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
138
<span class="gp">... </span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">output</span><span class="p">:</span>
139
<span class="gp">... </span> <span class="c"># i.e. check for patterns</span>
140
<span class="gp">... </span> <span class="k">pass</span>
141
<span class="go">...</span>
142
<span class="gp">... </span> <span class="c"># or check for a line containing ...</span>
143
<span class="gp">... </span> <span class="k">assert</span> <span class="s">"ValueError"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">output</span>
144
<span class="gp">... </span> <span class="k">def</span> <span class="nf">makeSuite</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
145
<span class="gp">... </span> <span class="k">class</span> <span class="nc">TC</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
146
<span class="gp">... </span> <span class="k">def</span> <span class="nf">runTest</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
147
<span class="gp">... </span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"I hate foo"</span><span class="p">)</span>
148
<span class="gp">... </span> <span class="k">return</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestSuite</span><span class="p">([</span><span class="n">TC</span><span class="p">()])</span>
149
<span class="go">...</span>
150
<span class="gp">>>> </span><span class="n">res</span> <span class="o">=</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestResult</span><span class="p">()</span>
151
<span class="gp">>>> </span><span class="n">case</span> <span class="o">=</span> <span class="n">TestPluginFoo</span><span class="p">(</span><span class="s">'test_foo'</span><span class="p">)</span>
152
<span class="gp">>>> </span><span class="n">case</span><span class="p">(</span><span class="n">res</span><span class="p">)</span>
153
<span class="gp">>>> </span><span class="n">res</span><span class="o">.</span><span class="n">errors</span>
154
<span class="go">[]</span>
155
<span class="gp">>>> </span><span class="n">res</span><span class="o">.</span><span class="n">failures</span>
156
<span class="go">[]</span>
157
<span class="gp">>>> </span><span class="n">res</span><span class="o">.</span><span class="n">wasSuccessful</span><span class="p">()</span>
158
<span class="go">True</span>
159
<span class="gp">>>> </span><span class="n">res</span><span class="o">.</span><span class="n">testsRun</span>
160
<span class="go">1</span>
163
<p>And here is a more complex example of testing a plugin that has extra
164
arguments and reads environment variables.</p>
166
<div class="highlight"><pre><span class="gp">>>> </span><span class="k">import</span> <span class="nn">unittest</span><span class="o">,</span> <span class="nn">os</span>
167
<span class="gp">>>> </span><span class="k">from</span> <span class="nn">nose.plugins</span> <span class="k">import</span> <span class="n">Plugin</span><span class="p">,</span> <span class="n">PluginTester</span>
168
<span class="gp">>>> </span><span class="k">class</span> <span class="nc">FancyOutputter</span><span class="p">(</span><span class="n">Plugin</span><span class="p">):</span>
169
<span class="gp">... </span> <span class="n">name</span> <span class="o">=</span> <span class="s">"fancy"</span>
170
<span class="gp">... </span> <span class="k">def</span> <span class="nf">configure</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">conf</span><span class="p">):</span>
171
<span class="gp">... </span> <span class="n">Plugin</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">conf</span><span class="p">)</span>
172
<span class="gp">... </span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">enabled</span><span class="p">:</span>
173
<span class="gp">... </span> <span class="k">return</span>
174
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">fanciness</span> <span class="o">=</span> <span class="mi">1</span>
175
<span class="gp">... </span> <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">more_fancy</span><span class="p">:</span>
176
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">fanciness</span> <span class="o">=</span> <span class="mi">2</span>
177
<span class="gp">... </span> <span class="k">if</span> <span class="s">'EVEN_FANCIER'</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="p">:</span>
178
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">fanciness</span> <span class="o">=</span> <span class="mi">3</span>
179
<span class="go">...</span>
180
<span class="gp">... </span> <span class="k">def</span> <span class="nf">options</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">parser</span><span class="p">,</span> <span class="n">env</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">):</span>
181
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span> <span class="o">=</span> <span class="n">env</span>
182
<span class="gp">... </span> <span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s">'--more-fancy'</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">'store_true'</span><span class="p">)</span>
183
<span class="gp">... </span> <span class="n">Plugin</span><span class="o">.</span><span class="n">options</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">parser</span><span class="p">,</span> <span class="n">env</span><span class="o">=</span><span class="n">env</span><span class="p">)</span>
184
<span class="go">...</span>
185
<span class="gp">... </span> <span class="k">def</span> <span class="nf">report</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream</span><span class="p">):</span>
186
<span class="gp">... </span> <span class="n">stream</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">"FANCY "</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">fanciness</span><span class="p">)</span>
187
<span class="go">...</span>
188
<span class="gp">>>> </span><span class="k">class</span> <span class="nc">TestFancyOutputter</span><span class="p">(</span><span class="n">PluginTester</span><span class="p">,</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
189
<span class="gp">... </span> <span class="n">activate</span> <span class="o">=</span> <span class="s">'--with-fancy'</span> <span class="c"># enables the plugin</span>
190
<span class="gp">... </span> <span class="n">plugins</span> <span class="o">=</span> <span class="p">[</span><span class="n">FancyOutputter</span><span class="p">()]</span>
191
<span class="gp">... </span> <span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="s">'--more-fancy'</span><span class="p">]</span>
192
<span class="gp">... </span> <span class="n">env</span> <span class="o">=</span> <span class="p">{</span><span class="s">'EVEN_FANCIER'</span><span class="p">:</span> <span class="s">'1'</span><span class="p">}</span>
193
<span class="go">...</span>
194
<span class="gp">... </span> <span class="k">def</span> <span class="nf">test_fancy_output</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
195
<span class="gp">... </span> <span class="k">assert</span> <span class="s">"FANCY FANCY FANCY"</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">output</span><span class="p">,</span> <span class="p">(</span>
196
<span class="gp">... </span> <span class="s">"got: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">output</span><span class="p">)</span>
197
<span class="gp">... </span> <span class="k">def</span> <span class="nf">makeSuite</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
198
<span class="gp">... </span> <span class="k">class</span> <span class="nc">TC</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
199
<span class="gp">... </span> <span class="k">def</span> <span class="nf">runTest</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
200
<span class="gp">... </span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">"I hate fancy stuff"</span><span class="p">)</span>
201
<span class="gp">... </span> <span class="k">return</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestSuite</span><span class="p">([</span><span class="n">TC</span><span class="p">()])</span>
202
<span class="go">...</span>
203
<span class="gp">>>> </span><span class="n">res</span> <span class="o">=</span> <span class="n">unittest</span><span class="o">.</span><span class="n">TestResult</span><span class="p">()</span>
204
<span class="gp">>>> </span><span class="n">case</span> <span class="o">=</span> <span class="n">TestFancyOutputter</span><span class="p">(</span><span class="s">'test_fancy_output'</span><span class="p">)</span>
205
<span class="gp">>>> </span><span class="n">case</span><span class="p">(</span><span class="n">res</span><span class="p">)</span>
206
<span class="gp">>>> </span><span class="n">res</span><span class="o">.</span><span class="n">errors</span>
207
<span class="go">[]</span>
208
<span class="gp">>>> </span><span class="n">res</span><span class="o">.</span><span class="n">failures</span>
209
<span class="go">[]</span>
210
<span class="gp">>>> </span><span class="n">res</span><span class="o">.</span><span class="n">wasSuccessful</span><span class="p">()</span>
211
<span class="go">True</span>
212
<span class="gp">>>> </span><span class="n">res</span><span class="o">.</span><span class="n">testsRun</span>
213
<span class="go">1</span>
220
<script src="http://www.google-analytics.com/urchin.js"
221
type="text/javascript">
223
<script type="text/javascript">
224
_uacct = "UA-2236166-1";