~certify-web-dev/twisted/certify-staging

« back to all changes in this revision

Viewing changes to doc/howto/plugin.html

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2010-01-02 19:38:17 UTC
  • mfrom: (2.2.4 sid)
  • Revision ID: james.westby@ubuntu.com-20100102193817-jphp464ppwh7dulg
Tags: 9.0.0-1
* python-twisted: Depend on the python-twisted-* 9.0 packages.
* python-twisted: Depend on python-zope.interface only. Closes: #557781.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>Twisted Documentation: The Twisted Plugin System</title><link href="stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">The Twisted Plugin System</h1><div class="toc"><ol><li><a href="#auto0">Writing Extensible Programs</a></li><li><a href="#auto1">Extending an Existing Program</a></li><li><a href="#auto2">Alternate Plugin Packages</a></li><li><a href="#auto3">Plugin Caching</a></li><li><a href="#auto4">Further Reading</a></li></ol></div><div class="content"><span></span><p>The purpose of this guide is to describe the preferred way to
 
1
<?xml version="1.0" encoding="utf-8"?>
 
2
<!DOCTYPE html
 
3
  PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'
 
4
  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
 
5
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
 
6
  <head>
 
7
<title>Twisted Documentation: The Twisted Plugin System</title>
 
8
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
 
9
  </head>
 
10
 
 
11
  <body bgcolor="white">
 
12
    <h1 class="title">The Twisted Plugin System</h1>
 
13
    <div class="toc"><ol><li><a href="#auto0">Writing Extensible Programs</a></li><li><a href="#auto1">Extending an Existing Program</a></li><li><a href="#auto2">Alternate Plugin Packages</a></li><li><a href="#auto3">Plugin Caching</a></li><li><a href="#auto4">Further Reading</a></li></ol></div>
 
14
    <div class="content">
 
15
    <span/>
 
16
 
 
17
    <p>The purpose of this guide is to describe the preferred way to
3
18
    write extensible Twisted applications (and consequently, also to
4
19
    describe how to extend applications written in such a way).  This
5
20
    extensibility is achieved through the definition of one or more
6
21
    APIs and a mechanism for collecting code plugins which
7
22
    implement this API to provide some additional functionality.
8
 
    At the base of this system is the <code class="API"><a href="http://twistedmatrix.com/documents/8.2.0/api/twisted.plugin.html" title="twisted.plugin">twisted.plugin</a></code> module.</p><p>Making an application extensible using the plugin system has
9
 
    several strong advantages over other techniques:</p><ul><li>It allows third-party developers to easily enhance your
 
23
    At the base of this system is the <code class="API"><a href="http://twistedmatrix.com/documents/9.0.0/api/twisted.plugin.html" title="twisted.plugin">twisted.plugin</a></code> module.</p>
 
24
 
 
25
    <p>Making an application extensible using the plugin system has
 
26
    several strong advantages over other techniques:</p>
 
27
 
 
28
    <ul>
 
29
      <li>It allows third-party developers to easily enhance your
10
30
      software in a way that is loosely coupled: only the plugin API
11
 
      is required to remain stable.</li><li>It allows new plugins to be discovered flexibly.  For
 
31
      is required to remain stable.</li>
 
32
 
 
33
      <li>It allows new plugins to be discovered flexibly.  For
12
34
      example, plugins can be loaded and saved when a program is first
13
35
      run, or re-discovered each time the program starts up, or they
14
36
      can be polled for repeatedly at runtime (allowing the discovery
15
 
      of new plugins installed after the program has started).</li></ul><h2>Writing Extensible Programs<a name="auto0"></a></h2><p>Taking advantage of <code class="API"><a href="http://twistedmatrix.com/documents/8.2.0/api/twisted.plugin.html" title="twisted.plugin">twisted.plugin</a></code> is
16
 
    a two step process:</p><ol><li><p>
 
37
      of new plugins installed after the program has started).</li>
 
38
    </ul>
 
39
 
 
40
    <h2>Writing Extensible Programs<a name="auto0"/></h2>
 
41
 
 
42
    <p>Taking advantage of <code class="API"><a href="http://twistedmatrix.com/documents/9.0.0/api/twisted.plugin.html" title="twisted.plugin">twisted.plugin</a></code> is
 
43
    a two step process:</p>
 
44
 
 
45
    <ol>
 
46
      <li>
 
47
        <p>
17
48
        Define an interface which plugins will be required to implement.
