1.1.10
by Free Ekanayaka
Import upstream version 10.0.0 |
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"> |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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 |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
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 |
|
1.1.6
by Matthias Klose
Import upstream version 8.0.1 |
18 |
implement this API to provide some additional functionality. |
1.1.10
by Free Ekanayaka
Import upstream version 10.0.0 |
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> |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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 |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
26 |
software in a way that is loosely coupled: only the plugin API |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
27 |
is required to remain stable.</li> |
28 |
||
29 |
<li>It allows new plugins to be discovered flexibly. For |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
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 |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
33 |
of new plugins installed after the program has started).</li> |
34 |
</ul> |
|
35 |
||
36 |
<h2>Writing Extensible Programs<a name="auto0"/></h2> |
|
37 |
||
1.1.10
by Free Ekanayaka
Import upstream version 10.0.0 |
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 |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
39 |
a two step process:</p> |
40 |
||
41 |
<ol> |
|
42 |
<li> |
|
43 |
<p> |
|
1.1.6
by Matthias Klose
Import upstream version 8.0.1 |
44 |
Define an interface which plugins will be required to implement. |
1.1.8
by Matthias Klose
Import upstream version 8.2.0 |
45 |
This is done using the zope.interface package in the same way one |
46 |
would define an interface for any other purpose. |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
47 |
</p> |
48 |
||
49 |
<p> |
|
1.1.5
by Matthias Klose
Import upstream version 2.5.0 |
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. |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
56 |
</p> |
57 |
</li> |
|
58 |
||
59 |
<li> |
|
1.1.10
by Free Ekanayaka
Import upstream version 10.0.0 |
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 |
1.1.5
by Matthias Klose
Import upstream version 2.5.0 |
61 |
result. |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
62 |
</li> |
63 |
</ol> |
|
64 |
||
65 |
<p> |
|
1.1.5
by Matthias Klose
Import upstream version 2.5.0 |
66 |
As an example of the first step, consider the following interface |
67 |
definition for a physical modelling system. |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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> |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
95 |
|
10
by Matthias Klose
Synchronize with Debian unstable. |
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">""" |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
98 |
An object with specific physical properties |
10
by Matthias Klose
Synchronize with Debian unstable. |
99 |
"""</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">""" |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
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 |
|
10
by Matthias Klose
Synchronize with Debian unstable. |
110 |
"""</span> |
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
111 |
|
10
by Matthias Klose
Synchronize with Debian unstable. |
112 |
<span class="py-src-variable">dielectricConstant</span> = <span class="py-src-variable">Attribute</span>(<span class="py-src-string">""" |
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
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. |
|
10
by Matthias Klose
Synchronize with Debian unstable. |
117 |
"""</span>) |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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>): |
|
10
by Matthias Klose
Synchronize with Debian unstable. |
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>,) |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
129 |
</pre> |
130 |
||
131 |
<p>The last piece of required code is that which collects |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
132 |
<code>IMaterial</code> providers and passes them to the |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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> |
|
10
by Matthias Klose
Synchronize with Debian unstable. |
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> |
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
143 |
|
10
by Matthias Klose
Synchronize with Debian unstable. |
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>) |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
147 |
</pre> |
148 |
||
149 |
<p>Third party developers may now contribute different materials |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
150 |
to be used by this modelling system by implementing one or more |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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 |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
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 |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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> |
|
10
by Matthias Klose
Synchronize with Debian unstable. |
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>): |
|
1.1.5
by Matthias Klose
Import upstream version 2.5.0 |
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> |
10
by Matthias Klose
Synchronize with Debian unstable. |
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>) |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
193 |
</pre> |
194 |
||
195 |
<p><code>steelPlate</code> and <code>brassPlate</code> now provide both |
|
1.1.10
by Free Ekanayaka
Import upstream version 10.0.0 |
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>. |
1.1.8
by Matthias Klose
Import upstream version 8.2.0 |
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 |
|
1.1.6
by Matthias Klose
Import upstream version 8.0.1 |
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 |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
209 |
plugins.</p> |
210 |
||
211 |
<p>Once this plugin is installed in one of these two ways, |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
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 |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
214 |
plate.</p> |
215 |
||
216 |
<h2>Alternate Plugin Packages<a name="auto2"/></h2> |
|
217 |
||
1.1.10
by Free Ekanayaka
Import upstream version 10.0.0 |
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 |
1.1.8
by Matthias Klose
Import upstream version 8.2.0 |
219 |
additional argument not mentioned above. If passed in, the 2nd argument |
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
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 |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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> |
|
1.1.6
by Matthias Klose
Import upstream version 8.0.1 |
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>)) |
10
by Matthias Klose
Synchronize with Debian unstable. |
235 |
<span class="py-src-variable">__all__</span> = [] |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
236 |
</pre> |
237 |
||
238 |
<p>The key behavior here is that interfaces are essentially paired |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
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 |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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 |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
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 |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
254 |
it but finds it out of date.</p> |
255 |
||
256 |
<p>For a site-wide install, it may not (indeed, should not) be |
|
1.1.3
by Matthias Klose
Import upstream version 2.1.0 |
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 |
|
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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> |
|
1.1.6
by Matthias Klose
Import upstream version 8.0.1 |
273 |
<span class="py-src-variable">list</span>(<span class="py-src-variable">getPlugins</span>(<span class="py-src-variable">IPlugin</span>)) |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
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> |
|
1.1.10
by Free Ekanayaka
Import upstream version 10.0.0 |
290 |
<span class="version">Version: 10.0.0</span> |
1.1.9
by Matthias Klose
Import upstream version 9.0.0 |
291 |
</body> |
292 |
</html> |