~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/soyuz/doc/vocabularies.txt

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-12-15 10:35:32 UTC
  • mfrom: (14517.1.3 new-bzr)
  • Revision ID: launchpad@pqm.canonical.com-20111215103532-q2m4uyk0r8ugiayx
[r=sinzui, poolie][bug=509016] Always load foreign plugins,
 but restrict probers to avoid accidentally opening foreign branches.
 (re-land)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
Vocabularies
2
 
============
3
 
 
4
 
Introduction
5
 
------------
6
 
 
7
 
Vocabularies are lists of terms. In Launchpad's Component Architecture
8
 
(CA), a vocabulary is a list of terms that a widget (normally a selection
9
 
style widget) "speaks", i.e., its allowed values.
10
 
 
11
 
    >>> from zope.component import getUtility
12
 
    >>> from canonical.launchpad.ftests import login
13
 
    >>> from canonical.database.sqlbase import flush_database_updates
14
 
    >>> from canonical.launchpad.webapp.interfaces import IOpenLaunchBag
15
 
    >>> from lp.registry.interfaces.person import IPersonSet
16
 
    >>> from lp.registry.interfaces.product import IProductSet
17
 
    >>> person_set = getUtility(IPersonSet)
18
 
    >>> product_set = getUtility(IProductSet)
19
 
    >>> login('foo.bar@canonical.com')
20
 
    >>> launchbag = getUtility(IOpenLaunchBag)
21
 
    >>> launchbag.clear()
22
 
 
23
 
 
24
 
Values, Tokens, and Titles
25
 
..........................
26
 
 
27
 
In Launchpad, we generally use "tokenized vocabularies." Each term in
28
 
a vocabulary has a value, token and title. A term is rendered in a
29
 
select widget like this:
30
 
 
31
 
<option value="$token">$title</option>
32
 
 
33
 
The $token is probably the data you would store in your DB. The Token is
34
 
used to uniquely identify a Term, and the Title is the thing you display
35
 
to the user.
36
 
 
37
 
 
38
 
Launchpad Vocabularies
39
 
----------------------
40
 
 
41
 
There are two kinds of vocabularies in Launchpad: enumerable and
42
 
non-enumerable. Enumerable vocabularies are short enough to render in a
43
 
select widget. Non-enumerable vocabularies require a query interface to make
44
 
it easy to choose just one or a couple of options from several hundred,
45
 
several thousand, or more.
46
 
 
47
 
Vocabularies should not be imported - they can be retrieved from the
48
 
vocabulary registry.
49
 
 
50
 
    >>> from zope.schema.vocabulary import getVocabularyRegistry
51
 
    >>> from zope.security.proxy import removeSecurityProxy
52
 
    >>> vocabulary_registry = getVocabularyRegistry()
53
 
    >>> def get_naked_vocab(context, name):
54
 
    ...     return removeSecurityProxy(
55
 
    ...         vocabulary_registry.get(context, name))
56
 
    >>> product_vocabulary = vocabulary_registry.get(None, "Product")
57
 
    >>> product_vocabulary.displayname
58
 
    'Select a project'
59
 
 
60
 
 
61
 
Iterating over non-enumerable vocabularies, while possible, will
62
 
probably kill the database. Instead, these vocabularies are
63
 
search-driven.
64
 
 
65
 
 
66
 
BinaryAndSourcePackageNameVocabulary
67
 
....................................
68
 
 
69
 
The list of binary and source package names, ordered by name.
70
 
 
71
 
    >>> package_name_vocabulary = vocabulary_registry.get(
72
 
    ...     None, "BinaryAndSourcePackageName")
73
 
    >>> package_name_vocabulary.displayname
74
 
    'Select a Package'
75
 
 
76
 
When a package name matches both a binary package name and a source
77
 
package of the exact same name, the binary package name is
78
 
returned. This allows us, in bug reporting for example, to collect the
79
 
most specific information possible.
80
 
 
81
 
Let's demonstrate by searching for "mozilla-firefox", for which there is
82
 
both a source and binary package of that name.
83
 
 
84
 
    >>> package_name_terms = package_name_vocabulary.searchForTerms(
85
 
    ...     "mozilla-firefox")
86
 
    >>> package_name_terms.count()
87
 
    2
88
 
    >>> [(term.token, term.title) for term in package_name_terms]