18
49
        This is done using the zope.interface package in the same way one
19
50
        would define an interface for any other purpose.
20
 
        </p><p>
 
51
        </p>
 
52
 
 
53
        <p>
21
54
        A convention for defining interfaces is do so in a file named like
22
55
        <em>ProjectName/projectname/iprojectname.py</em>.  The rest of this
23
56
        document will follow that convention: consider the following
24
57
        interface definition be in <code>Matsim/matsim/imatsim.py</code>, an
25
58
        interface definition module for a hypothetical material simulation
26
59
        package.
27
 
        </p></li><li>
28
 
      At one or more places in your program, invoke <code class="API"><a href="http://twistedmatrix.com/documents/8.2.0/api/twisted.plugin.getPlugins.html" title="twisted.plugin.getPlugins">twisted.plugin.getPlugins</a></code> and iterate over its
 
60
        </p>
 
61
      </li>
 
62
 
 
63
      <li>
 
64
      At one or more places in your program, invoke <code class="API"><a href="http://twistedmatrix.com/documents/9.0.0/api/twisted.plugin.getPlugins.html" title="twisted.plugin.getPlugins">twisted.plugin.getPlugins</a></code> and iterate over its
29
65
      result.
30
 
      </li></ol><p>
 
66
      </li>
 
67
    </ol>
 
68
 
 
69
    <p>
31
70
    As an example of the first step, consider the following interface
32
71
    definition for a physical modelling system.
33
 
    </p><pre class="python">
34
 
<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Interface</span>, <span class="py-src-variable">Attribute</span>
 
72
    </p>
 
73
 
 
74
    <pre class="python"><p class="py-linenumber"> 1
 
75
 2
 
76
 3
 
77
 4
 
78
 5
 
79
 6
 
80
 7
 
81
 8
 
82
 9
 
83
10
 
84
11
 
85
12
 
86
13
 
87
14
 
88
15
 
89
16
 
90
17
 
91
18
 
92
19
 
93
20
 
94
21
 
95
22
 
96
23
 
97
24
 
98
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Interface</span>, <span class="py-src-variable">Attribute</span>
35
99
 
36
100
<span class="py-src-keyword">class</span> <span class="py-src-identifier">IMaterial</span>(<span class="py-src-parameter">Interface</span>):
37
101
    <span class="py-src-string">&quot;&quot;&quot;
55
119
        real part giving reflective surface properties and the
56
120
        imaginary part giving the radio absorption coefficient.
57
121
        &quot;&quot;&quot;</span>)
58
 
</pre><p>In another module, we might have a function that operates on
59
 
    objects providing the <code>IMaterial</code> interface:</p><pre class="python">
60
 
<span class="py-src-keyword">def</span> <span class="py-src-identifier">displayMaterial</span>(<span class="py-src-parameter">m</span>):
 
122
</pre>
 
123
 
 
124
    <p>In another module, we might have a function that operates on
 
125
    objects providing the <code>IMaterial</code> interface:</p>
 
126
 
 
127
    <pre class="python"><p class="py-linenumber">1
 
128
2
 
129
3
 
130
</p><span class="py-src-keyword">def</span> <span class="py-src-identifier">displayMaterial</span>(<span class="py-src-parameter">m</span>):
61
131
    <span class="py-src-keyword">print</span> <span class="py-src-string">'A material with yield stress %s at 500 K'</span> % (<span class="py-src-variable">m</span>.<span class="py-src-variable">yieldStress</span>(<span class="py-src-number">500</span>),)
62
132
    <span class="py-src-keyword">print</span> <span class="py-src-string">'Also a dielectric constant of %s.'</span> % (<span class="py-src-variable">m</span>.<span class="py-src-variable">dielectricConstant</span>,)
63
 
</pre><p>The last piece of required code is that which collects
 
133
</pre>
 
134
 
 
135
    <p>The last piece of required code is that which collects
64
136
    <code>IMaterial</code> providers and passes them to the
65
 
    <code>displayMaterial</code> function.</p><pre class="python">
66
 
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">plugin</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">getPlugins</span>
 
137
    <code>displayMaterial</code> function.</p>
 
138
 
 
139
    <pre class="python"><p class="py-linenumber">1
 
140
2
 
141
3
 
142
4
 
143
5
 
144
6
 
145
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">plugin</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">getPlugins</span>
67
146
<span class="py-src-keyword">from</span> <span class="py-src-variable">matsim</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">imatsim</span>
68
147
 
