Merge lp:~adiroiban/launchpad/bug-531261 into lp:launchpad
- bug-531261
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Guilherme Salgado |
Approved revision: | no longer in the source branch. |
Merged at revision: | not available |
Proposed branch: | lp:~adiroiban/launchpad/bug-531261 |
Merge into: | lp:launchpad |
Diff against target: |
595 lines (+150/-152) 8 files modified
lib/lp/registry/interfaces/distroseries.py (+11/-39) lib/lp/registry/interfaces/productseries.py (+6/-41) lib/lp/registry/interfaces/series.py (+53/-1) lib/lp/registry/model/distroseries.py (+4/-38) lib/lp/registry/model/productseries.py (+7/-26) lib/lp/registry/model/series.py (+53/-0) lib/lp/registry/stories/webservice/xx-distroseries.txt (+1/-0) lib/lp/registry/stories/webservice/xx-project-registry.txt (+15/-7) |
To merge this branch: | bzr merge lp:~adiroiban/launchpad/bug-531261 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guilherme Salgado (community) | Approve | ||
Review via email: mp+20748@code.launchpad.net |
Commit message
Move ISeriesMixin to lp.registry.
Description of the change
= Bug 531261 =
Right now ISeriesMixin is located in lp.registry.
Since this Mixin should be used for DistroSeries and ProductSeries common attributes, we should move it to lp.registry.
We can also see what other attributes can be moved to ISeriesMixin
== Proposed fix ==
As a start, move summary, bug_supervisor, security_contact and drivers in the common interface and mixin.
The other related bugs can be found here:
https:/
== Pre-implementation notes ==
Curtis has added his comments in the report for bug 531261.
== Implementation details ==
I don't know how to fix pylint warning about lazr modules. Any hint is much appreciated.
== Tests ==
./bin/test -t series
== Demo and Q/A ==
Since this is only a cleanup, there is no new functionality to test.
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files:
lib/lp/
== Pylint notices ==
lib/lp/
22: [F0401] Unable to import 'lazr.enum' (No module named enum)
23: [F0401] Unable to import 'lazr.restful.
28: [F0401] Unable to import 'lazr.restful.
112: [E1002, DistroSeriesVer
423: [C0322, IDistroSeriesPu
description=_(
^
"Return items that are more recent than this timestamp."),
required=
status=Choice(
vocabulary=
title=
description
required=
archive=
schema=
title=
description
required=
pocket=Choice(
vocabulary=
title=
description
required=
custom_
vocabulary=
title=_("Custom Type"),
description
"type."),
required=
)
@operation_
@export_
def getPackageUploa
custom_type):
Guilherme Salgado (salgado) wrote : | # |
Adi Roiban (adiroiban) wrote : | # |
> Hi Adi,
>
> This is a nice refactoring; thanks for doing it.
>
> There's just one thing I noticed which was not mentioned in your cover
> letter: the IProductSeries interface has grown a 'active' attribute,
> thanks to ISeriesMixin. Since your branch doesn't add any code that
> uses that attribute, I don't see a reason for adding it, so I'd suggest
> moving it to IDistroSeries and the actual implementation to
> DistroSeries. Unless you do plan to use IProductSeries.
> somewhere?
>
In the current code from lp/devel 'active' is the only attribute of ISeriesMixin. I was thinking it was put there to be used in the future.
Adi Roiban (adiroiban) wrote : | # |
Hi, as you suggested, I moved „active” from ISeries to IDistroSeries.
Here is the latest diff:
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -164,6 +164,12 @@
+ active = exported(Bool(
+ title=_("Active"),
+ description=_(
+ "Whether or not this series is stable and supported, or "
+ "under current development. This excludes series which "
+ "are experimental or obsolete.")))
description = exported(
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -92,13 +92,6 @@
class ISeriesMixin(
"""Methods & properties shared between distro & product series."""
- active = exported(Bool(
- title=_("Active"),
- description=_(
- "Whether or not this series is stable and supported, or "
- "under current development. This excludes series which "
- "are experimental or obsolete.")))
-
summary = exported(
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -183,6 +183,15 @@
@property
+ def active(self):
+ return self.status in [
+ SeriesStatus.
+ SeriesStatus.
+ SeriesStatus.
+ SeriesStatus.
+ ]
+
+ @property
def named_version(
return '%s (%s)' % (self.displayname, self.version)
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -25,15 +25,6 @@
summary = StringCol(
@property
- def active(self):
- return self.status in [
- SeriesStatus.
- SeriesStatus.
- SeriesStatus.
- SeriesStatus.
- ]
-
- @property
def bug_supervisor(
"""See `ISeriesMixin`."""
return self.parent.
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -810,7 +810,6 @@
>>> babadoo_foobadoo = webservice.
Adi Roiban (adiroiban) wrote : | # |
This is a small diff that fixes a spurious test, as a few line below the test is using both display_name and name:
>>> for project in project_
... print "%s (%s)" % (project[
APTonCD (aptoncd)
Arch mirrors (arch-mirrors)
Bazaar (bazaar)
Bazaar (bzr)
Derby (derby)
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -500,7 +500,7 @@
>>> project_collection = webservice.
>>> project_entries = sorted(
- ... project_
+ ... project_
>>> len(project_
25
Guilherme Salgado (salgado) wrote : | # |
On Mon, 2010-03-08 at 10:13 +0000, Adi Roiban wrote:
> This is a small diff that fixes a spurious test, as a few line below the test is using both display_name and name:
>
> >>> for project in project_
> ... print "%s (%s)" % (project[
> APTonCD (aptoncd)
> Arch mirrors (arch-mirrors)
> Bazaar (bazaar)
> Bazaar (bzr)
> Derby (derby)
>
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -500,7 +500,7 @@
> >>> project_collection = webservice.
>
> >>> project_entries = sorted(
> - ... project_
> + ... project_
This line has more than 80 chars now, no? Can you break it between the
two args?
review approve
--
Guilherme Salgado <email address hidden>
Adi Roiban (adiroiban) wrote : | # |
I have fixed the long line + some other long lines in this file.
"./bin/test -m registry" has no errors on my system.
Do you have time to sent this branch for landing?
Many thanks!
Guilherme Salgado (salgado) wrote : | # |
Sure; I've just submitted it.
Guilherme Salgado (salgado) wrote : | # |
The test suite hanged on ec2, but there are a few failures: http://
Adi, can you run these tests locally and let me know if the pass or if you need to make any changes to have them passing again?
Adi Roiban (adiroiban) wrote : | # |
Hi,
There are no errors running buildd-
---------------
./bin/test -t test_programmin
These Windmill tests are randomly failing.
They also fail on my computer for the lp/devel branch.
They are AJAX action to modify product properties.
I have watch them using „./bin/test -D -t test_programmin
What should I do to move thinkgs forward?
Many thanks!
Guilherme Salgado (salgado) wrote : | # |
If the tests don't fail for you locally, I'll resubmit.
Adi Roiban (adiroiban) wrote : | # |
It looks like the buildd-slavescanner error was fixed:
http://
I merged with devel and fixed the conflict.
I don't know how to fix those randomly failing Windmill tests.
Adi Roiban (adiroiban) wrote : | # |
The active attribute for productseries is used in registry/
This was causing the failure of test_timeline_
This is really strange, since the product.py code was commited long time ago and test_timeline_graph is not failing on mainline.
Can you please try to run this test on your computer using this branch?
These are the test failing on ec2-test, but they are fine on my computer.
bin/test --layer=
Guilherme Salgado (salgado) wrote : | # |
They fail here too, and the reason why they're failing is that on this
branch I asked you to move the active attribute from SeriesMixin to
DistroSeries because it seemed to be used only there. That was wrong --
ProductSeries inherits from SeriesMixin and, as you noticed, we have
code that rely on ProductSeries.
I think the correct fix here is to move the 'active' property back to
SeriesMixin. After you do that you'll have to update one of the
webservice tests for ProductSeries because its webservice representation
will now contain an extra 'active' field.
Adi Roiban (adiroiban) wrote : | # |
Here is the diff for moving "active" back to SeriesMixin.
I have pushed these changes.
After pulling the changes, can you please try to run this test on you computer:
bin/test --layer=
Many thanks!
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -165,12 +165,6 @@
- active = exported(Bool(
- title=_("Active"),
- description=_(
- "Whether or not this series is stable and supported, or "
- "under current development. This excludes series which "
- "are experimental or obsolete.")))
description = exported(
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -92,6 +92,13 @@
class ISeriesMixin(
"""Methods & properties shared between distro & product series."""
+ active = exported(Bool(
+ title=_("Active"),
+ description=_(
+ "Whether or not this series is stable and supported, or "
+ "under current development. This excludes series which "
+ "are experimental or obsolete.")))
+
summary = exported(
@@ -110,7 +117,6 @@
-
bug_supervisor = CollectionField(
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -182,15 +182,6 @@
@property
- def active(self):
- return self.status in [
- SeriesStatus.
- SeriesStatus.
- SeriesStatus.
- SeriesStatus.
- ]
-
- @property
def named_version(
return '%s (%s)' % (self.displayname, self.version)
=== modified file 'lib/lp/
--- lib/lp/
+++ lib/lp/
@@ -25,6 +25,15 @@
summary = StringCol(
@property
+ def active(self):
+ return self.status in [
+ SeriesStatus.
+ SeriesStatus.
+ SeriesStatus.
+ ...
Preview Diff
1 | === modified file 'lib/lp/registry/interfaces/distroseries.py' |
2 | --- lib/lp/registry/interfaces/distroseries.py 2010-03-08 10:43:34 +0000 |
3 | +++ lib/lp/registry/interfaces/distroseries.py 2010-03-15 15:04:36 +0000 |
4 | @@ -12,7 +12,6 @@ |
5 | 'IDistroSeriesEditRestricted', |
6 | 'IDistroSeriesPublic', |
7 | 'IDistroSeriesSet', |
8 | - 'ISeriesMixin', |
9 | 'NoSuchDistroSeries', |
10 | ] |
11 | |
12 | @@ -30,10 +29,9 @@ |
13 | |
14 | from canonical.launchpad import _ |
15 | from canonical.launchpad.fields import ( |
16 | - ContentNameField, Description, PublicPersonChoice, Summary, Title, |
17 | + ContentNameField, Description, PublicPersonChoice, Title, |
18 | UniqueField) |
19 | -from canonical.launchpad.interfaces.launchpad import ( |
20 | - IHasAppointedDriver, IHasDrivers) |
21 | +from canonical.launchpad.interfaces.launchpad import IHasAppointedDriver |
22 | from canonical.launchpad.validators import LaunchpadValidationError |
23 | from canonical.launchpad.validators.email import email_validator |
24 | from canonical.launchpad.validators.name import name_validator |
25 | @@ -46,7 +44,7 @@ |
26 | IBugTarget, IHasBugs, IHasOfficialBugTags) |
27 | from lp.registry.interfaces.milestone import IHasMilestones, IMilestone |
28 | from lp.registry.interfaces.role import IHasOwner |
29 | -from lp.registry.interfaces.series import SeriesStatus |
30 | +from lp.registry.interfaces.series import ISeriesMixin, SeriesStatus |
31 | from lp.registry.interfaces.sourcepackage import ISourcePackage |
32 | from lp.registry.interfaces.structuralsubscription import ( |
33 | IStructuralSubscriptionTarget) |
34 | @@ -141,22 +139,10 @@ |
35 | """Create a new milestone for this DistroSeries.""" |
36 | |
37 | |
38 | -class ISeriesMixin(Interface): |
39 | - """Methods & properties shared between distro & product series.""" |
40 | - |
41 | - active = exported( |
42 | - Bool( |
43 | - title=_("Active"), |
44 | - description=_( |
45 | - "Whether or not this series is stable and supported, or " |
46 | - "under current development. This excludes series which " |
47 | - "are experimental or obsolete."))) |
48 | - |
49 | - |
50 | -class IDistroSeriesPublic(IHasAppointedDriver, IHasDrivers, IHasOwner, |
51 | - IBugTarget, ISpecificationGoal, IHasMilestones, |
52 | - IHasBuildRecords, ISeriesMixin, |
53 | - IHasOfficialBugTags): |
54 | +class IDistroSeriesPublic( |
55 | + ISeriesMixin, IHasAppointedDriver, IHasOwner, IBugTarget, |
56 | + ISpecificationGoal, IHasMilestones, IHasOfficialBugTags, |
57 | + IHasBuildRecords): |
58 | """Public IDistroSeries properties.""" |
59 | |
60 | id = Attribute("The distroseries's unique number.") |
61 | @@ -179,12 +165,6 @@ |
62 | description=_( |
63 | "The title of this series. It should be distinctive " |
64 | "and designed to look good at the top of a page."))) |
65 | - summary = exported( |
66 | - Summary(title=_("Summary"), required=True, |
67 | - description=_( |
68 | - "A brief summary of the highlights of this release. " |
69 | - "It should be no longer than a single paragraph, up " |
70 | - "to 200 words."))) |
71 | description = exported( |
72 | Description(title=_("Description"), required=True, |
73 | description=_("A detailed description of this series, with " |
74 | @@ -251,14 +231,6 @@ |
75 | nominatedarchindep = Attribute( |
76 | "DistroArchSeries designed to build architecture-independent " |
77 | "packages whithin this distroseries context.") |
78 | - drivers = Attribute( |
79 | - 'A list of the people or teams who are drivers for this series. ' |
80 | - 'This list is made up of any drivers or owners from this ' |
81 | - 'DistroSeries, and the Distribution to which it belong.') |
82 | - bug_supervisor = Attribute( |
83 | - 'Currently just a reference to the Distribution bug supervisor.') |
84 | - security_contact = Attribute( |
85 | - 'Currently just a reference to the Distribution security contact.') |
86 | messagecount = Attribute("The total number of translatable items in " |
87 | "this series.") |
88 | distroserieslanguages = Attribute("The set of dr-languages in this " |
89 | @@ -445,14 +417,14 @@ |
90 | """Return a list of packagings that are the most recently linked. |
91 | |
92 | At most five packages are returned of those most recently linked to an |
93 | - upstream. |
94 | - """ |
95 | + upstream. |
96 | + """ |
97 | |
98 | @operation_parameters( |
99 | created_since_date=Datetime( |
100 | title=_("Created Since Timestamp"), |
101 | - description=_("Return items that are more recent than this " |
102 | - "timestamp."), |
103 | + description=_( |
104 | + "Return items that are more recent than this timestamp."), |
105 | required=False), |
106 | status=Choice( |
107 | # Really PackageUploadCustomFormat, patched in |
108 | |
109 | === modified file 'lib/lp/registry/interfaces/productseries.py' |
110 | --- lib/lp/registry/interfaces/productseries.py 2010-02-03 12:09:42 +0000 |
111 | +++ lib/lp/registry/interfaces/productseries.py 2010-03-15 15:04:36 +0000 |
112 | @@ -19,19 +19,16 @@ |
113 | from zope.interface import Interface, Attribute |
114 | |
115 | from canonical.launchpad.fields import ( |
116 | - ContentNameField, NoneableDescription, ParticipatingPersonChoice, |
117 | - PublicPersonChoice, Title) |
118 | + ContentNameField, ParticipatingPersonChoice, Title) |
119 | from lp.registry.interfaces.structuralsubscription import ( |
120 | IStructuralSubscriptionTarget) |
121 | from lp.code.interfaces.branch import IBranch |
122 | from lp.bugs.interfaces.bugtarget import IBugTarget, IHasOfficialBugTags |
123 | -from lp.registry.interfaces.series import SeriesStatus |
124 | -from canonical.launchpad.interfaces.launchpad import ( |
125 | - IHasAppointedDriver, IHasDrivers) |
126 | +from lp.registry.interfaces.series import ISeriesMixin, SeriesStatus |
127 | +from canonical.launchpad.interfaces.launchpad import IHasAppointedDriver |
128 | from lp.registry.interfaces.role import IHasOwner |
129 | from lp.registry.interfaces.milestone import ( |
130 | IHasMilestones, IMilestone) |
131 | -from lp.registry.interfaces.person import IPerson |
132 | from lp.registry.interfaces.productrelease import IProductRelease |
133 | from lp.blueprints.interfaces.specificationtarget import ( |
134 | ISpecificationGoal) |
135 | @@ -92,9 +89,9 @@ |
136 | """Create a new milestone for this ProjectSeries.""" |
137 | |
138 | |
139 | -class IProductSeriesPublic(IHasAppointedDriver, IHasDrivers, IHasOwner, |
140 | - IBugTarget, ISpecificationGoal, IHasMilestones, |
141 | - IHasOfficialBugTags): |
142 | +class IProductSeriesPublic( |
143 | + ISeriesMixin, IHasAppointedDriver, IHasOwner, IBugTarget, |
144 | + ISpecificationGoal, IHasMilestones, IHasOfficialBugTags): |
145 | """Public IProductSeries properties.""" |
146 | # XXX Mark Shuttleworth 2004-10-14: Would like to get rid of id in |
147 | # interfaces, as soon as SQLobject allows using the object directly |
148 | @@ -158,15 +155,6 @@ |
149 | 'just returns the name.')), |
150 | exported_as='display_name') |
151 | |
152 | - summary = exported( |
153 | - NoneableDescription(title=_("Summary"), |
154 | - description=_('A single paragraph that explains the goals of ' |
155 | - 'of this series and the intended users. ' |
156 | - 'For example: "The 2.0 series of Apache ' |
157 | - 'represents the current stable series, ' |
158 | - 'and is recommended for all new deployments".'), |
159 | - required=True)) |
160 | - |
161 | releases = exported( |
162 | CollectionField( |
163 | title=_("An iterator over the releases in this " |
164 | @@ -201,28 +189,6 @@ |
165 | readonly=True, |
166 | value_type=Reference(schema=IMilestone))) |
167 | |
168 | - drivers = exported( |
169 | - CollectionField( |
170 | - title=_( |
171 | - 'A list of the people or teams who are drivers for this ' |
172 | - 'series. This list is made up of any drivers or owners ' |
173 | - 'from this project series, the project and if it exists, ' |
174 | - 'the relevant project group.'), |
175 | - readonly=True, |
176 | - value_type=Reference(schema=IPerson))) |
177 | - |
178 | - bug_supervisor = CollectionField( |
179 | - title=_('Currently just a reference to the project bug ' |
180 | - 'supervisor.'), |
181 | - readonly=True, |
182 | - value_type=Reference(schema=IPerson)) |
183 | - |
184 | - security_contact = PublicPersonChoice( |
185 | - title=_('Security Contact'), |
186 | - description=_('Currently just a reference to the project ' |
187 | - 'security contact.'), |
188 | - required=False, vocabulary='ValidPersonOrTeam') |
189 | - |
190 | branch = exported( |
191 | ReferenceChoice( |
192 | title=_('Branch'), |
193 | @@ -318,7 +284,6 @@ |
194 | export_as_webservice_entry('project_series') |
195 | |
196 | |
197 | - |
198 | class IProductSeriesSet(Interface): |
199 | """Interface representing the set of ProductSeries.""" |
200 | |
201 | |
202 | === modified file 'lib/lp/registry/interfaces/series.py' |
203 | --- lib/lp/registry/interfaces/series.py 2009-12-13 11:55:40 +0000 |
204 | +++ lib/lp/registry/interfaces/series.py 2010-03-15 15:04:36 +0000 |
205 | @@ -8,10 +8,22 @@ |
206 | __metaclass__ = type |
207 | |
208 | __all__ = [ |
209 | - 'SeriesStatus' |
210 | + 'SeriesStatus', |
211 | + 'ISeriesMixin', |
212 | ] |
213 | |
214 | +from zope.schema import Bool |
215 | + |
216 | from lazr.enum import DBEnumeratedType, DBItem |
217 | +from lazr.restful.fields import CollectionField, Reference |
218 | +from lazr.restful.declarations import exported |
219 | + |
220 | +from canonical.launchpad import _ |
221 | +from canonical.launchpad.fields import ( |
222 | + PublicPersonChoice, Summary) |
223 | +from canonical.launchpad.interfaces.launchpad import IHasDrivers |
224 | +from lp.registry.interfaces.person import IPerson |
225 | + |
226 | |
227 | class SeriesStatus(DBEnumeratedType): |
228 | """Distro/Product Series Status |
229 | @@ -76,3 +88,43 @@ |
230 | haven't started working yet. |
231 | """) |
232 | |
233 | + |
234 | +class ISeriesMixin(IHasDrivers): |
235 | + """Methods & properties shared between distro & product series.""" |
236 | + |
237 | + active = exported(Bool( |
238 | + title=_("Active"), |
239 | + description=_( |
240 | + "Whether or not this series is stable and supported, or " |
241 | + "under current development. This excludes series which " |
242 | + "are experimental or obsolete."))) |
243 | + |
244 | + summary = exported( |
245 | + Summary(title=_("Summary"), |
246 | + description=_('A single paragraph that explains the goals of ' |
247 | + 'of this series and the intended users. ' |
248 | + 'For example: "The 2.0 series of Apache ' |
249 | + 'represents the current stable series, ' |
250 | + 'and is recommended for all new deployments".'), |
251 | + required=True)) |
252 | + |
253 | + drivers = exported( |
254 | + CollectionField( |
255 | + title=_( |
256 | + 'A list of the people or teams who are drivers for this ' |
257 | + 'series. This list is made up of any drivers or owners ' |
258 | + 'from this series and the parent drivers.'), |
259 | + readonly=True, |
260 | + value_type=Reference(schema=IPerson))) |
261 | + |
262 | + bug_supervisor = CollectionField( |
263 | + title=_('Currently just a reference to the parent bug ' |
264 | + 'supervisor.'), |
265 | + readonly=True, |
266 | + value_type=Reference(schema=IPerson)) |
267 | + |
268 | + security_contact = PublicPersonChoice( |
269 | + title=_('Security Contact'), |
270 | + description=_('Currently just a reference to the parent ' |
271 | + 'security contact.'), |
272 | + required=False, vocabulary='ValidPersonOrTeam') |
273 | |
274 | === modified file 'lib/lp/registry/model/distroseries.py' |
275 | --- lib/lp/registry/model/distroseries.py 2010-03-08 10:43:34 +0000 |
276 | +++ lib/lp/registry/model/distroseries.py 2010-03-15 15:04:36 +0000 |
277 | @@ -10,7 +10,6 @@ |
278 | __all__ = [ |
279 | 'DistroSeries', |
280 | 'DistroSeriesSet', |
281 | - 'SeriesMixin', |
282 | ] |
283 | |
284 | import logging |
285 | @@ -87,8 +86,6 @@ |
286 | HasSpecificationsMixin, Specification) |
287 | from lp.translations.model.translationimportqueue import ( |
288 | HasTranslationImportsMixin) |
289 | -from lp.registry.model.structuralsubscription import ( |
290 | - StructuralSubscriptionTargetMixin) |
291 | from canonical.launchpad.helpers import shortlist |
292 | from lp.soyuz.interfaces.archive import ( |
293 | ALLOW_RELEASE_BUILDS, ArchivePurpose, IArchiveSet, MAIN_ARCHIVE_PURPOSES) |
294 | @@ -98,7 +95,10 @@ |
295 | IBinaryPackageName) |
296 | from lp.registry.interfaces.series import SeriesStatus |
297 | from lp.registry.interfaces.distroseries import ( |
298 | - IDistroSeries, IDistroSeriesSet, ISeriesMixin) |
299 | + IDistroSeries, IDistroSeriesSet) |
300 | +from lp.registry.model.series import SeriesMixin |
301 | +from lp.registry.model.structuralsubscription import ( |
302 | + StructuralSubscriptionTargetMixin) |
303 | from lp.translations.interfaces.languagepack import LanguagePackType |
304 | from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet |
305 | from lp.soyuz.interfaces.queue import PackageUploadStatus |
306 | @@ -123,20 +123,6 @@ |
307 | ISourcePackageFormatSelectionSet) |
308 | |
309 | |
310 | -class SeriesMixin: |
311 | - """See `ISeriesMixin`.""" |
312 | - implements(ISeriesMixin) |
313 | - |
314 | - @property |
315 | - def active(self): |
316 | - return self.status in [ |
317 | - SeriesStatus.DEVELOPMENT, |
318 | - SeriesStatus.FROZEN, |
319 | - SeriesStatus.CURRENT, |
320 | - SeriesStatus.SUPPORTED, |
321 | - ] |
322 | - |
323 | - |
324 | class DistroSeries(SQLBase, BugTargetBase, HasSpecificationsMixin, |
325 | HasTranslationImportsMixin, HasTranslationTemplatesMixin, |
326 | HasMilestonesMixin, SeriesMixin, |
327 | @@ -154,7 +140,6 @@ |
328 | name = StringCol(notNull=True) |
329 | displayname = StringCol(notNull=True) |
330 | title = StringCol(notNull=True) |
331 | - summary = StringCol(notNull=True) |
332 | description = StringCol(notNull=True) |
333 | version = StringCol(notNull=True) |
334 | status = EnumCol( |
335 | @@ -283,25 +268,6 @@ |
336 | return self.distribution |
337 | |
338 | @property |
339 | - def drivers(self): |
340 | - """See `IDistroSeries`.""" |
341 | - drivers = set() |
342 | - drivers.add(self.driver) |
343 | - drivers = drivers.union(self.distribution.drivers) |
344 | - drivers.discard(None) |
345 | - return sorted(drivers, key=lambda driver: driver.displayname) |
346 | - |
347 | - @property |
348 | - def bug_supervisor(self): |
349 | - """See `IDistroSeries`.""" |
350 | - return self.distribution.bug_supervisor |
351 | - |
352 | - @property |
353 | - def security_contact(self): |
354 | - """See `IDistroSeries`.""" |
355 | - return self.distribution.security_contact |
356 | - |
357 | - @property |
358 | def sortkey(self): |
359 | """A string to be used for sorting distro seriess. |
360 | |
361 | |
362 | === modified file 'lib/lp/registry/model/productseries.py' |
363 | --- lib/lp/registry/model/productseries.py 2010-03-05 23:59:18 +0000 |
364 | +++ lib/lp/registry/model/productseries.py 2010-03-15 15:04:36 +0000 |
365 | @@ -50,8 +50,6 @@ |
366 | from lp.registry.model.structuralsubscription import ( |
367 | StructuralSubscriptionTargetMixin) |
368 | from canonical.launchpad.helpers import shortlist |
369 | -from lp.registry.interfaces.series import SeriesStatus |
370 | -from lp.registry.model.distroseries import SeriesMixin |
371 | from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
372 | from lp.registry.interfaces.packaging import PackagingType |
373 | from lp.translations.interfaces.potemplate import IHasTranslationTemplates |
374 | @@ -60,10 +58,12 @@ |
375 | SpecificationGoalStatus, SpecificationImplementationStatus, |
376 | SpecificationSort) |
377 | from canonical.launchpad.webapp.interfaces import NotFoundError |
378 | +from lp.registry.interfaces.series import SeriesStatus |
379 | from lp.registry.interfaces.productseries import ( |
380 | IProductSeries, IProductSeriesSet) |
381 | from lp.translations.interfaces.translations import ( |
382 | TranslationsBranchImportMode) |
383 | +from lp.registry.model.series import SeriesMixin |
384 | from canonical.launchpad.webapp.publisher import canonical_url |
385 | from canonical.launchpad.webapp.sorting import sorted_dotted_numbers |
386 | |
387 | @@ -92,12 +92,12 @@ |
388 | notNull=True, schema=SeriesStatus, |
389 | default=SeriesStatus.DEVELOPMENT) |
390 | name = StringCol(notNull=True) |
391 | - summary = StringCol(notNull=True) |
392 | datecreated = UtcDateTimeCol(notNull=True, default=UTC_NOW) |
393 | owner = ForeignKey( |
394 | dbName="owner", foreignKey="Person", |
395 | storm_validator=validate_person_not_private_membership, |
396 | notNull=True) |
397 | + |
398 | driver = ForeignKey( |
399 | dbName="driver", foreignKey="Person", |
400 | storm_validator=validate_person_not_private_membership, |
401 | @@ -165,25 +165,6 @@ |
402 | """See `IHasBugs`.""" |
403 | return self.product.max_bug_heat |
404 | |
405 | - @property |
406 | - def drivers(self): |
407 | - """See IProductSeries.""" |
408 | - drivers = set() |
409 | - drivers.add(self.driver) |
410 | - drivers = drivers.union(self.product.drivers) |
411 | - drivers.discard(None) |
412 | - return sorted(drivers, key=lambda x: x.displayname) |
413 | - |
414 | - @property |
415 | - def bug_supervisor(self): |
416 | - """See IProductSeries.""" |
417 | - return self.product.bug_supervisor |
418 | - |
419 | - @property |
420 | - def security_contact(self): |
421 | - """See IProductSeries.""" |
422 | - return self.product.security_contact |
423 | - |
424 | def getPOTemplate(self, name): |
425 | """See IProductSeries.""" |
426 | return POTemplate.selectOne( |
427 | @@ -308,7 +289,7 @@ |
428 | |
429 | # filter based on completion. see the implementation of |
430 | # Specification.is_complete() for more details |
431 | - completeness = Specification.completeness_clause |
432 | + completeness = Specification.completeness_clause |
433 | |
434 | if SpecificationFilter.COMPLETE in filter: |
435 | query += ' AND ( %s ) ' % completeness |
436 | @@ -438,8 +419,8 @@ |
437 | |
438 | def getTranslationTemplates(self): |
439 | """See `IHasTranslationTemplates`.""" |
440 | - result = POTemplate.selectBy(productseries=self, |
441 | - orderBy=['-priority','name']) |
442 | + result = POTemplate.selectBy( |
443 | + productseries=self, orderBy=['-priority', 'name']) |
444 | return shortlist(result, 300) |
445 | |
446 | def getCurrentTranslationTemplates(self, just_ids=False): |
447 | @@ -472,7 +453,7 @@ |
448 | ProductSeries.product = Product.id AND |
449 | (iscurrent IS FALSE OR Product.official_rosetta IS FALSE) |
450 | ''' % sqlvalues(self), |
451 | - orderBy=['-priority','name'], |
452 | + orderBy=['-priority', 'name'], |
453 | clauseTables = ['ProductSeries', 'Product']) |
454 | return shortlist(result, 300) |
455 | |
456 | |
457 | === added file 'lib/lp/registry/model/series.py' |
458 | --- lib/lp/registry/model/series.py 1970-01-01 00:00:00 +0000 |
459 | +++ lib/lp/registry/model/series.py 2010-03-15 15:04:36 +0000 |
460 | @@ -0,0 +1,53 @@ |
461 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
462 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
463 | + |
464 | +"""Common implementations for a series.""" |
465 | + |
466 | +__metaclass__ = type |
467 | + |
468 | +__all__ = [ |
469 | + 'SeriesMixin', |
470 | + ] |
471 | + |
472 | +from operator import attrgetter |
473 | +from sqlobject import StringCol |
474 | + |
475 | +from zope.interface import implements |
476 | + |
477 | +from lp.registry.interfaces.series import ISeriesMixin, SeriesStatus |
478 | + |
479 | + |
480 | +class SeriesMixin: |
481 | + """See `ISeriesMixin`.""" |
482 | + |
483 | + implements(ISeriesMixin) |
484 | + |
485 | + summary = StringCol(notNull=True) |
486 | + |
487 | + @property |
488 | + def active(self): |
489 | + return self.status in [ |
490 | + SeriesStatus.DEVELOPMENT, |
491 | + SeriesStatus.FROZEN, |
492 | + SeriesStatus.CURRENT, |
493 | + SeriesStatus.SUPPORTED, |
494 | + ] |
495 | + |
496 | + @property |
497 | + def bug_supervisor(self): |
498 | + """See `ISeriesMixin`.""" |
499 | + return self.parent.bug_supervisor |
500 | + |
501 | + @property |
502 | + def security_contact(self): |
503 | + """See `ISeriesMixin`.""" |
504 | + return self.parent.security_contact |
505 | + |
506 | + @property |
507 | + def drivers(self): |
508 | + """See `ISeriesMixin`.""" |
509 | + drivers = set() |
510 | + drivers.add(self.driver) |
511 | + drivers = drivers.union(self.parent.drivers) |
512 | + drivers.discard(None) |
513 | + return sorted(drivers, key=attrgetter('displayname')) |
514 | |
515 | === modified file 'lib/lp/registry/stories/webservice/xx-distroseries.txt' |
516 | --- lib/lp/registry/stories/webservice/xx-distroseries.txt 2010-02-04 21:16:37 +0000 |
517 | +++ lib/lp/registry/stories/webservice/xx-distroseries.txt 2010-03-15 15:04:36 +0000 |
518 | @@ -68,6 +68,7 @@ |
519 | displayname: u'Hoary' |
520 | distribution_link: u'http://.../ubuntu' |
521 | driver_link: None |
522 | + drivers_collection_link: u'http://.../ubuntu/hoary/drivers' |
523 | fullseriesname: u'Ubuntu Hoary' |
524 | main_archive_link: u'http://.../ubuntu/+archive/primary' |
525 | name: u'hoary' |
526 | |
527 | === modified file 'lib/lp/registry/stories/webservice/xx-project-registry.txt' |
528 | --- lib/lp/registry/stories/webservice/xx-project-registry.txt 2010-02-04 21:18:35 +0000 |
529 | +++ lib/lp/registry/stories/webservice/xx-project-registry.txt 2010-03-15 15:04:36 +0000 |
530 | @@ -93,7 +93,8 @@ |
531 | active_milestones_collection_link and the |
532 | all_milestones_collection_link. |
533 | |
534 | - >>> response = webservice.get(mozilla['active_milestones_collection_link']) |
535 | + >>> response = webservice.get( |
536 | + ... mozilla['active_milestones_collection_link']) |
537 | >>> active_milestones = response.jsonBody() |
538 | >>> print_self_link_of_entries(active_milestones) |
539 | http://.../mozilla/+milestone/1.0 |
540 | @@ -233,7 +234,8 @@ |
541 | active_milestones_collection_link and the |
542 | all_milestones_collection_link. |
543 | |
544 | - >>> response = webservice.get(firefox['active_milestones_collection_link']) |
545 | + >>> response = webservice.get( |
546 | + ... firefox['active_milestones_collection_link']) |
547 | >>> active_milestones = response.jsonBody() |
548 | >>> print_self_link_of_entries(active_milestones) |
549 | http://.../firefox/+milestone/1.0 |
550 | @@ -360,11 +362,14 @@ |
551 | >>> # Create a product with a series and release. |
552 | >>> login('test@canonical.com') |
553 | >>> test_project_owner = factory.makePerson(name='test-project-owner') |
554 | - >>> test_project = factory.makeProduct(name='test-project', owner=test_project_owner) |
555 | + >>> test_project = factory.makeProduct( |
556 | + ... name='test-project', owner=test_project_owner) |
557 | >>> test_series = factory.makeProductSeries( |
558 | - ... product=test_project, name='test-series', owner=test_project_owner) |
559 | + ... product=test_project, name='test-series', |
560 | + ... owner=test_project_owner) |
561 | >>> test_milestone = factory.makeMilestone( |
562 | - ... product=test_project, name='test-milestone', productseries=test_series) |
563 | + ... product=test_project, name='test-milestone', |
564 | + ... productseries=test_series) |
565 | >>> test_project_release = factory.makeProductRelease( |
566 | ... product=test_project, milestone=test_milestone) |
567 | >>> logout() |
568 | @@ -500,7 +505,8 @@ |
569 | >>> project_collection = webservice.get("/projects?ws.size=75").jsonBody() |
570 | |
571 | >>> project_entries = sorted( |
572 | - ... project_collection['entries'], key=itemgetter('display_name')) |
573 | + ... project_collection['entries'], |
574 | + ... key=itemgetter('display_name','name')) |
575 | >>> len(project_entries) |
576 | 25 |
577 | |
578 | @@ -528,7 +534,8 @@ |
579 | If you don't specify "text" to the search a batched list of all the |
580 | projects is returned. |
581 | |
582 | - >>> project_collection = webservice.named_get("/projects", "search").jsonBody() |
583 | + >>> project_collection = webservice.named_get( |
584 | + ... "/projects", "search").jsonBody() |
585 | >>> len(project_collection['entries']) |
586 | 5 |
587 | |
588 | @@ -810,6 +817,7 @@ |
589 | |
590 | >>> babadoo_foobadoo = webservice.get('/babadoo/foobadoo').jsonBody() |
591 | >>> pprint_entry(babadoo_foobadoo) |
592 | + active: True |
593 | active_milestones_collection_link: u'http://.../babadoo/foobadoo/active_milestones' |
594 | all_milestones_collection_link: u'http://.../babadoo/foobadoo/all_milestones' |
595 | branch_link: u'http://.../~babadoo-owner/babadoo/fooey' |
Hi Adi,
This is a nice refactoring; thanks for doing it.
There's just one thing I noticed which was not mentioned in your cover active
letter: the IProductSeries interface has grown a 'active' attribute,
thanks to ISeriesMixin. Since your branch doesn't add any code that
uses that attribute, I don't see a reason for adding it, so I'd suggest
moving it to IDistroSeries and the actual implementation to
DistroSeries. Unless you do plan to use IProductSeries.
somewhere?
On Fri, 2010-03-05 at 13:51 +0000, Adi Roiban wrote:
> Adi Roiban has proposed merging lp:~adiroiban/launchpad/bug-531261
> into lp:launchpad/devel.
>
[...]
> == Implementation details ==
>
> I don't know how to fix pylint warning about lazr modules. Any hint is
> much appreciated.
These are spurious, but I don't know how to silence pylint,
unfortunately.
> registry/ interfaces/ distroseries. py registry/ interfaces/ distroseries. py declarations' (No fields' (No module sionField. _validate] Use super on an
> == Tests ==
> ./bin/test -t series
>
> == Demo and Q/A ==
>
> Since this is only a cleanup, there is no new functionality to test.
>
> = Launchpad lint =
>
> Checking for conflicts. and issues in doctests and templates.
> Running jslint, xmllint, pyflakes, and pylint.
> Using normal rules.
>
> Linting changed files:
> lib/lp/
>
>
> == Pylint notices ==
>
> lib/lp/
> 22: [F0401] Unable to import 'lazr.enum' (No module named enum)
> 23: [F0401] Unable to import 'lazr.restful.
> module named restful)
> 28: [F0401] Unable to import 'lazr.restful.
> named restful)
> 112: [E1002, DistroSeriesVer
> old style class
> === modified file 'lib/lp/ registry/ interfaces/ series. py' registry/ interfaces/ series. py 2009-12-13 11:55:40 +0000 registry/ interfaces/ series. py 2010-03-05 13:51:28 +0000 IHasDrivers) :
> --- lib/lp/
> +++ lib/lp/
> @@ -76,3 +88,45 @@
> haven't started working yet.
> """)
>
> +
> +class ISeriesMixin(
> + """Methods & properties shared between distro & product series."""
> +
> + active = exported(
> + Bool(
In this case, having the first argument on a line by itself doesn't buy
us much as it allows you to move only one char to the left, so better to
leave it on the same line as Bool.
> + title=_("Active"), title=_ ("Summary" ),
> + description=_(
> + "Whether or not this series is stable and supported, or "
> + "under current development. This excludes series which "
> + "are experimental or obsolete.")))
> +
> + summary = exported(
> + Summary(
> + description=_('A single paragraph that explains the goals of '
> + 'of this series and the intended users. '
> + 'For example: "The 2.0 series of Apache '
> + 'represents the current stable series, '
> + 'and is recommended for all new deployments".'),
> + required=True))
> +
> + drivers = exported(
> + CollectionField(
> + title=_(
> + 'A list of the people or teams who are drivers for this '
> + 'series. This l...