89
 
    [('mozilla-firefox', u'mozilla-firefox'),
90
 
     ('mozilla-firefox-data', u'mozilla-firefox-data')]
91
 
 
92
 
Searching for "mozilla" should return the binary package name above, and
93
 
the source package named "mozilla".
94
 
 
95
 
    >>> package_name_terms = package_name_vocabulary.searchForTerms("mozilla")
96
 
    >>> package_name_terms.count()
97
 
    3
98
 
    >>> [(term.token, term.title) for term in package_name_terms]
99
 
    [('mozilla', u'mozilla'),
100
 
     ('mozilla-firefox', u'mozilla-firefox'),
101
 
     ('mozilla-firefox-data', u'mozilla-firefox-data')]
102
 
 
103
 
The search does a case-insensitive, substring match.
104
 
 
105
 
    >>> package_name_terms = package_name_vocabulary.searchForTerms("lInuX")
106
 
    >>> package_name_terms.count()
107
 
    2
108
 
    >>> [(term.token, term.title) for term in package_name_terms]
109
 
    [('linux-2.6.12', u'linux-2.6.12'),
110
 
     ('linux-source-2.6.15', u'linux-source-2.6.15')]
111
 
 
112
 
 
113
 
BinaryPackageNameVocabulary
114
 
...........................
115
 
 
116
 
All the binary packages in Launchpad.
117
 
 
118
 
    >>> bpn_vocabulary = vocabulary_registry.get(None, 'BinaryPackageName')
119
 
    >>> len(bpn_vocabulary)
120
 
    8
121
 
 
122
 
    >>> bpn_terms = bpn_vocabulary.searchForTerms("mozilla")
123
 
    >>> len(bpn_terms)
124
 
    2
125
 
    >>> [(term.token, term.title) for term in bpn_terms]
126
 
    [('mozilla-firefox', u'iceweasel huh ?'),
127
 
     ('mozilla-firefox-data', u'Mozilla Firefox Data is .....')]
128
 
 
129
 
 
130
 
SourcePackageNameVocabulary
131
 
...........................
132
 
 
133
 
All the source packages in Launchpad.
134
 
 
135
 
    >>> spn_vocabulary = vocabulary_registry.get(None, 'SourcePackageName')
136
 
    >>> len(spn_vocabulary)
137
 
    17
138
 
 
139
 
    >>> spn_terms = spn_vocabulary.searchForTerms("mozilla")
140
 
    >>> len(spn_terms)
141
 
    2
142
 
    >>> [(term.token, term.title) for term in spn_terms]
143
 
    [('mozilla', u'mozilla'), ('mozilla-firefox', u'mozilla-firefox')]
144
 
 
145
 
    >>> spn_terms = spn_vocabulary.searchForTerms("pmount")
146
 
    >>> len(spn_terms)
147
 
    1
148
 
    >>> [(term.token, term.title) for term in spn_terms]
149
 
    [('pmount', u'pmount')]
150
 
 
151
 
 
152
 
Processor
153
 
.........
154
 
 
155
 
All processors type available in Launchpad.
156
 
 
157
 
    >>> vocab = vocabulary_registry.get(None, "Processor")
158
 
    >>> vocab.displayname
159
 
    'Select a processor'
160
 
 
161
 
    >>> [term.token for term in vocab.searchForTerms('386')]
162
 
    ['386']
163
 
 
164
 
 
165
 
PPA
166
 
...
167
 
 
168
 
The PPA vocabulary contains all the PPAs available in a particular
169
 
collection. It provides the IHugeVocabulary interface.
170
 
 
171
 
    >>> from canonical.launchpad.webapp.testing import verifyObject
172
 
    >>> from canonical.launchpad.webapp.vocabulary import IHugeVocabulary
173
 
 
174
 
    >>> vocabulary = get_naked_vocab(None, 'PPA')
175
 
    >>> verifyObject(IHugeVocabulary, vocabulary)
176
 
    True
177
 
 
178
 
    >>> print vocabulary.displayname
179
 
    Select a PPA
180
 
 
181
 
Iterations over the PPA vocabulary will return on PPA archives.
182
 
 
183
 
    >>> sorted([term.value.owner.name for term in vocabulary])
184
 
    [u'cprov', u'mark', u'no-priv']