69
148
<span class="py-src-keyword">def</span> <span class="py-src-identifier">displayAllKnownMaterials</span>():
70
149
    <span class="py-src-keyword">for</span> <span class="py-src-variable">material</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">getPlugins</span>(<span class="py-src-variable">imatsim</span>.<span class="py-src-variable">IMaterial</span>):
71
150
        <span class="py-src-variable">displayMaterial</span>(<span class="py-src-variable">material</span>)
72
 
</pre><p>Third party developers may now contribute different materials
 
151
</pre>
 
152
 
 
153
    <p>Third party developers may now contribute different materials
73
154
    to be used by this modelling system by implementing one or more
74
 
    plugins for the <code>IMaterial</code> interface.</p><h2>Extending an Existing Program<a name="auto1"></a></h2><p>The above code demonstrates how an extensible program might be
 
155
    plugins for the <code>IMaterial</code> interface.</p>
 
156
 
 
157
    <h2>Extending an Existing Program<a name="auto1"/></h2>
 
158
 
 
159
    <p>The above code demonstrates how an extensible program might be
75
160
    written using Twisted's plugin system.  How do we write plugins
76
161
    for it, though?  Essentially, we create objects which provide the
77
162
    required interface and then make them available at a particular
78
 
    location.  Consider the following example.</p><pre class="python">
79
 
<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
 
163
    location.  Consider the following example.</p>
 
164
 
 
165
    <pre class="python"><p class="py-linenumber"> 1
 
166
 2
 
167
 3
 
168
 4
 
169
 5
 
170
 6
 
171
 7
 
172
 8
 
173
 9
 
174
10
 
175
11
 
176
12
 
177
13
 
178
14
 
179
15
 
180
16
 
181
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
80
182
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">plugin</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IPlugin</span>
81
183
<span class="py-src-keyword">from</span> <span class="py-src-variable">matsim</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">imatsim</span>
82
184
 
92
194
 
93
195
<span class="py-src-variable">steelPlate</span> = <span class="py-src-variable">SimpleMaterial</span>(<span class="py-src-number">2.06842719e11</span>, <span class="py-src-number">2.7</span> + <span class="py-src-number">0.2j</span>)
94
196
<span class="py-src-variable">brassPlate</span> = <span class="py-src-variable">SimpleMaterial</span>(<span class="py-src-number">1.03421359e11</span>, <span class="py-src-number">1.4</span> + <span class="py-src-number">0.5j</span>)
95
 
</pre><p><code>steelPlate</code> and <code>brassPlate</code> now provide both
96
 
    <code class="API"><a href="http://twistedmatrix.com/documents/8.2.0/api/twisted.plugin.IPlugin.html" title="twisted.plugin.IPlugin">IPlugin</a></code> and <code>IMaterial</code>.
 
197
</pre>
 
198
 
 
199
    <p><code>steelPlate</code> and <code>brassPlate</code> now provide both
 
200
    <code class="API"><a href="http://twistedmatrix.com/documents/9.0.0/api/twisted.plugin.IPlugin.html" title="twisted.plugin.IPlugin">IPlugin</a></code> and <code>IMaterial</code>.
97
201
    All that remains is to make this module available at an appropriate
98
202
    location. For this, there are two options. The first of these is
99
203
    primarily useful during development: if a directory which
106
210
    directory to be skipped and no plugins loaded from it.  Second, each
107
211
    module in the installed version of Twisted's <code class="shell">
108
212
    twisted.plugins</code> package will also be loaded as a source of
109
 
    plugins.</p><p>Once this plugin is installed in one of these two ways,
 
213
    plugins.</p>
 
214
 
 
215
    <p>Once this plugin is installed in one of these two ways,
110
216
    <code>displayAllKnownMaterials</code> can be run and we will see
111
217
    two pairs of output: one for a steel plate and one for a brass
112
 
    plate.</p><h2>Alternate Plugin Packages<a name="auto2"></a></h2><p><code class="API"><a href="http://twistedmatrix.com/documents/8.2.0/api/twisted.plugin.getPlugins.html" title="twisted.plugin.getPlugins">getPlugins</a></code> takes one
 
218
    plate.</p>
 
219
 
 
220
    <h2>Alternate Plugin Packages<a name="auto2"/></h2>
 
221
 
 
222
    <p><code class="API"><a href="http://twistedmatrix.com/documents/9.0.0/api/twisted.plugin.getPlugins.html" title="twisted.plugin.getPlugins">getPlugins</a></code> takes one
