Merge lp:~adiroiban/launchpad/bug-532239 into lp:launchpad

Proposed by Adi Roiban
Status: Work in progress
Proposed branch: lp:~adiroiban/launchpad/bug-532239
Merge into: lp:launchpad
Diff against target: 790 lines (+104/-164)
23 files modified
lib/canonical/launchpad/doc/vocabularies.txt (+2/-2)
lib/canonical/launchpad/xmlrpc/configure.zcml (+1/-5)
lib/canonical/launchpad/xmlrpc/faults.py (+7/-19)
lib/lp/code/interfaces/branchlookup.py (+3/-5)
lib/lp/code/interfaces/branchnamespace.py (+3/-5)
lib/lp/code/model/branchlookup.py (+6/-7)
lib/lp/code/model/branchnamespace.py (+3/-3)
lib/lp/code/model/linkedbranch.py (+2/-2)
lib/lp/code/model/tests/test_branchlookup.py (+7/-8)
lib/lp/code/model/tests/test_branchnamespace.py (+3/-3)
lib/lp/code/model/tests/test_linkedbranch.py (+2/-2)
lib/lp/code/xmlrpc/branch.py (+3/-7)
lib/lp/code/xmlrpc/tests/test_branch.py (+9/-9)
lib/lp/registry/interfaces/distroseries.py (+1/-35)
lib/lp/registry/interfaces/productseries.py (+0/-38)
lib/lp/registry/interfaces/series.py (+43/-3)
lib/lp/registry/model/distribution.py (+2/-2)
lib/lp/registry/model/distroseries.py (+0/-1)
lib/lp/registry/model/productseries.py (+0/-1)
lib/lp/registry/model/series.py (+1/-0)
lib/lp/registry/stories/webservice/xx-distribution.txt (+1/-1)
lib/lp/registry/tests/test_distribution.py (+2/-3)
lib/lp/registry/tests/test_distroseries.py (+3/-3)
To merge this branch: bzr merge lp:~adiroiban/launchpad/bug-532239
Reviewer Review Type Date Requested Status
Robert Collins (community) Needs Information
Review via email: mp+30108@code.launchpad.net

Commit message

Merge 'name' attribute in the common series mixin.

Description of the change

= Bug 532239 =
Since for solving bug 531261, moving name attribute would make the diff to big, I'm opening this bug to be fixed in a different branch.

We will also need to merge DistroSeriesNameField , NoSuchDistroSeries and ProductSeriesNameField , NoSuchProductSeries and the expcetion are used in many places.

== Proposed fix ==

Move name attribute in the common Series interface and mixin.

== Pre-implementation notes ==

I had a short chat with Sinzui and he agreed that merging NoSuchDistroSeries and NoSuchProductSeries into NoSuchSeries is a good idea.
He also volunteer to review this branch in case someone else thing it is too big.

== Implementation details ==

Name attribute is attached to a name validation which was raising

== Tests ==
./bin/test -t test_branchlookup -t test_branchnamespace -t test_linkedbranch -t test_branch -t test_distroseries -t test_distribution -t test_distribution -t vocabularie -t xx-distribution

== Demo and Q/A ==
Since this is a refactoring there is not much of QA and Demo.
Basically if you observe any changes, this branch is of not good :)

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

I have a few open questions here.

Firstly, we use the XMLRPC server from live servers. Will this / can this cause the existing users to handle errors wrongly (I think it can). If so, we'll have to do special rollouts for this change, which is a pain. Please consider how to avoid that (e.g. by landing a fix to the clients in advance of this change, in particular the fix would need to be CP'd in advance).

Secondly, you seem to be reducing the clarity of raised errors, and I don't see that as being an improvement. (By dropping the context that the missing thing is missing in).

review: Needs Information
Revision history for this message
Gavin Panella (allenap) wrote :

Is there still interest in landing this?

Revision history for this message
Robert Collins (lifeless) wrote :

6 months with no reply, I'm moving this to work in progress. Adi, if/when you want to move it forward please just change the merge proposal status to needs review.

Unmerged revisions

10701. By Adi Roiban

Fix tests.

10700. By Adi Roiban

Merge devel.

10699. By Adi Roiban

Fix usage of NoSuchSeries as a replacement for NoSuchProductSeries.

10698. By Adi Roiban

Merge devel.

10697. By Adi Roiban