185
 
 
186
 
PPA vocabulary terms contain:
187
 
 
188
 
 * token: the PPA owner name combined with the archive name (using '/');
189
 
 * value: the IArchive object;
190
 
 * title: the first line of the PPA description text.
191
 
 
192
 
    >>> cprov_term = vocabulary.getTermByToken('cprov/ppa')
193
 
 
194
 
    >>> print cprov_term.token
195
 
    cprov/ppa
196
 
 
197
 
    >>> print cprov_term.value
198
 
    <Archive ...>
199
 
 
200
 
    >>> print cprov_term.title
201
 
    packages to help my friends.
202
 
 
203
 
Not found terms result in LookupError.
204
 
 
205
 
    >>> vocabulary.getTermByToken('foobar')
206
 
    Traceback (most recent call last):
207
 
    ...
208
 
    LookupError: foobar
209
 
 
210
 
PPA vocabulary searches consider the owner FTI and the PPA FTI.
211
 
 
212
 
    >>> def print_search_results(results):
213
 
    ...     for archive in results:
214
 
    ...         term = vocabulary.toTerm(archive)
215
 
    ...         print '%s: %s' % (term.token, term.title)
216
 
 
217
 
    >>> cprov_search = vocabulary.search('cprov')
218
 
    >>> print_search_results(cprov_search)
219
 
    cprov/ppa: packages to help my friends.
220
 
 
221
 
    >>> celso_search = vocabulary.search('celso')
222
 
    >>> print_search_results(celso_search)
223
 
    cprov/ppa: packages to help my friends.
224
 
 
225
 
    >>> friends_search = vocabulary.search('friends')
226
 
    >>> print_search_results(friends_search)
227
 
    cprov/ppa: packages to help my friends.
228
 
 
229
 
We will create an additional PPA for Celso named 'testing'
230
 
 
231
 
    >>> from lp.soyuz.enums import ArchivePurpose
232
 
    >>> from lp.soyuz.interfaces.archive import IArchiveSet
233
 
 
234
 
    >>> login('foo.bar@canonical.com')
235
 
    >>> cprov = getUtility(IPersonSet).getByName('cprov')
236
 
    >>> cprov_testing = getUtility(IArchiveSet).new(
237
 
    ...     owner=cprov, name='testing', purpose=ArchivePurpose.PPA,
238
 
    ...     description='testing packages.')
239
 
 
240
 
Now, a search for 'cprov' will return 2 ppas and the result is ordered
241
 
by PPA name.
242
 
 
243
 
    >>> cprov_search = vocabulary.search('cprov')
244
 
    >>> print_search_results(cprov_search)
245
 
    cprov/ppa: packages to help my friends.
246
 
    cprov/testing: testing packages.
247
 
 
248
 
The vocabulary search also supports specific named PPA lookups
249
 
follwing the same combined syntax used to build unique tokens.
250
 
 
251
 
    >>> named_search = vocabulary.search('cprov/testing')
252
 
    >>> print_search_results(named_search)
253
 
    cprov/testing: testing packages.
254
 
 
255
 
As mentioned the PPA vocabulary term title only contains the first
256
 
line of the PPA description.
257
 
 
258
 
    >>> cprov.archive.description = "Single line."
259
 
    >>> flush_database_updates()
260
 
 
261
 
    >>> cprov_term = vocabulary.getTermByToken('cprov/ppa')
262
 
    >>> print cprov_term.title
263
 
    Single line.
264
 
 
265
 
    >>> cprov.archive.description = "First line\nSecond line."
266
 
    >>> flush_database_updates()
267
 
 
268
 
    >>> cprov_term = vocabulary.getTermByToken('cprov/ppa')
269
 
    >>> print cprov_term.title
270
 
    First line
271
 
 
272
 
PPAs with empty description are identified and have a title saying so.
273
 
 
274
 
    >>> cprov.archive.description = None
275
 
    >>> flush_database_updates()
276
 
 
277
 
    >>> cprov_term = vocabulary.getTermByToken('cprov/ppa')
278
 
    >>> print cprov_term.title
279
 
    No description available
280
 
 
281
 
Queries on empty strings also results in a valid SelectResults.
282
 
 
283
 
    >>> empty_search = vocabulary.search('')
284
 
    >>> empty_search.count() == 0
285
 
    True