113
223
    additional argument not mentioned above.  If passed in, the 2nd argument
114
224
    should be a module or package to be used instead of
115
225
    <code>twisted.plugins</code> as the plugin meta-package.  If you
119
229
    are installed in your own plugins package, rather than in
120
230
    Twisted's.  In this case, you probably also want to support <code class="shell">yourproject/plugins/</code> directories for ease of
121
231
    development.  To do so, you should make the <code class="shell">__init__.py</code> for that package contain at least
122
 
    the following lines.</p><pre class="python">
123
 
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">plugin</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pluginPackagePaths</span>
 
232
    the following lines.</p>
 
233
 
 
234
    <pre class="python"><p class="py-linenumber">1
 
235
2
 
236
3
 
237
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">plugin</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pluginPackagePaths</span>
124
238
<span class="py-src-variable">__path__</span>.<span class="py-src-variable">extend</span>(<span class="py-src-variable">pluginPackagePaths</span>(<span class="py-src-variable">__name__</span>))
125
239
<span class="py-src-variable">__all__</span> = []
126
 
</pre><p>The key behavior here is that interfaces are essentially paired
 
240
</pre>
 
241
 
 
242
    <p>The key behavior here is that interfaces are essentially paired
127
243
    with a particular plugin package.  If plugins are installed in a
128
244
    different package than the one the code which relies on the
129
245
    interface they provide, they will not be found when the
130
 
    application goes to load them.</p><h2>Plugin Caching<a name="auto3"></a></h2><p>In the course of using the Twisted plugin system, you may
 
246
    application goes to load them.</p>
 
247
 
 
248
    <h2>Plugin Caching<a name="auto3"/></h2>
 
249
 
 
250
    <p>In the course of using the Twisted plugin system, you may
131
251
    notice <code class="shell">dropin.cache</code> files appearing at
132
252
    various locations.  These files are used to cache information
133
253
    about what plugins are present in the directory which contains
135
255
    Twisted uses the mtimes of various files involved in the plugin
136
256
    system to determine when this cache may have become invalid.
137
257
    Twisted will try to re-write the cache each time it tries to use
138
 
    it but finds it out of date.</p><p>For a site-wide install, it may not (indeed, should not) be
 
258
    it but finds it out of date.</p>
 
259
 
 
260
    <p>For a site-wide install, it may not (indeed, should not) be
139
261
    possible for applications running as normal users to rewrite the
140
262
    cache file.  While these applications will still run and find
141
263
    correct plugin information, they may run more slowly than they
147
269
    Well-behaved package managers for such software should take this
148
270
    task upon themselves, since it is trivially automatable.  The
149
271
    canonical way to regenerate the cache is to run the following
150
 
    Python code:</p><pre class="python">
151
 
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">plugin</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IPlugin</span>, <span class="py-src-variable">getPlugins</span>
 
272
    Python code:</p>
 
273
 
 
274
    <pre class="python"><p class="py-linenumber">1
 
275
2
 
276
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">plugin</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IPlugin</span>, <span class="py-src-variable">getPlugins</span>
152
277
<span class="py-src-variable">list</span>(<span class="py-src-variable">getPlugins</span>(<span class="py-src-variable">IPlugin</span>))
153
 
</pre><p>As mentioned, it is normal for exceptions to be raised
154
 
    <strong>once</strong> here if plugins have been removed.</p><h2>Further Reading<a name="auto4"></a></h2><ul><li><a href="components.html">Components: Interfaces and Adapters</a></li></ul></div><p><a href="index.html">Index</a></p><span class="version">Version: 8.2.0</span></body></html>
 
 
b'\\ No newline at end of file'
 
278
</pre>
 
279
 
 
280
    <p>As mentioned, it is normal for exceptions to be raised
 
281
    <strong>once</strong> here if plugins have been removed.</p>
 
282
 
 
283
    <h2>Further Reading<a name="auto4"/></h2>
 
284
 
 
285
    <ul>
 
286
 
 
287
      <li><a href="components.html" shape="rect">Components: Interfaces and Adapters</a></li>
 
288
 
 
289
    </ul>
 
290
 
 
291
  </div>
 
292
 
 
293
    <p><a href="index.html">Index</a></p>
 
294
    <span class="version">Version: 9.0.0</span>
 
295
  </body>
 
296
</html>
 
 
b'\\ No newline at end of file'