~justin-fathomdb/nova/justinsb-openstack-api-volumes

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/doc/core/howto/plugin.html

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

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