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"?>
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">
7
<title>Twisted Documentation: The Twisted Plugin System</title>
8
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
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>
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>
25
<p>Making an application extensible using the plugin system has
26
several strong advantages over other techniques:</p>
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>
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>
40
<h2>Writing Extensible Programs<a name="auto0"/></h2>
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>
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.
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
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
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
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>
74
<pre class="python"><p class="py-linenumber"> 1
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>
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">"""
55
119
real part giving reflective surface properties and the
56
120
imaginary part giving the radio absorption coefficient.
57
121
"""</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>):
124
<p>In another module, we might have a function that operates on
125
objects providing the <code>IMaterial</code> interface:</p>
127
<pre class="python"><p class="py-linenumber">1
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
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>
139
<pre class="python"><p class="py-linenumber">1
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>
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
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>
157
<h2>Extending an Existing Program<a name="auto1"/></h2>
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>
165
<pre class="python"><p class="py-linenumber"> 1
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>
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>.
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,
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
220
<h2>Alternate Plugin Packages<a name="auto2"/></h2>
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>
234
<pre class="python"><p class="py-linenumber">1
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
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>
248
<h2>Plugin Caching<a name="auto3"/></h2>
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>
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>
274
<pre class="python"><p class="py-linenumber">1
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'
280
<p>As mentioned, it is normal for exceptions to be raised
281
<strong>once</strong> here if plugins have been removed.</p>
283
<h2>Further Reading<a name="auto4"/></h2>
287
<li><a href="components.html" shape="rect">Components: Interfaces and Adapters</a></li>
293
<p><a href="index.html">Index</a></p>
294
<span class="version">Version: 9.0.0</span>
b'\\ No newline at end of file'