1
##############################################################################
3
# Copyright (c) 2003 Zope Corporation and Contributors.
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
13
##############################################################################
14
r"""How to write a simple directive
16
This module documents how to write a simple directive.
18
A simple directive is a directive that doesn't contain other
19
directives. It can be implemented via a fairly simple function.
20
To implement a simple directive, you need to do 3 things:
22
- You need to create a schema to describe the directive parameters,
24
- You need to write a directive handler, and
26
- You need to register the directive.
28
In this module, we'll implement a contrived example that records
29
information about files in a file registry. The file registry is just
30
the list, ``file_registry``. Our registry will contain tuples
39
- Information about where the file was defined
41
Our schema is defined in IRegisterFile (see below). Our schema lists
42
the path and title. We'll get the description and other information
43
for free, as we'll see later. The title is not required, and may be
46
The job of a configuration handler is to compute one or more
47
configuration actions. Configuration actions are defered function
48
calls. The handler doesn't perform the actions. It just computes
49
actions, which may be performed later if they are not overridden by
52
Out handler is given in the function, ``registerFile``. It takes a context,
53
a path and a title. All directive handlers take the directive context
54
as the first argument. A directive context, at a minimim, implements,
55
``zope.configuration.IConfigurationContext``. (Specialized contexts
56
can implement more specific interfaces. We'll say more about that when
57
we talk about grouping directives.) The title argument
58
must have a default value, because we indicated that the title was not
59
required in the schema. (Alternatively, we could have made the title
60
required, but provided a default value in the schema.
62
In the first line of function `registerFile`, we get the context information
63
object. This object contains information about the configuration
64
directive, such as the file and location within the file of the
67
The context information object also has a text attribute that contains
68
the textual data contained by the configuration directive. (This is
69
the concatenation of all of the xml text nodes directly contained by
70
the directive.) We use this for our description in the second line
73
The last thing the handler does is to compute an action by calling the
74
action method of the context. It passes the action method 3 keyword
79
The discriminator is used to identify the action to be performed so
80
that duplicate actions can be detected. Two actions are duplicated,
81
and this conflict, if they have the same discriminator values and
82
the values are not ``None``. Conflicting actions can be resolved if
83
one of the conflicting actions is from a configuration file that
84
directly or indirectly includes the files containing the other
87
In function ``registerFile``, we a tuple with the string
88
``'RegisterFile'`` and the path to be registered.
92
The callable is the object to be called to perform the action.
96
The args argument contains positinal arguments to be passed to the
97
callable. In function ``registerFile``, we pass a tuple containing a
100
(Note that there's nothing special about the FileInfo class. It has
101
nothing to do with creating simple directives. It's just used in
102
this example to organize the application data.)
105
The final step in implementing the simple directive is to register
106
it. We do that with the zcml ``meta:directive`` directive. This is
107
given in the file simple.zcml. Here we specify the name, namespace,
108
schema, and handler for the directive. We also provide a
109
documentation for the directive as text between the start and end
112
The file simple.zcml also includes some directives that use the new
113
directive to register some files.
115
Now let's try it all out:
117
>>> from zope.configuration import tests
118
>>> context = xmlconfig.file("simple.zcml", tests)
120
Now we should see some file information in the registry:
122
>>> from zope.configuration.tests.test_xmlconfig import clean_text_w_paths
123
>>> from zope.configuration.tests.test_xmlconfig import clean_path
124
>>> for i in file_registry:
125
... print "path:", clean_path(i.path)
126
... print "title:", i.title
127
... print "description:", '\n'.join(
129
... for l in i.description.strip().split('\n')
132
... print clean_text_w_paths(i.info)
133
path: tests/test_simple.py
134
title: How to create a simple directive
135
description: Describes how to implement a simple directive
137
File "tests/simple.zcml", line 19.2-24.2
139
path="test_simple.py"
140
title="How to create a simple directive"
142
Describes how to implement a simple directive
144
path: tests/simple.zcml
146
description: Shows the ZCML directives needed to register a simple directive.
147
Also show some usage examples,
149
File "tests/simple.zcml", line 26.2-30.2
150
<files:register path="simple.zcml">
151
Shows the ZCML directives needed to register a simple directive.
152
Also show some usage examples,
154
path: tests/__init__.py
155
title: Make this a package
158
File "tests/simple.zcml", line 32.2-32.67
159
<files:register path="__init__.py" title="Make this a package" />
162
We'll clean up after ourselves:
164
>>> del file_registry[:]
173
from zope.testing.doctestunit import DocTestSuite
174
from zope import interface
175
from zope import schema
176
from zope.configuration import fields, xmlconfig
178
class IRegisterFile(interface.Interface):
182
description=u"This is the path name of the file to be registered."
186
title=u"Short summary of the file",
187
description=u"This will be used in file listings",
191
class FileInfo(object):
193
def __init__(self, path, title, description, info):
194
(self.path, self.title, self.description, self.info
195
) = path, title, description, info
197
def registerFile(context, path, title=u""):
199
description = info.text.strip()
200
context.action(discriminator=('RegisterFile', path),
201
callable=file_registry.append,
202
args=(FileInfo(path, title, description, info),)
206
return unittest.TestSuite((
210
if __name__ == '__main__': unittest.main()