Initial changes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/doc/vocabularies.txt'
2--- lib/canonical/launchpad/doc/vocabularies.txt 2010-02-17 11:13:06 +0000
3+++ lib/canonical/launchpad/doc/vocabularies.txt 2010-07-16 14:15:25 +0000
4@@ -236,12 +236,12 @@
5 True
6
7 Trying to get a non-existent release will result in a
8-NoSuchDistroSeries error.
9+NoSuchSeries error.
10
11 >>> series_vocabulary.getTermByToken('non-such-release')
12 Traceback (most recent call last):
13 ...
14- NoSuchDistroSeries...
15+ NoSuchSeries...
16
17
18 === ProjectProductsVocabularyUsingMalone ===
19
20=== modified file 'lib/canonical/launchpad/xmlrpc/configure.zcml'
21--- lib/canonical/launchpad/xmlrpc/configure.zcml 2010-07-01 19:39:54 +0000
22+++ lib/canonical/launchpad/xmlrpc/configure.zcml 2010-07-16 14:15:25 +0000
23@@ -140,10 +140,6 @@
24 <require like_class="xmlrpclib.Fault" />
25 </class>
26
27- <class class="canonical.launchpad.xmlrpc.faults.NoSuchProductSeries">
28- <require like_class="xmlrpclib.Fault" />
29- </class>
30-
31 <class class="canonical.launchpad.xmlrpc.faults.InvalidBranchIdentifier">
32 <require like_class="xmlrpclib.Fault" />
33 </class>
34@@ -196,7 +192,7 @@
35 <require like_class="xmlrpclib.Fault" />
36 </class>
37
38- <class class="canonical.launchpad.xmlrpc.faults.NoSuchDistroSeries">
39+ <class class="canonical.launchpad.xmlrpc.faults.NoSuchSeries">
40 <require like_class="xmlrpclib.Fault" />
41 </class>
42
43
44=== modified file 'lib/canonical/launchpad/xmlrpc/faults.py'
45--- lib/canonical/launchpad/xmlrpc/faults.py 2010-07-02 12:10:21 +0000
46+++ lib/canonical/launchpad/xmlrpc/faults.py 2010-07-16 14:15:25 +0000
47@@ -32,7 +32,7 @@
48 'NoSuchPerson',
49 'NoSuchPersonWithName',
50 'NoSuchProduct',
51- 'NoSuchProductSeries',
52+ 'NoSuchSeries',
53 'NoSuchTeamMailingList',
54 'NotInTeam',
55 'NoUrlForBranch',
56@@ -226,18 +226,6 @@
57 LaunchpadFault.__init__(self, object_name=component.displayname)
58
59
60-class NoSuchProductSeries(LaunchpadFault):
61- """There is no such series on a particular project."""
62-
63- error_code = 180
64- msg_template = (
65- 'Project %(product_name)s has no series called "%(series_name)s"')
66-
67- def __init__(self, series_name, product):
68- LaunchpadFault.__init__(
69- self, series_name=series_name, product_name=product.name)
70-
71-
72 class InvalidBranchIdentifier(LaunchpadFault):
73 """The branch identifier didn't begin with a tilde."""
74
75@@ -419,15 +407,15 @@
76 LaunchpadFault.__init__(self, path=path)
77
78
79-class NoSuchDistroSeries(LaunchpadFault):
80- """Raised when the user tries to get a distroseries that doesn't exist."""
81+class NoSuchSeries(LaunchpadFault):
82+ """Raised when the user tries to get a series that doesn't exist."""
83
84 error_code = 340
85- msg_template = "No such distribution series %(distroseries_name)s."
86+ msg_template = "No such series %(series_name)s."
87
88- def __init__(self, distroseries_name):
89- self.distroseries_name = distroseries_name
90- LaunchpadFault.__init__(self, distroseries_name=distroseries_name)
91+ def __init__(self, series_name):
92+ self.series_name = series_name
93+ LaunchpadFault.__init__(self, series_name=series_name)
94
95
96 class NoSuchSourcePackageName(LaunchpadFault):
97
98=== modified file 'lib/lp/code/interfaces/branchlookup.py'
99--- lib/lp/code/interfaces/branchlookup.py 2009-11-19 15:46:10 +0000
100+++ lib/lp/code/interfaces/branchlookup.py 2010-07-16 14:15:25 +0000
101@@ -40,7 +40,7 @@
102 component of the path.
103 :raises NoSuchProduct: If we can't find a product that matches the
104 product component of the path.
105- :raises NoSuchProductSeries: If the series component doesn't match an
106+ :raises NoSuchSeries: If the series component doesn't match an
107 existing series.
108 :raises NoSuchSourcePackageName: If the source packagae referred to
109 does not exist.
110@@ -131,10 +131,8 @@
111 component of the path.
112 :raises NoSuchProduct: If we can't find a product that matches the
113 product component of the path.
114- :raises NoSuchProductSeries: If the product series component doesn't
115- match an existing series.
116- :raises NoSuchDistroSeries: If the distro series component doesn't
117- match an existing series.
118+ :raises NoSuchSeries: If the series component doesn't match an
119+ existing series.
120 :raises NoSuchSourcePackageName: If the source packagae referred to
121 does not exist.
122
123
124=== modified file 'lib/lp/code/interfaces/branchnamespace.py'
125--- lib/lp/code/interfaces/branchnamespace.py 2009-08-13 15:12:16 +0000
126+++ lib/lp/code/interfaces/branchnamespace.py 2010-07-16 14:15:25 +0000
127@@ -188,8 +188,7 @@
128 :raise NoSuchProduct: if the product referred to cannot be found.
129 :raise NoSuchDistribution: if the distribution referred to cannot be
130 found.
131- :raise NoSuchDistroSeries: if the distroseries referred to cannot be-
132- found.
133+ :raise NoSuchSeries: if the series referred to cannot be found.
134 :raise NoSuchSourcePackageName: if the sourcepackagename referred to
135 cannot be found.
136 :return: An `IBranchNamespace`.
137@@ -203,8 +202,7 @@
138 :raise NoSuchProduct: if the product referred to cannot be found.
139 :raise NoSuchDistribution: if the distribution referred to cannot be
140 found.
141- :raise NoSuchDistroSeries: if the distroseries referred to cannot be-
142- found.
143+ :raise NoSuchSeries: if the series referred to cannot be found.
144 :raise NoSuchSourcePackageName: if the sourcepackagename referred to
145 cannot be found.
146 :return: An `IBranchNamespace`.
147@@ -273,7 +271,7 @@
148 found.
149 :raise NoSuchDistribution: if the distribution referred to cannot be
150 found.
151- :raise NoSuchDistroSeries: if the distroseries referred to cannot be-
152+ :raise NoSuchSeries: if the series referred to cannot be-
153 found.
154 :raise NoSuchSourcePackageName: if the sourcepackagename referred to
155 cannot be found.
156
157=== modified file 'lib/lp/code/model/branchlookup.py'
158--- lib/lp/code/model/branchlookup.py 2009-11-20 15:58:09 +0000
159+++ lib/lp/code/model/branchlookup.py 2010-07-16 14:15:25 +0000
160@@ -30,12 +30,12 @@
161 CannotHaveLinkedBranch, get_linked_branch, NoLinkedBranch)
162 from lp.registry.interfaces.distribution import IDistribution
163 from lp.registry.interfaces.distroseries import (
164- IDistroSeries, IDistroSeriesSet, NoSuchDistroSeries)
165+ IDistroSeries, IDistroSeriesSet)
166 from lp.registry.interfaces.person import NoSuchPerson
167 from lp.registry.interfaces.pillar import IPillarNameSet
168 from lp.registry.interfaces.product import (
169 InvalidProductName, IProduct, NoSuchProduct)
170-from lp.registry.interfaces.productseries import NoSuchProductSeries
171+from lp.registry.interfaces.series import NoSuchSeries
172 from lp.registry.interfaces.sourcepackagename import (
173 NoSuchSourcePackageName)
174 from lp.services.utils import iter_split
175@@ -109,13 +109,13 @@
176 def traverse(self, name, segments):
177 """See `ITraversable`.
178
179- :raises NoSuchProductSeries: if 'name' doesn't match an existing
180+ :raises NoSuchSeries: if 'name' doesn't match an existing
181 series.
182 :return: `IProductSeries`.
183 """
184 series = self.context.getSeries(name)
185 if series is None:
186- raise NoSuchProductSeries(name, self.context)
187+ raise NoSuchSeries(name)
188 return series
189
190
191@@ -132,7 +132,7 @@
192 """See `ITraversable`."""
193 try:
194 return getUtility(IDistroSeriesSet).fromSuite(self.context, name)
195- except NoSuchDistroSeries:
196+ except NoSuchSeries:
197 sourcepackage = self.context.getSourcePackage(name)
198 if sourcepackage is None:
199 if segments:
200@@ -233,8 +233,7 @@
201 except (
202 CannotHaveLinkedBranch, InvalidNamespace, InvalidProductName,
203 NoSuchBranch, NoSuchPerson, NoSuchProduct,
204- NoSuchProductSeries, NoSuchDistroSeries,
205- NoSuchSourcePackageName, NoLinkedBranch):
206+ NoSuchSeries, NoSuchSourcePackageName, NoLinkedBranch):
207 return None
208
209 return Branch.selectOneBy(url=url)
210
211=== modified file 'lib/lp/code/model/branchnamespace.py'
212--- lib/lp/code/model/branchnamespace.py 2010-05-25 04:16:25 +0000
213+++ lib/lp/code/model/branchnamespace.py 2010-07-16 14:15:25 +0000
214@@ -37,8 +37,8 @@
215 from lp.code.model.branch import Branch
216 from lp.registry.interfaces.distribution import (
217 IDistributionSet, NoSuchDistribution)
218-from lp.registry.interfaces.distroseries import (
219- IDistroSeriesSet, NoSuchDistroSeries)
220+from lp.registry.interfaces.series import NoSuchSeries
221+from lp.registry.interfaces.distroseries import IDistroSeriesSet
222 from lp.registry.interfaces.person import IPersonSet, NoSuchPerson
223 from lp.registry.interfaces.pillar import IPillarNameSet
224 from lp.registry.interfaces.projectgroup import IProjectGroup
225@@ -585,7 +585,7 @@
226
227 def _findDistroSeries(self, distribution, distroseries_name):
228 return self._findOrRaise(
229- NoSuchDistroSeries, distroseries_name,
230+ NoSuchSeries, distroseries_name,
231 getUtility(IDistroSeriesSet).queryByName, distribution)
232
233 def _findSourcePackageName(self, sourcepackagename_name):
234
235=== modified file 'lib/lp/code/model/linkedbranch.py'
236--- lib/lp/code/model/linkedbranch.py 2010-04-09 01:46:52 +0000
237+++ lib/lp/code/model/linkedbranch.py 2010-07-16 14:15:25 +0000
238@@ -17,7 +17,7 @@
239 from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
240 from lp.registry.interfaces.distributionsourcepackage import (
241 IDistributionSourcePackage)
242-from lp.registry.interfaces.distroseries import NoSuchDistroSeries
243+from lp.registry.interfaces.series import NoSuchSeries
244 from lp.registry.interfaces.pocket import PackagePublishingPocket
245 from lp.registry.interfaces.product import IProduct
246 from lp.registry.interfaces.productseries import IProductSeries
247@@ -230,7 +230,7 @@
248 development_package = (
249 self.distribution_sourcepackage.development_version)
250 if development_package is None:
251- raise NoSuchDistroSeries('no current series')
252+ raise NoSuchSeries('no current series')
253 suite_sourcepackage = development_package.getSuiteSourcePackage(
254 PackagePublishingPocket.RELEASE)
255 ICanHasLinkedBranch(suite_sourcepackage).setBranch(branch, registrant)
256
257=== modified file 'lib/lp/code/model/tests/test_branchlookup.py'
258--- lib/lp/code/model/tests/test_branchlookup.py 2010-04-16 15:06:55 +0000
259+++ lib/lp/code/model/tests/test_branchlookup.py 2010-07-16 14:15:25 +0000
260@@ -20,12 +20,11 @@
261 get_branch_namespace, InvalidNamespace)
262 from lp.code.interfaces.linkedbranch import (
263 CannotHaveLinkedBranch, ICanHasLinkedBranch, NoLinkedBranch)
264-from lp.registry.interfaces.distroseries import NoSuchDistroSeries
265 from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
266 from lp.registry.interfaces.person import NoSuchPerson
267 from lp.registry.interfaces.product import (
268 InvalidProductName, NoSuchProduct)
269-from lp.registry.interfaces.productseries import NoSuchProductSeries
270+from lp.registry.interfaces.series import NoSuchSeries
271 from lp.registry.interfaces.pocket import PackagePublishingPocket
272 from lp.registry.interfaces.sourcepackagename import (
273 NoSuchSourcePackageName)
274@@ -364,13 +363,13 @@
275 def test_error_fallthrough_product_series(self):
276 # For the short name of a series branch, `traverse` raises
277 # `NoSuchProduct` if the first component refers to a non-existent
278- # product, and `NoSuchProductSeries` if the second component refers to
279+ # product, and `NoSuchSeries` if the second component refers to
280 # a non-existent series.
281 self.assertRaises(
282 NoSuchProduct, self.traverser.traverse, 'bb/dd')
283 self.factory.makeProduct(name='bb')
284 self.assertRaises(
285- NoSuchProductSeries, self.traverser.traverse, 'bb/dd')
286+ NoSuchSeries, self.traverser.traverse, 'bb/dd')
287
288 def test_product_series(self):
289 # `traverse` resolves the path to a product series to the product
290@@ -428,11 +427,11 @@
291 'distro/series/package')
292
293 def test_no_such_distro_series(self):
294- # `traverse` raises `NoSuchDistroSeries` if the distro series doesn't
295+ # `traverse` raises `NoSuchSeries` if the distro series doesn't
296 # exist.
297 self.factory.makeDistribution(name='distro')
298 self.assertRaises(
299- NoSuchDistroSeries, self.traverser.traverse,
300+ NoSuchSeries, self.traverser.traverse,
301 'distro/series/package')
302
303 def test_no_such_sourcepackagename(self):
304@@ -617,14 +616,14 @@
305 def test_too_long_product(self):
306 # If the provided path points to an existing product with a linked
307 # branch but there are also extra path segments, then raise a
308- # NoSuchProductSeries error, since we can't tell the difference
309+ # NoSuchSeries error, since we can't tell the difference
310 # between a trailing path and an attempt to load a non-existent series
311 # branch.
312 branch = self.factory.makeProductBranch()
313 product = removeSecurityProxy(branch.product)
314 product.development_focus.branch = branch
315 self.assertRaises(
316- NoSuchProductSeries,
317+ NoSuchSeries,
318 self.branch_lookup.getByLPPath, '%s/other/bits' % product.name)
319
320 def test_too_long_product_series(self):
321
322=== modified file 'lib/lp/code/model/tests/test_branchnamespace.py'
323--- lib/lp/code/model/tests/test_branchnamespace.py 2010-05-21 17:04:28 +0000
324+++ lib/lp/code/model/tests/test_branchnamespace.py 2010-07-16 14:15:25 +0000
325@@ -27,7 +27,7 @@
326 IBranchNamespaceSet, lookup_branch_namespace, InvalidNamespace)
327 from lp.code.interfaces.branchtarget import IBranchTarget
328 from lp.registry.interfaces.distribution import NoSuchDistribution
329-from lp.registry.interfaces.distroseries import NoSuchDistroSeries
330+from lp.registry.interfaces.series import NoSuchSeries
331 from lp.registry.interfaces.person import NoSuchPerson
332 from lp.registry.interfaces.product import NoSuchProduct
333 from lp.registry.interfaces.sourcepackagename import (
334@@ -527,7 +527,7 @@
335 person = self.factory.makePerson()
336 distribution = self.factory.makeDistribution()
337 self.assertRaises(
338- NoSuchDistroSeries, lookup_branch_namespace,
339+ NoSuchSeries, lookup_branch_namespace,
340 '~%s/%s/no-such-series/whocares'
341 % (person.name, distribution.name))
342
343@@ -769,7 +769,7 @@
344 segments = iter(
345 [person.name, distro.name, 'no-such-series', 'package', 'branch'])
346 self.assertRaises(
347- NoSuchDistroSeries, self.namespace_set.traverse, segments)
348+ NoSuchSeries, self.namespace_set.traverse, segments)
349 self.assertEqual(['package', 'branch'], list(segments))
350
351 def test_traverse_sourcepackagename_not_found(self):
352
353=== modified file 'lib/lp/code/model/tests/test_linkedbranch.py'
354--- lib/lp/code/model/tests/test_linkedbranch.py 2010-04-16 15:06:55 +0000
355+++ lib/lp/code/model/tests/test_linkedbranch.py 2010-07-16 14:15:25 +0000
356@@ -15,7 +15,7 @@
357 from canonical.testing.layers import DatabaseFunctionalLayer
358 from lp.code.interfaces.linkedbranch import (
359 CannotHaveLinkedBranch, get_linked_branch, ICanHasLinkedBranch)
360-from lp.registry.interfaces.distroseries import NoSuchDistroSeries
361+from lp.registry.interfaces.series import NoSuchSeries
362 from lp.registry.interfaces.pocket import PackagePublishingPocket
363 from lp.testing import run_with_login, TestCaseWithFactory
364
365@@ -175,7 +175,7 @@
366 ubuntu_branches = getUtility(ILaunchpadCelebrities).ubuntu_branches
367 registrant = ubuntu_branches.teamowner
368 self.assertRaises(
369- NoSuchDistroSeries,
370+ NoSuchSeries,
371 linked_branch.setBranch, self.factory.makeAnyBranch(), registrant)
372
373 def test_bzr_path(self):
374
375=== modified file 'lib/lp/code/xmlrpc/branch.py'
376--- lib/lp/code/xmlrpc/branch.py 2010-02-21 21:13:34 +0000
377+++ lib/lp/code/xmlrpc/branch.py 2010-07-16 14:15:25 +0000
378@@ -31,11 +31,10 @@
379 get_branch_namespace, InvalidNamespace)
380 from lp.code.interfaces.linkedbranch import (
381 CannotHaveLinkedBranch, NoLinkedBranch)
382-from lp.registry.interfaces.distroseries import NoSuchDistroSeries
383 from lp.registry.interfaces.person import NoSuchPerson
384 from lp.registry.interfaces.product import (
385 InvalidProductName, NoSuchProduct)
386-from lp.registry.interfaces.productseries import NoSuchProductSeries
387+from lp.registry.interfaces.series import NoSuchSeries
388 from lp.registry.interfaces.sourcepackagename import (
389 NoSuchSourcePackageName)
390 from canonical.launchpad.validators import LaunchpadValidationError
391@@ -241,15 +240,12 @@
392 # or using a narrower range of faults (e.g. only one "NoSuch" fault).
393 except InvalidProductName, e:
394 raise faults.InvalidProductIdentifier(urlutils.escape(e.name))
395- except NoSuchProductSeries, e:
396- raise faults.NoSuchProductSeries(
397- urlutils.escape(e.name), e.product)
398 except NoSuchPerson, e:
399 raise faults.NoSuchPersonWithName(urlutils.escape(e.name))
400 except NoSuchProduct, e:
401 raise faults.NoSuchProduct(urlutils.escape(e.name))
402- except NoSuchDistroSeries, e:
403- raise faults.NoSuchDistroSeries(urlutils.escape(e.name))
404+ except NoSuchSeries, e:
405+ raise faults.NoSuchSeries(urlutils.escape(e.name))
406 except NoSuchSourcePackageName, e:
407 raise faults.NoSuchSourcePackageName(urlutils.escape(e.name))
408 except NoLinkedBranch, e:
409
410=== modified file 'lib/lp/code/xmlrpc/tests/test_branch.py'
411--- lib/lp/code/xmlrpc/tests/test_branch.py 2010-04-09 12:58:01 +0000
412+++ lib/lp/code/xmlrpc/tests/test_branch.py 2010-07-16 14:15:25 +0000
413@@ -192,35 +192,35 @@
414 faults.NoLinkedBranch(series))
415
416 def test_no_such_product_series(self):
417- # Return a NoSuchProductSeries fault if there is no series of the
418+ # Return a NoSuchSeries fault if there is no series of the
419 # given name associated with the product.
420 self.assertFault(
421 '%s/%s' % (self.product.name, "doesntexist"),
422- faults.NoSuchProductSeries("doesntexist", self.product))
423+ faults.NoSuchSeries("doesntexist"))
424
425 def test_no_such_product_series_non_ascii(self):
426- # lp:product/<non-ascii-string> returns NoSuchProductSeries with the
427+ # lp:product/<non-ascii-string> returns NoSuchSeries with the
428 # name escaped.
429 self.assertFault(
430 '%s/%s' % (self.product.name, NON_ASCII_NAME),
431- faults.NoSuchProductSeries(
432- urlutils.escape(NON_ASCII_NAME), self.product))
433+ faults.NoSuchSeries(
434+ urlutils.escape(NON_ASCII_NAME)))
435
436 def test_no_such_distro_series(self):
437- # Return a NoSuchDistroSeries fault if there is no series of the given
438+ # Return a NoSuchSeries fault if there is no series of the given
439 # name on that distribution.
440 distro = self.factory.makeDistribution()
441 self.assertFault(
442 '%s/doesntexist/whocares' % distro.name,
443- faults.NoSuchDistroSeries("doesntexist"))
444+ faults.NoSuchSeries("doesntexist"))
445
446 def test_no_such_distro_series_non_ascii(self):
447- # lp:distro/<non-ascii-string>/whatever returns NoSuchDistroSeries
448+ # lp:distro/<non-ascii-string>/whatever returns NoSuchSeries
449 # with the name escaped.
450 distro = self.factory.makeDistribution()
451 self.assertFault(
452 '%s/%s/whocares' % (distro.name, NON_ASCII_NAME),
453- faults.NoSuchDistroSeries(urlutils.escape(NON_ASCII_NAME)))
454+ faults.NoSuchSeries(urlutils.escape(NON_ASCII_NAME)))
455
456 def test_no_such_source_package(self):
457 # Return a NoSuchSourcePackageName fault if there is no source package
458
459=== modified file 'lib/lp/registry/interfaces/distroseries.py'
460--- lib/lp/registry/interfaces/distroseries.py 2010-06-08 15:58:04 +0000
461+++ lib/lp/registry/interfaces/distroseries.py 2010-07-16 14:15:25 +0000
462@@ -12,7 +12,6 @@
463 'IDistroSeriesEditRestricted',
464 'IDistroSeriesPublic',
465 'IDistroSeriesSet',
466- 'NoSuchDistroSeries',
467 ]
468
469 from zope.component import getUtility
470@@ -53,28 +52,6 @@
471 from lp.translations.interfaces.languagepack import ILanguagePack
472 from lp.translations.interfaces.potemplate import IHasTranslationTemplates
473
474-
475-class DistroSeriesNameField(ContentNameField):
476- """A class to ensure `IDistroSeries` has unique names."""
477- errormessage = _("%s is already in use by another series.")
478-
479- @property
480- def _content_iface(self):
481- """See `IField`."""
482- return IDistroSeries
483-
484- def _getByName(self, name):
485- """See `IField`."""
486- try:
487- if self._content_iface.providedBy(self.context):
488- return self.context.distribution.getSeries(name)
489- else:
490- return self.context.getSeries(name)
491- except NoSuchDistroSeries:
492- # The name is available for the new series.
493- return None
494-
495-
496 class DistroSeriesVersionField(UniqueField):
497 """A class to ensure `IDistroSeries` has unique versions."""
498 errormessage = _(
499@@ -147,11 +124,7 @@
500 """Public IDistroSeries properties."""
501
502 id = Attribute("The distroseries's unique number.")
503- name = exported(
504- DistroSeriesNameField(
505- title=_("Name"), required=True,
506- description=_("The name of this series."),
507- constraint=name_validator))
508+
509 displayname = exported(
510 TextLine(
511 title=_("Display name"), required=True,
512@@ -855,12 +828,5 @@
513 released == None will do no filtering on status.
514 """
515
516-
517-class NoSuchDistroSeries(NameLookupFailed):
518- """Raised when we try to find a DistroSeries that doesn't exist."""
519- webservice_error(400) #Bad request.
520- _message_prefix = "No such distribution series"
521-
522-
523 # Monkey patch for circular import avoidance done in
524 # _schema_circular_imports.py
525
526=== modified file 'lib/lp/registry/interfaces/productseries.py'
527--- lib/lp/registry/interfaces/productseries.py 2010-06-11 18:05:59 +0000
528+++ lib/lp/registry/interfaces/productseries.py 2010-07-16 14:15:25 +0000
529@@ -12,7 +12,6 @@
530 'IProductSeriesEditRestricted',
531 'IProductSeriesPublic',
532 'IProductSeriesSet',
533- 'NoSuchProductSeries',
534 ]
535
536 from zope.schema import Bool, Choice, Datetime, Int, TextLine
537@@ -51,23 +50,6 @@
538 rename_parameters_as)
539
540
541-class ProductSeriesNameField(ContentNameField):
542- """A class to ensure `IProductSeries` has unique names."""
543- errormessage = _("%s is already in use by another series.")
544-
545- @property
546- def _content_iface(self):
547- """See `IField`."""
548- return IProductSeries
549-
550- def _getByName(self, name):
551- """See `IField`."""
552- if self._content_iface.providedBy(self.context):
553- return self.context.product.getSeries(name)
554- else:
555- return self.context.getSeries(name)
556-
557-
558 def validate_release_glob(value):
559 """Validate that the URL is supported."""
560 parts = urlparse(value)
561@@ -112,16 +94,6 @@
562
563 parent = Attribute('The structural parent of this series - the product')
564
565- name = exported(
566- ProductSeriesNameField(
567- title=_('Name'),
568- description=_(
569- "The name of the series is a short, unique name "
570- "that identifies it, being used in URLs. It must be all "
571- "lowercase, with no special characters. For example, '2.0' "
572- "or 'trunk'."),
573- constraint=name_validator))
574-
575 datecreated = exported(
576 Datetime(title=_('Date Registered'),
577 required=True,
578@@ -318,13 +290,3 @@
579 :param force_translations_upload: Actually ignore if translations are
580 enabled for this series.
581 """
582-
583-
584-class NoSuchProductSeries(NameLookupFailed):
585- """Raised when we try to find a product that doesn't exist."""
586-
587- _message_prefix = "No such product series"
588-
589- def __init__(self, name, product, message=None):
590- NameLookupFailed.__init__(self, name, message)
591- self.product = product
592
593=== modified file 'lib/lp/registry/interfaces/series.py'
594--- lib/lp/registry/interfaces/series.py 2010-05-17 09:35:18 +0000
595+++ lib/lp/registry/interfaces/series.py 2010-07-16 14:15:25 +0000
596@@ -8,20 +8,23 @@
597 __metaclass__ = type
598
599 __all__ = [
600+ 'ISeriesMixin',
601+ 'NoSuchSeries',
602 'SeriesStatus',
603- 'ISeriesMixin',
604 ]
605
606 from zope.schema import Bool
607
608 from lazr.enum import DBEnumeratedType, DBItem
609 from lazr.restful.fields import CollectionField, Reference
610-from lazr.restful.declarations import exported
611+from lazr.restful.declarations import exported, webservice_error
612
613 from canonical.launchpad import _
614 from canonical.launchpad.fields import (
615- PublicPersonChoice, Summary)
616+ ContentNameField, PublicPersonChoice, Summary)
617 from canonical.launchpad.interfaces.launchpad import IHasDrivers
618+from canonical.launchpad.validators.name import name_validator
619+from canonical.launchpad.webapp.interfaces import NameLookupFailed
620 from lp.registry.interfaces.person import IPerson
621
622
623@@ -89,6 +92,33 @@
624 """)
625
626
627+class NoSuchSeries(NameLookupFailed):
628+ """Raised when we try to find a series that doesn't exist."""
629+ webservice_error(400) #Bad request.
630+ _message_prefix = "No such series"
631+
632+
633+class SeriesNameField(ContentNameField):
634+ """A class to ensure an series has an unique name."""
635+ errormessage = _("%s is already in use by another series.")
636+
637+ @property
638+ def _content_iface(self):
639+ """See `IField`."""
640+ return ISeriesMixin
641+
642+ def _getByName(self, name):
643+ """See `IField`."""
644+ try:
645+ if self._content_iface.providedBy(self.context):
646+ return self.context.parent.getSeries(name)
647+ else:
648+ return self.context.getSeries(name)
649+ except NoSuchSeries:
650+ # The name is available for the new series.
651+ return None
652+
653+
654 class ISeriesMixin(IHasDrivers):
655 """Methods & properties shared between distro & product series."""
656
657@@ -99,6 +129,16 @@
658 "under current development. This excludes series which "
659 "are experimental or obsolete.")))
660
661+ name = exported(
662+ SeriesNameField(
663+ title=_('Name'),
664+ description=_(
665+ "The name of the series is a short, unique name "
666+ "that identifies it, being used in URLs. It must be all "
667+ "lowercase, with no special characters. For example, '2.0', "
668+ "'hardy' or 'trunk'."),
669+ constraint=name_validator))
670+
671 summary = exported(
672 Summary(title=_("Summary"),
673 description=_('A single paragraph that explains the goals of '
674
675=== modified file 'lib/lp/registry/model/distribution.py'
676--- lib/lp/registry/model/distribution.py 2010-06-29 10:17:06 +0000
677+++ lib/lp/registry/model/distribution.py 2010-07-16 14:15:25 +0000
678@@ -90,7 +90,7 @@
679 from lp.registry.interfaces.distributionmirror import (
680 IDistributionMirror, MirrorContent, MirrorStatus)
681 from lp.registry.interfaces.series import SeriesStatus
682-from lp.registry.interfaces.distroseries import NoSuchDistroSeries
683+from lp.registry.interfaces.series import NoSuchSeries
684 from canonical.launchpad.interfaces.launchpad import (
685 IHasIcon, IHasLogo, IHasMugshot, ILaunchpadCelebrities, ILaunchpadUsage)
686 from lp.soyuz.interfaces.queue import PackageUploadStatus
687@@ -529,7 +529,7 @@
688 DistroSeries.version == name_or_version),
689 DistroSeries.distribution == self).one()
690 if not distroseries:
691- raise NoSuchDistroSeries(name_or_version)
692+ raise NoSuchSeries(name_or_version)
693 return distroseries
694
695 def getDevelopmentSeries(self):
696
697=== modified file 'lib/lp/registry/model/distroseries.py'
698--- lib/lp/registry/model/distroseries.py 2010-06-22 19:42:51 +0000
699+++ lib/lp/registry/model/distroseries.py 2010-07-16 14:15:25 +0000
700@@ -136,7 +136,6 @@
701
702 distribution = ForeignKey(
703 dbName='distribution', foreignKey='Distribution', notNull=True)
704- name = StringCol(notNull=True)
705 displayname = StringCol(notNull=True)
706 title = StringCol(notNull=True)
707 description = StringCol(notNull=True)
708
709=== modified file 'lib/lp/registry/model/productseries.py'
710--- lib/lp/registry/model/productseries.py 2010-06-09 08:26:26 +0000
711+++ lib/lp/registry/model/productseries.py 2010-07-16 14:15:25 +0000
712@@ -91,7 +91,6 @@
713 status = EnumCol(
714 notNull=True, schema=SeriesStatus,
715 default=SeriesStatus.DEVELOPMENT)
716- name = StringCol(notNull=True)
717 datecreated = UtcDateTimeCol(notNull=True, default=UTC_NOW)
718 owner = ForeignKey(
719 dbName="owner", foreignKey="Person",
720
721=== modified file 'lib/lp/registry/model/series.py'
722--- lib/lp/registry/model/series.py 2010-05-17 09:35:18 +0000
723+++ lib/lp/registry/model/series.py 2010-07-16 14:15:25 +0000
724@@ -22,6 +22,7 @@
725
726 implements(ISeriesMixin)
727
728+ name = StringCol(notNull=True)
729 summary = StringCol(notNull=True)
730
731 @property
732
733=== modified file 'lib/lp/registry/stories/webservice/xx-distribution.txt'
734--- lib/lp/registry/stories/webservice/xx-distribution.txt 2010-06-09 08:26:26 +0000
735+++ lib/lp/registry/stories/webservice/xx-distribution.txt 2010-07-16 14:15:25 +0000
736@@ -69,7 +69,7 @@
737 ... name_or_version='fnord')
738 HTTP/1.1 400 Bad Request
739 ...
740- NoSuchDistroSeries: No such distribution series: 'fnord'.
741+ NoSuchSeries: No such series: 'fnord'.
742
743 "getDevelopmentSeries" returns all the distribution series for the
744 distribution that are marked as in development.
745
746=== modified file 'lib/lp/registry/tests/test_distribution.py'
747--- lib/lp/registry/tests/test_distribution.py 2010-06-21 13:33:36 +0000
748+++ lib/lp/registry/tests/test_distribution.py 2010-07-16 14:15:25 +0000
749@@ -11,8 +11,7 @@
750
751 from lp.registry.tests.test_distroseries import (
752 TestDistroSeriesCurrentSourceReleases)
753-from lp.registry.interfaces.distroseries import NoSuchDistroSeries
754-from lp.registry.interfaces.series import SeriesStatus
755+from lp.registry.interfaces.series import NoSuchSeries, SeriesStatus
756 from lp.soyuz.interfaces.distributionsourcepackagerelease import (
757 IDistributionSourcePackageRelease)
758 from lp.testing import TestCaseWithFactory
759@@ -129,7 +128,7 @@
760
761 def test_get_none(self):
762 distro = self.factory.makeDistribution()
763- self.assertRaises(NoSuchDistroSeries, distro.getSeries, "astronomy")
764+ self.assertRaises(NoSuchSeries, distro.getSeries, "astronomy")
765
766 def test_get_by_name(self):
767 distro = self.factory.makeDistribution()
768
769=== modified file 'lib/lp/registry/tests/test_distroseries.py'
770--- lib/lp/registry/tests/test_distroseries.py 2010-06-23 23:23:28 +0000
771+++ lib/lp/registry/tests/test_distroseries.py 2010-07-16 14:15:25 +0000
772@@ -14,8 +14,8 @@
773
774 from canonical.launchpad.ftests import ANONYMOUS, login
775 from lp.soyuz.interfaces.archive import ArchivePurpose, IArchiveSet
776-from lp.registry.interfaces.distroseries import (
777- IDistroSeriesSet, NoSuchDistroSeries)
778+from lp.registry.interfaces.series import NoSuchSeries
779+from lp.registry.interfaces.distroseries import IDistroSeriesSet
780 from lp.registry.interfaces.pocket import PackagePublishingPocket
781 from lp.soyuz.interfaces.component import IComponentSet
782 from lp.soyuz.interfaces.distroseriessourcepackagerelease import (
783@@ -390,7 +390,7 @@
784 def test_fromSuite_no_such_series(self):
785 distribution = self.factory.makeDistribution()
786 self.assertRaises(
787- NoSuchDistroSeries,
788+ NoSuchSeries,
789 getUtility(IDistroSeriesSet).fromSuite,
790 distribution, 'doesntexist')
791