Merge ~cjwatson/launchpad:stormify-specification into launchpad:master
- Git
- lp:~cjwatson/launchpad
- stormify-specification
- Merge into master
Proposed by
Colin Watson
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | b5ffde7d61e04caea653e37d76b17541cab1994b |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:stormify-specification |
Merge into: | launchpad:master |
Diff against target: |
1114 lines (+288/-233) 24 files modified
lib/lp/blueprints/doc/specification.rst (+3/-3) lib/lp/blueprints/interfaces/specificationsubscription.py (+0/-1) lib/lp/blueprints/model/specification.py (+157/-139) lib/lp/blueprints/model/specificationdependency.py (+17/-10) lib/lp/blueprints/model/specificationmessage.py (+25/-11) lib/lp/blueprints/model/specificationsearch.py (+4/-4) lib/lp/blueprints/tests/test_specification.py (+1/-1) lib/lp/blueprints/tests/test_specification_access_policy_triggers.py (+8/-9) lib/lp/blueprints/vocabularies/specification.py (+3/-3) lib/lp/blueprints/vocabularies/specificationdependency.py (+13/-13) lib/lp/registry/browser/__init__.py (+3/-1) lib/lp/registry/doc/person-account.rst (+4/-1) lib/lp/registry/doc/productseries.rst (+16/-14) lib/lp/registry/model/distribution.py (+6/-2) lib/lp/registry/model/distroseries.py (+1/-1) lib/lp/registry/model/milestone.py (+5/-3) lib/lp/registry/model/person.py (+6/-6) lib/lp/registry/model/product.py (+6/-2) lib/lp/registry/model/productseries.py (+2/-2) lib/lp/registry/model/projectgroup.py (+2/-2) lib/lp/registry/services/sharingservice.py (+2/-2) lib/lp/registry/tests/test_person.py (+1/-1) lib/lp/registry/tests/test_sharingjob.py (+1/-0) lib/lp/scripts/harness.py (+2/-2) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrey Fedoseev (community) | Approve | ||
Review via email: mp+428840@code.launchpad.net |
Commit message
Convert remaining lp.blueprints models to Storm
Description of the change
This ports `Specification`, `SpecificationD
To post a comment you must log in.
Revision history for this message
Andrey Fedoseev (andrey-fedoseev) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/blueprints/doc/specification.rst b/lib/lp/blueprints/doc/specification.rst |
2 | index 47b6121..6c490cb 100644 |
3 | --- a/lib/lp/blueprints/doc/specification.rst |
4 | +++ b/lib/lp/blueprints/doc/specification.rst |
5 | @@ -320,13 +320,13 @@ If there are dependencies between the specs, the method returns a |
6 | mapping between them. |
7 | |
8 | >>> spec_a.createDependency(spec_b) |
9 | - <SpecificationDependency at ...> |
10 | + <...SpecificationDependency object at ...> |
11 | |
12 | >>> spec_a.createDependency(spec_c) |
13 | - <SpecificationDependency at ...> |
14 | + <...SpecificationDependency object at ...> |
15 | |
16 | >>> spec_c.createDependency(spec_d) |
17 | - <SpecificationDependency at ...> |
18 | + <...SpecificationDependency object at ...> |
19 | |
20 | >>> deps_dict = specset.getDependencyDict( |
21 | ... [spec_a, spec_b, spec_c, spec_d]) |
22 | diff --git a/lib/lp/blueprints/interfaces/specificationsubscription.py b/lib/lp/blueprints/interfaces/specificationsubscription.py |
23 | index c727957..eef862e 100644 |
24 | --- a/lib/lp/blueprints/interfaces/specificationsubscription.py |
25 | +++ b/lib/lp/blueprints/interfaces/specificationsubscription.py |
26 | @@ -38,7 +38,6 @@ class ISpecificationSubscription(Interface): |
27 | ) |
28 | personID = Attribute("db person value") |
29 | specification = Int(title=_("Specification"), required=True, readonly=True) |
30 | - specificationID = Attribute("db specification value") |
31 | essential = Bool( |
32 | title=_("Participation essential"), |
33 | required=True, |
34 | diff --git a/lib/lp/blueprints/model/specification.py b/lib/lp/blueprints/model/specification.py |
35 | index 707d397..cffe3d2 100644 |
36 | --- a/lib/lp/blueprints/model/specification.py |
37 | +++ b/lib/lp/blueprints/model/specification.py |
38 | @@ -12,9 +12,23 @@ __all__ = [ |
39 | |
40 | import operator |
41 | |
42 | +import pytz |
43 | from lazr.lifecycle.event import ObjectCreatedEvent |
44 | from lazr.lifecycle.objectdelta import ObjectDelta |
45 | -from storm.locals import SQL, Count, Desc, Join, Or, ReferenceSet, Store |
46 | +from storm.locals import ( |
47 | + SQL, |
48 | + Bool, |
49 | + Count, |
50 | + DateTime, |
51 | + Desc, |
52 | + Int, |
53 | + Join, |
54 | + Or, |
55 | + Reference, |
56 | + ReferenceSet, |
57 | + Store, |
58 | + Unicode, |
59 | +) |
60 | from zope.component import getUtility |
61 | from zope.event import notify |
62 | from zope.interface import implementer |
63 | @@ -71,22 +85,13 @@ from lp.registry.interfaces.productseries import IProductSeries |
64 | from lp.registry.model.milestone import Milestone |
65 | from lp.services.database import bulk |
66 | from lp.services.database.constants import DEFAULT, UTC_NOW |
67 | -from lp.services.database.datetimecol import UtcDateTimeCol |
68 | from lp.services.database.enumcol import DBEnum |
69 | from lp.services.database.interfaces import IStore |
70 | from lp.services.database.sqlbase import ( |
71 | - SQLBase, |
72 | convert_storm_clause_to_string, |
73 | sqlvalues, |
74 | ) |
75 | -from lp.services.database.sqlobject import ( |
76 | - BoolCol, |
77 | - ForeignKey, |
78 | - IntCol, |
79 | - SQLMultipleJoin, |
80 | - SQLRelatedJoin, |
81 | - StringCol, |
82 | -) |
83 | +from lp.services.database.stormbase import StormBase |
84 | from lp.services.mail.helpers import get_contact_email_addresses |
85 | from lp.services.propertycache import cachedproperty, get_property_cache |
86 | from lp.services.webapp.interfaces import ILaunchBag |
87 | @@ -160,15 +165,17 @@ SPECIFICATION_POLICY_DEFAULT_TYPES = { |
88 | |
89 | |
90 | @implementer(ISpecification, IBugLinkTarget, IInformationType) |
91 | -class Specification(SQLBase, BugLinkTargetMixin, InformationTypeMixin): |
92 | +class Specification(StormBase, BugLinkTargetMixin, InformationTypeMixin): |
93 | """See ISpecification.""" |
94 | |
95 | - _defaultOrder = ["-priority", "definition_status", "name", "id"] |
96 | + __storm_table__ = "Specification" |
97 | + __storm_order__ = ("-priority", "definition_status", "name", "id") |
98 | |
99 | # db field names |
100 | - name = StringCol(unique=True, notNull=True) |
101 | - title = StringCol(notNull=True) |
102 | - summary = StringCol(notNull=True) |
103 | + id = Int(primary=True) |
104 | + name = Unicode(allow_none=False) |
105 | + title = Unicode(allow_none=False) |
106 | + summary = Unicode(allow_none=False) |
107 | definition_status = DBEnum( |
108 | enum=SpecificationDefinitionStatus, |
109 | allow_none=False, |
110 | @@ -179,110 +186,94 @@ class Specification(SQLBase, BugLinkTargetMixin, InformationTypeMixin): |
111 | allow_none=False, |
112 | default=SpecificationPriority.UNDEFINED, |
113 | ) |
114 | - _assignee = ForeignKey( |
115 | - dbName="assignee", |
116 | - notNull=False, |
117 | - foreignKey="Person", |
118 | - storm_validator=validate_public_person, |
119 | - default=None, |
120 | - ) |
121 | - _drafter = ForeignKey( |
122 | - dbName="drafter", |
123 | - notNull=False, |
124 | - foreignKey="Person", |
125 | - storm_validator=validate_public_person, |
126 | - default=None, |
127 | - ) |
128 | - _approver = ForeignKey( |
129 | - dbName="approver", |
130 | - notNull=False, |
131 | - foreignKey="Person", |
132 | - storm_validator=validate_public_person, |
133 | + _assignee_id = Int( |
134 | + name="assignee", |
135 | + allow_none=True, |
136 | + validator=validate_public_person, |
137 | default=None, |
138 | ) |
139 | - owner = ForeignKey( |
140 | - dbName="owner", |
141 | - foreignKey="Person", |
142 | - storm_validator=validate_public_person, |
143 | - notNull=True, |
144 | - ) |
145 | - datecreated = UtcDateTimeCol(notNull=True, default=DEFAULT) |
146 | - product = ForeignKey( |
147 | - dbName="product", foreignKey="Product", notNull=False, default=None |
148 | - ) |
149 | - productseries = ForeignKey( |
150 | - dbName="productseries", |
151 | - foreignKey="ProductSeries", |
152 | - notNull=False, |
153 | + _assignee = Reference(_assignee_id, "Person.id") |
154 | + _drafter_id = Int( |
155 | + name="drafter", |
156 | + allow_none=True, |
157 | + validator=validate_public_person, |
158 | default=None, |
159 | ) |
160 | - distribution = ForeignKey( |
161 | - dbName="distribution", |
162 | - foreignKey="Distribution", |
163 | - notNull=False, |
164 | + _drafter = Reference(_drafter_id, "Person.id") |
165 | + _approver_id = Int( |
166 | + name="approver", |
167 | + allow_none=True, |
168 | + validator=validate_public_person, |
169 | default=None, |
170 | ) |
171 | - distroseries = ForeignKey( |
172 | - dbName="distroseries", |
173 | - foreignKey="DistroSeries", |
174 | - notNull=False, |
175 | - default=None, |
176 | + _approver = Reference(_approver_id, "Person.id") |
177 | + owner_id = Int( |
178 | + name="owner", validator=validate_public_person, allow_none=False |
179 | ) |
180 | + owner = Reference(owner_id, "Person.id") |
181 | + datecreated = DateTime(allow_none=False, default=DEFAULT, tzinfo=pytz.UTC) |
182 | + product_id = Int(name="product", allow_none=True, default=None) |
183 | + product = Reference(product_id, "Product.id") |
184 | + productseries_id = Int(name="productseries", allow_none=True, default=None) |
185 | + productseries = Reference(productseries_id, "ProductSeries.id") |
186 | + distribution_id = Int(name="distribution", allow_none=True, default=None) |
187 | + distribution = Reference(distribution_id, "Distribution.id") |
188 | + distroseries_id = Int(name="distroseries", allow_none=True, default=None) |
189 | + distroseries = Reference(distroseries_id, "DistroSeries.id") |
190 | goalstatus = DBEnum( |
191 | enum=SpecificationGoalStatus, |
192 | allow_none=False, |
193 | default=SpecificationGoalStatus.PROPOSED, |
194 | ) |
195 | - goal_proposer = ForeignKey( |
196 | - dbName="goal_proposer", |
197 | - notNull=False, |
198 | - foreignKey="Person", |
199 | - storm_validator=validate_public_person, |
200 | + goal_proposer_id = Int( |
201 | + name="goal_proposer", |
202 | + allow_none=True, |
203 | + validator=validate_public_person, |
204 | default=None, |
205 | ) |
206 | - date_goal_proposed = UtcDateTimeCol(notNull=False, default=None) |
207 | - goal_decider = ForeignKey( |
208 | - dbName="goal_decider", |
209 | - notNull=False, |
210 | - foreignKey="Person", |
211 | - storm_validator=validate_public_person, |
212 | + goal_proposer = Reference(goal_proposer_id, "Person.id") |
213 | + date_goal_proposed = DateTime( |
214 | + allow_none=True, default=None, tzinfo=pytz.UTC |
215 | + ) |
216 | + goal_decider_id = Int( |
217 | + name="goal_decider", |
218 | + allow_none=True, |
219 | + validator=validate_public_person, |
220 | default=None, |
221 | ) |
222 | - date_goal_decided = UtcDateTimeCol(notNull=False, default=None) |
223 | - milestone = ForeignKey( |
224 | - dbName="milestone", foreignKey="Milestone", notNull=False, default=None |
225 | + goal_decider = Reference(goal_decider_id, "Person.id") |
226 | + date_goal_decided = DateTime( |
227 | + allow_none=True, default=None, tzinfo=pytz.UTC |
228 | ) |
229 | - specurl = StringCol(notNull=False, default=None) |
230 | - whiteboard = StringCol(notNull=False, default=None) |
231 | - direction_approved = BoolCol(notNull=True, default=False) |
232 | - man_days = IntCol(notNull=False, default=None) |
233 | + milestone_id = Int(name="milestone", allow_none=True, default=None) |
234 | + milestone = Reference(milestone_id, "Milestone.id") |
235 | + specurl = Unicode(allow_none=True, default=None) |
236 | + whiteboard = Unicode(allow_none=True, default=None) |
237 | + direction_approved = Bool(allow_none=False, default=False) |
238 | + man_days = Int(allow_none=True, default=None) |
239 | implementation_status = DBEnum( |
240 | enum=SpecificationImplementationStatus, |
241 | allow_none=False, |
242 | default=SpecificationImplementationStatus.UNKNOWN, |
243 | ) |
244 | - superseded_by = ForeignKey( |
245 | - dbName="superseded_by", |
246 | - foreignKey="Specification", |
247 | - notNull=False, |
248 | - default=None, |
249 | - ) |
250 | - completer = ForeignKey( |
251 | - dbName="completer", |
252 | - notNull=False, |
253 | - foreignKey="Person", |
254 | - storm_validator=validate_public_person, |
255 | + superseded_by_id = Int(name="superseded_by", allow_none=True, default=None) |
256 | + superseded_by = Reference(superseded_by_id, "Specification.id") |
257 | + completer_id = Int( |
258 | + name="completer", |
259 | + allow_none=True, |
260 | + validator=validate_public_person, |
261 | default=None, |
262 | ) |
263 | - date_completed = UtcDateTimeCol(notNull=False, default=None) |
264 | - starter = ForeignKey( |
265 | - dbName="starter", |
266 | - notNull=False, |
267 | - foreignKey="Person", |
268 | - storm_validator=validate_public_person, |
269 | + completer = Reference(completer_id, "Person.id") |
270 | + date_completed = DateTime(allow_none=True, default=None, tzinfo=pytz.UTC) |
271 | + starter_id = Int( |
272 | + name="starter", |
273 | + allow_none=True, |
274 | + validator=validate_public_person, |
275 | default=None, |
276 | ) |
277 | - date_started = UtcDateTimeCol(notNull=False, default=None) |
278 | + starter = Reference(starter_id, "Person.id") |
279 | + date_started = DateTime(allow_none=True, default=None, tzinfo=pytz.UTC) |
280 | |
281 | # useful joins |
282 | _subscriptions = ReferenceSet( |
283 | @@ -298,32 +289,59 @@ class Specification(SQLBase, BugLinkTargetMixin, InformationTypeMixin): |
284 | order_by=("Person.display_name", "Person.name"), |
285 | ) |
286 | sprint_links = ReferenceSet( |
287 | - "<primary key>", |
288 | + "id", |
289 | "SprintSpecification.specification_id", |
290 | order_by="SprintSpecification.id", |
291 | ) |
292 | sprints = ReferenceSet( |
293 | - "<primary key>", |
294 | + "id", |
295 | "SprintSpecification.specification_id", |
296 | "SprintSpecification.sprint_id", |
297 | "Sprint.id", |
298 | order_by="Sprint.name", |
299 | ) |
300 | - spec_dependency_links = SQLMultipleJoin( |
301 | - "SpecificationDependency", joinColumn="specification", orderBy="id" |
302 | + spec_dependency_links = ReferenceSet( |
303 | + "id", |
304 | + "SpecificationDependency.specification_id", |
305 | + order_by="SpecificationDependency.id", |
306 | ) |
307 | |
308 | - dependencies = SQLRelatedJoin( |
309 | - "Specification", |
310 | - joinColumn="specification", |
311 | - otherColumn="dependency", |
312 | - orderBy="title", |
313 | - intermediateTable="SpecificationDependency", |
314 | + dependencies = ReferenceSet( |
315 | + "id", |
316 | + "SpecificationDependency.specification_id", |
317 | + "SpecificationDependency.dependency_id", |
318 | + "Specification.id", |
319 | + order_by="Specification.title", |
320 | ) |
321 | information_type = DBEnum( |
322 | enum=InformationType, allow_none=False, default=InformationType.PUBLIC |
323 | ) |
324 | |
325 | + def __init__( |
326 | + self, |
327 | + name, |
328 | + title, |
329 | + summary, |
330 | + owner, |
331 | + definition_status=DEFAULT, |
332 | + assignee=None, |
333 | + drafter=None, |
334 | + approver=None, |
335 | + specurl=None, |
336 | + whiteboard=None, |
337 | + ): |
338 | + super().__init__() |
339 | + self.name = name |
340 | + self.title = title |
341 | + self.summary = summary |
342 | + self.owner = owner |
343 | + self.definition_status = definition_status |
344 | + self._assignee = assignee |
345 | + self._drafter = drafter |
346 | + self._approver = approver |
347 | + self.specurl = specurl |
348 | + self.whiteboard = whiteboard |
349 | + |
350 | @cachedproperty |
351 | def linked_branches(self): |
352 | return list( |
353 | @@ -355,44 +373,44 @@ class Specification(SQLBase, BugLinkTargetMixin, InformationTypeMixin): |
354 | |
355 | def getDependencies(self, user=None): |
356 | return self._fetch_children_or_parents( |
357 | - SpecificationDependency.specificationID, |
358 | - SpecificationDependency.dependencyID, |
359 | + SpecificationDependency.specification_id, |
360 | + SpecificationDependency.dependency_id, |
361 | user, |
362 | ) |
363 | |
364 | def getBlockedSpecs(self, user=None): |
365 | return self._fetch_children_or_parents( |
366 | - SpecificationDependency.dependencyID, |
367 | - SpecificationDependency.specificationID, |
368 | + SpecificationDependency.dependency_id, |
369 | + SpecificationDependency.specification_id, |
370 | user, |
371 | ) |
372 | |
373 | - def set_assignee(self, person): |
374 | - self.subscribeIfAccessGrantNeeded(person) |
375 | - self._assignee = person |
376 | - |
377 | - def get_assignee(self): |
378 | + @property |
379 | + def assignee(self): |
380 | return self._assignee |
381 | |
382 | - assignee = property(get_assignee, set_assignee) |
383 | - |
384 | - def set_drafter(self, person): |
385 | + @assignee.setter |
386 | + def assignee(self, person): |
387 | self.subscribeIfAccessGrantNeeded(person) |
388 | - self._drafter = person |
389 | + self._assignee = person |
390 | |
391 | - def get_drafter(self): |
392 | + @property |
393 | + def drafter(self): |
394 | return self._drafter |
395 | |
396 | - drafter = property(get_drafter, set_drafter) |
397 | - |
398 | - def set_approver(self, person): |
399 | + @drafter.setter |
400 | + def drafter(self, person): |
401 | self.subscribeIfAccessGrantNeeded(person) |
402 | - self._approver = person |
403 | + self._drafter = person |
404 | |
405 | - def get_approver(self): |
406 | + @property |
407 | + def approver(self): |
408 | return self._approver |
409 | |
410 | - approver = property(get_approver, set_approver) |
411 | + @approver.setter |
412 | + def approver(self, person): |
413 | + self.subscribeIfAccessGrantNeeded(person) |
414 | + self._approver = person |
415 | |
416 | def subscribeIfAccessGrantNeeded(self, person): |
417 | """Subscribe person if this specification is not public and if |
418 | @@ -777,22 +795,22 @@ class Specification(SQLBase, BugLinkTargetMixin, InformationTypeMixin): |
419 | """See ISpecification.""" |
420 | newstatus = None |
421 | if self.is_started: |
422 | - if self.starterID is None: |
423 | + if self.starter_id is None: |
424 | newstatus = SpecificationLifecycleStatus.STARTED |
425 | self.date_started = UTC_NOW |
426 | self.starter = user |
427 | else: |
428 | - if self.starterID is not None: |
429 | + if self.starter_id is not None: |
430 | newstatus = SpecificationLifecycleStatus.NOTSTARTED |
431 | self.date_started = None |
432 | self.starter = None |
433 | if self.is_complete: |
434 | - if self.completerID is None: |
435 | + if self.completer_id is None: |
436 | newstatus = SpecificationLifecycleStatus.COMPLETE |
437 | self.date_completed = UTC_NOW |
438 | self.completer = user |
439 | else: |
440 | - if self.completerID is not None: |
441 | + if self.completer_id is not None: |
442 | self.date_completed = None |
443 | self.completer = None |
444 | if self.is_started: |
445 | @@ -1025,8 +1043,8 @@ class Specification(SQLBase, BugLinkTargetMixin, InformationTypeMixin): |
446 | # see if a relevant dependency link exists, and if so, delete it |
447 | for deplink in self.spec_dependency_links: |
448 | if deplink.dependency.id == specification.id: |
449 | - SpecificationDependency.delete(deplink.id) |
450 | - return deplink |
451 | + Store.of(deplink).remove(deplink) |
452 | + return |
453 | |
454 | def all_deps(self, user=None): |
455 | return list( |
456 | @@ -1253,7 +1271,7 @@ class SpecificationSet(HasSpecificationsMixin): |
457 | (Specification.implementation_status, Count()), |
458 | Or( |
459 | Specification.productseries == product_series, |
460 | - Specification.milestoneID.is_in( |
461 | + Specification.milestone_id.is_in( |
462 | list( |
463 | product_series.all_milestones.values(Milestone.id) |
464 | ) |
465 | @@ -1291,15 +1309,15 @@ class SpecificationSet(HasSpecificationsMixin): |
466 | |
467 | def getByURL(self, url): |
468 | """See ISpecificationSet.""" |
469 | - return Specification.selectOneBy(specurl=url) |
470 | + return IStore(Specification).find(Specification, specurl=url).one() |
471 | |
472 | def getByName(self, pillar, name): |
473 | """See ISpecificationSet.""" |
474 | clauses = [Specification.name == name] |
475 | if IDistribution.providedBy(pillar): |
476 | - clauses.append(Specification.distributionID == pillar.id) |
477 | + clauses.append(Specification.distribution == pillar) |
478 | elif IProduct.providedBy(pillar): |
479 | - clauses.append(Specification.productID == pillar.id) |
480 | + clauses.append(Specification.product == pillar) |
481 | return IStore(Specification).find(Specification, *clauses).one() |
482 | |
483 | @property |
484 | @@ -1349,9 +1367,9 @@ class SpecificationSet(HasSpecificationsMixin): |
485 | summary=summary, |
486 | definition_status=definition_status, |
487 | owner=owner, |
488 | - _approver=approver, |
489 | - _assignee=assignee, |
490 | - _drafter=drafter, |
491 | + approver=approver, |
492 | + assignee=assignee, |
493 | + drafter=drafter, |
494 | whiteboard=whiteboard, |
495 | ) |
496 | spec.setTarget(target) |
497 | @@ -1386,14 +1404,14 @@ class SpecificationSet(HasSpecificationsMixin): |
498 | for spec_id, dep_id in results: |
499 | if spec_id not in dependencies: |
500 | dependencies[spec_id] = [] |
501 | - dependency = Specification.get(dep_id) |
502 | + dependency = IStore(Specification).get(Specification, dep_id) |
503 | dependencies[spec_id].append(dependency) |
504 | |
505 | return dependencies |
506 | |
507 | def get(self, spec_id): |
508 | """See lp.blueprints.interfaces.specification.ISpecificationSet.""" |
509 | - return Specification.get(spec_id) |
510 | + return IStore(Specification).get(Specification, spec_id) |
511 | |
512 | def empty_list(self): |
513 | """See `ISpecificationSet`.""" |
514 | diff --git a/lib/lp/blueprints/model/specificationdependency.py b/lib/lp/blueprints/model/specificationdependency.py |
515 | index 365b4be..0a90436 100644 |
516 | --- a/lib/lp/blueprints/model/specificationdependency.py |
517 | +++ b/lib/lp/blueprints/model/specificationdependency.py |
518 | @@ -3,23 +3,30 @@ |
519 | |
520 | __all__ = ["SpecificationDependency"] |
521 | |
522 | +from storm.locals import Int, Reference |
523 | from zope.interface import implementer |
524 | |
525 | from lp.blueprints.interfaces.specificationdependency import ( |
526 | ISpecificationDependency, |
527 | ) |
528 | -from lp.services.database.sqlbase import SQLBase |
529 | -from lp.services.database.sqlobject import ForeignKey |
530 | +from lp.services.database.stormbase import StormBase |
531 | |
532 | |
533 | @implementer(ISpecificationDependency) |
534 | -class SpecificationDependency(SQLBase): |
535 | +class SpecificationDependency(StormBase): |
536 | """A link between a spec and a bug.""" |
537 | |
538 | - _table = "SpecificationDependency" |
539 | - specification = ForeignKey( |
540 | - dbName="specification", foreignKey="Specification", notNull=True |
541 | - ) |
542 | - dependency = ForeignKey( |
543 | - dbName="dependency", foreignKey="Specification", notNull=True |
544 | - ) |
545 | + __storm_table__ = "SpecificationDependency" |
546 | + |
547 | + id = Int(primary=True) |
548 | + |
549 | + specification_id = Int(name="specification", allow_none=False) |
550 | + specification = Reference(specification_id, "Specification.id") |
551 | + |
552 | + dependency_id = Int(name="dependency", allow_none=False) |
553 | + dependency = Reference(dependency_id, "Specification.id") |
554 | + |
555 | + def __init__(self, specification, dependency): |
556 | + super().__init__() |
557 | + self.specification = specification |
558 | + self.dependency = dependency |
559 | diff --git a/lib/lp/blueprints/model/specificationmessage.py b/lib/lp/blueprints/model/specificationmessage.py |
560 | index 6edb0e7..3603a9e 100644 |
561 | --- a/lib/lp/blueprints/model/specificationmessage.py |
562 | +++ b/lib/lp/blueprints/model/specificationmessage.py |
563 | @@ -5,28 +5,38 @@ __all__ = ["SpecificationMessage", "SpecificationMessageSet"] |
564 | |
565 | from email.utils import make_msgid |
566 | |
567 | +from storm.locals import Bool, Int, Reference |
568 | from zope.interface import implementer |
569 | |
570 | from lp.blueprints.interfaces.specificationmessage import ( |
571 | ISpecificationMessage, |
572 | ISpecificationMessageSet, |
573 | ) |
574 | -from lp.services.database.sqlbase import SQLBase |
575 | -from lp.services.database.sqlobject import BoolCol, ForeignKey |
576 | +from lp.services.database.interfaces import IStore |
577 | +from lp.services.database.stormbase import StormBase |
578 | from lp.services.messages.model.message import Message, MessageChunk |
579 | |
580 | |
581 | @implementer(ISpecificationMessage) |
582 | -class SpecificationMessage(SQLBase): |
583 | +class SpecificationMessage(StormBase): |
584 | """A table linking specifications and messages.""" |
585 | |
586 | - _table = "SpecificationMessage" |
587 | + __storm_table__ = "SpecificationMessage" |
588 | |
589 | - specification = ForeignKey( |
590 | - dbName="specification", foreignKey="Specification", notNull=True |
591 | - ) |
592 | - message = ForeignKey(dbName="message", foreignKey="Message", notNull=True) |
593 | - visible = BoolCol(notNull=True, default=True) |
594 | + id = Int(primary=True) |
595 | + |
596 | + specification_id = Int(name="specification", allow_none=False) |
597 | + specification = Reference(specification_id, "Specification.id") |
598 | + |
599 | + message_id = Int(name="message", allow_none=False) |
600 | + message = Reference(message_id, "Message.id") |
601 | + |
602 | + visible = Bool(allow_none=False, default=True) |
603 | + |
604 | + def __init__(self, specification, message): |
605 | + super().__init__() |
606 | + self.specification = specification |
607 | + self.message = message |
608 | |
609 | |
610 | @implementer(ISpecificationMessageSet) |
611 | @@ -39,8 +49,12 @@ class SpecificationMessageSet: |
612 | owner=owner, rfc822msgid=make_msgid("blueprint"), subject=subject |
613 | ) |
614 | MessageChunk(message=msg, content=content, sequence=1) |
615 | - return SpecificationMessage(specification=spec, message=msg) |
616 | + specmessage = SpecificationMessage(specification=spec, message=msg) |
617 | + IStore(SpecificationMessage).flush() |
618 | + return specmessage |
619 | |
620 | def get(self, specmessageid): |
621 | """See ISpecificationMessageSet.""" |
622 | - return SpecificationMessage.get(specmessageid) |
623 | + return IStore(SpecificationMessage).get( |
624 | + SpecificationMessage, specmessageid |
625 | + ) |
626 | diff --git a/lib/lp/blueprints/model/specificationsearch.py b/lib/lp/blueprints/model/specificationsearch.py |
627 | index 2f00a54..f505628 100644 |
628 | --- a/lib/lp/blueprints/model/specificationsearch.py |
629 | +++ b/lib/lp/blueprints/model/specificationsearch.py |
630 | @@ -153,9 +153,9 @@ def search_specifications( |
631 | for spec in rows: |
632 | if need_people: |
633 | person_ids |= { |
634 | - spec._assigneeID, |
635 | - spec._approverID, |
636 | - spec._drafterID, |
637 | + spec._assignee_id, |
638 | + spec._approver_id, |
639 | + spec._drafter_id, |
640 | } |
641 | if need_branches: |
642 | get_property_cache(spec).linked_branches = [] |
643 | @@ -215,7 +215,7 @@ def get_specification_active_product_filter(context): |
644 | return [], [] |
645 | from lp.registry.model.product import Product |
646 | |
647 | - tables = [LeftJoin(Product, Specification.productID == Product.id)] |
648 | + tables = [LeftJoin(Product, Specification.product_id == Product.id)] |
649 | active_products = Or(Specification.product == None, Product.active == True) |
650 | return tables, [active_products] |
651 | |
652 | diff --git a/lib/lp/blueprints/tests/test_specification.py b/lib/lp/blueprints/tests/test_specification.py |
653 | index fa7404e..62fbea3 100644 |
654 | --- a/lib/lp/blueprints/tests/test_specification.py |
655 | +++ b/lib/lp/blueprints/tests/test_specification.py |
656 | @@ -586,7 +586,7 @@ class SpecificationTests(TestCaseWithFactory): |
657 | def _fetch_specs_visible_for_user(self, user): |
658 | return Store.of(self.product).find( |
659 | Specification, |
660 | - Specification.productID == self.product.id, |
661 | + Specification.product == self.product, |
662 | *get_specification_privacy_filter(user), |
663 | ) |
664 | |
665 | diff --git a/lib/lp/blueprints/tests/test_specification_access_policy_triggers.py b/lib/lp/blueprints/tests/test_specification_access_policy_triggers.py |
666 | index e192cb7..2ba7153 100644 |
667 | --- a/lib/lp/blueprints/tests/test_specification_access_policy_triggers.py |
668 | +++ b/lib/lp/blueprints/tests/test_specification_access_policy_triggers.py |
669 | @@ -17,15 +17,14 @@ class TestSpecificationAccessPolicyTriggers(TestCaseWithFactory): |
670 | |
671 | def fetchPolicies(self, specification): |
672 | # We may be dealing with private specs, so just ignore security. |
673 | - return ( |
674 | - IStore(Specification) |
675 | - .execute( |
676 | - "SELECT access_policy, access_grants FROM specification WHERE " |
677 | - "id = ?", |
678 | - (removeSecurityProxy(specification).id,), |
679 | - ) |
680 | - .get_one() |
681 | - ) |
682 | + store = IStore(Specification) |
683 | + # Ensure that the specification's ID is available. |
684 | + store.flush() |
685 | + return store.execute( |
686 | + "SELECT access_policy, access_grants FROM specification WHERE " |
687 | + "id = ?", |
688 | + (removeSecurityProxy(specification).id,), |
689 | + ).get_one() |
690 | |
691 | def assertAccess(self, specification, expected_policy, expected_grants): |
692 | policy, grants = self.fetchPolicies(specification) |
693 | diff --git a/lib/lp/blueprints/vocabularies/specification.py b/lib/lp/blueprints/vocabularies/specification.py |
694 | index 55526cc..68a6a51 100644 |
695 | --- a/lib/lp/blueprints/vocabularies/specification.py |
696 | +++ b/lib/lp/blueprints/vocabularies/specification.py |
697 | @@ -14,16 +14,16 @@ from zope.schema.vocabulary import SimpleTerm |
698 | |
699 | from lp.blueprints.model.specification import Specification |
700 | from lp.services.webapp.interfaces import ILaunchBag |
701 | -from lp.services.webapp.vocabulary import SQLObjectVocabularyBase |
702 | +from lp.services.webapp.vocabulary import StormVocabularyBase |
703 | |
704 | |
705 | -class SpecificationVocabulary(SQLObjectVocabularyBase): |
706 | +class SpecificationVocabulary(StormVocabularyBase): |
707 | """List specifications for the current product or distribution in |
708 | ILaunchBag, EXCEPT for the current spec in LaunchBag if one exists. |
709 | """ |
710 | |
711 | _table = Specification |
712 | - _orderBy = "title" |
713 | + _order_by = "title" |
714 | |
715 | def __iter__(self): |
716 | launchbag = getUtility(ILaunchBag) |
717 | diff --git a/lib/lp/blueprints/vocabularies/specificationdependency.py b/lib/lp/blueprints/vocabularies/specificationdependency.py |
718 | index de5b89c..d458c05 100644 |
719 | --- a/lib/lp/blueprints/vocabularies/specificationdependency.py |
720 | +++ b/lib/lp/blueprints/vocabularies/specificationdependency.py |
721 | @@ -8,7 +8,7 @@ __all__ = [ |
722 | "SpecificationDependenciesVocabulary", |
723 | ] |
724 | |
725 | -from storm.locals import SQL, And, Store |
726 | +from storm.locals import SQL, Store |
727 | from zope.component import getUtility |
728 | from zope.interface import implementer |
729 | from zope.schema.vocabulary import SimpleTerm |
730 | @@ -28,12 +28,12 @@ from lp.services.webapp.interfaces import ILaunchBag |
731 | from lp.services.webapp.vocabulary import ( |
732 | CountableIterator, |
733 | IHugeVocabulary, |
734 | - SQLObjectVocabularyBase, |
735 | + StormVocabularyBase, |
736 | ) |
737 | |
738 | |
739 | @implementer(IHugeVocabulary) |
740 | -class SpecificationDepCandidatesVocabulary(SQLObjectVocabularyBase): |
741 | +class SpecificationDepCandidatesVocabulary(StormVocabularyBase): |
742 | """Specifications that could be dependencies of this spec. |
743 | |
744 | This includes only those specs that are not blocked by this spec (directly |
745 | @@ -54,7 +54,7 @@ class SpecificationDepCandidatesVocabulary(SQLObjectVocabularyBase): |
746 | """ |
747 | |
748 | _table = Specification |
749 | - _orderBy = "name" |
750 | + _order_by = "name" |
751 | displayname = "Select a blueprint" |
752 | step_title = "Search" |
753 | |
754 | @@ -74,7 +74,7 @@ class SpecificationDepCandidatesVocabulary(SQLObjectVocabularyBase): |
755 | user = getattr(getUtility(ILaunchBag), "user", None) |
756 | return spec not in set(self.context.all_blocked(user=user)) |
757 | |
758 | - def _order_by(self): |
759 | + def _order_search_by(self): |
760 | """Look at the context to provide grouping. |
761 | |
762 | If the blueprint is for a project, then matching results for that |
763 | @@ -187,7 +187,7 @@ class SpecificationDepCandidatesVocabulary(SQLObjectVocabularyBase): |
764 | fti_search(Specification, query), |
765 | self._exclude_blocked_query(), |
766 | ) |
767 | - .order_by(self._order_by()) |
768 | + .order_by(self._order_search_by()) |
769 | ) |
770 | |
771 | def __iter__(self): |
772 | @@ -198,17 +198,17 @@ class SpecificationDepCandidatesVocabulary(SQLObjectVocabularyBase): |
773 | return self._is_valid_candidate(obj) |
774 | |
775 | |
776 | -class SpecificationDependenciesVocabulary(SQLObjectVocabularyBase): |
777 | +class SpecificationDependenciesVocabulary(StormVocabularyBase): |
778 | """List specifications on which the current specification depends.""" |
779 | |
780 | _table = Specification |
781 | - _orderBy = "title" |
782 | + _order_by = "title" |
783 | |
784 | @property |
785 | - def _filter(self): |
786 | + def _clauses(self): |
787 | user = getattr(getUtility(ILaunchBag), "user", None) |
788 | - return And( |
789 | - SpecificationDependency.specificationID == self.context.id, |
790 | - SpecificationDependency.dependencyID == Specification.id, |
791 | + return [ |
792 | + SpecificationDependency.specification == self.context, |
793 | + SpecificationDependency.dependency_id == Specification.id, |
794 | *get_specification_privacy_filter(user), |
795 | - ) |
796 | + ] |
797 | diff --git a/lib/lp/registry/browser/__init__.py b/lib/lp/registry/browser/__init__.py |
798 | index 403345b..5cad743 100644 |
799 | --- a/lib/lp/registry/browser/__init__.py |
800 | +++ b/lib/lp/registry/browser/__init__.py |
801 | @@ -244,7 +244,9 @@ class RegistryDeleteViewMixin: |
802 | Store.of(bugtask).remove(nb.conjoined_primary) |
803 | else: |
804 | nb.milestone = None |
805 | - removeSecurityProxy(milestone.all_specifications).set(milestoneID=None) |
806 | + removeSecurityProxy(milestone.all_specifications).set( |
807 | + milestone_id=None |
808 | + ) |
809 | getUtility(ISpecificationWorkItemSet).unlinkMilestone(milestone) |
810 | self._deleteRelease(milestone.product_release) |
811 | milestone.destroySelf() |
812 | diff --git a/lib/lp/registry/doc/person-account.rst b/lib/lp/registry/doc/person-account.rst |
813 | index 0ed70c6..f5e2424 100644 |
814 | --- a/lib/lp/registry/doc/person-account.rst |
815 | +++ b/lib/lp/registry/doc/person-account.rst |
816 | @@ -76,7 +76,10 @@ will cause this spec to be reassigned. |
817 | |
818 | >>> from lp.blueprints.model.specification import Specification |
819 | >>> from lp.registry.model.person import Person |
820 | - >>> spec = Specification.selectFirst("assignee IS NULL", orderBy='id') |
821 | + >>> from lp.services.database.interfaces import IStore |
822 | + >>> spec = IStore(Specification).find( |
823 | + ... Specification, _assignee=None |
824 | + ... ).order_by("id").first() |
825 | >>> spec.assignee = foobar |
826 | |
827 | >>> for membership in foobar.team_memberships: |
828 | diff --git a/lib/lp/registry/doc/productseries.rst b/lib/lp/registry/doc/productseries.rst |
829 | index 18d0c9c..44d6516 100644 |
830 | --- a/lib/lp/registry/doc/productseries.rst |
831 | +++ b/lib/lp/registry/doc/productseries.rst |
832 | @@ -201,25 +201,27 @@ is informational. |
833 | We will create two specs for onezero and use them to demonstrate the |
834 | filtering. |
835 | |
836 | - >>> from lp.services.database.constants import UTC_NOW |
837 | + >>> from lp.blueprints.enums import SpecificationDefinitionStatus |
838 | + >>> from lp.blueprints.interfaces.specification import ISpecificationSet |
839 | >>> carlos = getUtility(IPersonSet).getByName('carlos') |
840 | - >>> from lp.blueprints.model.specification import Specification |
841 | - >>> a = Specification(name='a', title='A', summary='AA', owner=carlos, |
842 | - ... product=firefox, productseries=onezero, |
843 | - ... specurl='http://wbc.com/two', goal_proposer=carlos, |
844 | - ... date_goal_proposed=UTC_NOW) |
845 | - >>> b = Specification(name='b', title='b', summary='bb', owner=carlos, |
846 | - ... product=firefox, productseries=onezero, |
847 | - ... specurl='http://fds.com/adsf', goal_proposer=carlos, |
848 | - ... date_goal_proposed=UTC_NOW) |
849 | + >>> _ = login_person(carlos) |
850 | + >>> a = getUtility(ISpecificationSet).new( |
851 | + ... name="a", title="A", specurl="http://wbc.com/two", summary="AA", |
852 | + ... definition_status=SpecificationDefinitionStatus.NEW, owner=carlos, |
853 | + ... target=firefox, |
854 | + ... ) |
855 | + >>> a.proposeGoal(onezero, carlos) |
856 | + >>> b = getUtility(ISpecificationSet).new( |
857 | + ... name="b", title="b", specurl="http://fds.com/adsf", summary="bb", |
858 | + ... definition_status=SpecificationDefinitionStatus.NEW, owner=carlos, |
859 | + ... target=firefox, |
860 | + ... ) |
861 | + >>> b.proposeGoal(onezero, carlos) |
862 | |
863 | Now, we will make one of them accepted, the other declined, and both of |
864 | them informational. |
865 | |
866 | - >>> from lp.blueprints.enums import ( |
867 | - ... SpecificationDefinitionStatus, |
868 | - ... SpecificationImplementationStatus, |
869 | - ... ) |
870 | + >>> from lp.blueprints.enums import SpecificationImplementationStatus |
871 | >>> a.definition_status = b.definition_status = ( |
872 | ... SpecificationDefinitionStatus.APPROVED) |
873 | >>> a.implementation_status = ( |
874 | diff --git a/lib/lp/registry/model/distribution.py b/lib/lp/registry/model/distribution.py |
875 | index 3dd493e..d8ed65c 100644 |
876 | --- a/lib/lp/registry/model/distribution.py |
877 | +++ b/lib/lp/registry/model/distribution.py |
878 | @@ -1404,7 +1404,7 @@ class Distribution( |
879 | - informationalness: we will show ANY if nothing is said |
880 | |
881 | """ |
882 | - base_clauses = [Specification.distributionID == self.id] |
883 | + base_clauses = [Specification.distribution == self] |
884 | return search_specifications( |
885 | self, |
886 | base_clauses, |
887 | @@ -1419,7 +1419,11 @@ class Distribution( |
888 | |
889 | def getSpecification(self, name): |
890 | """See `ISpecificationTarget`.""" |
891 | - return Specification.selectOneBy(distribution=self, name=name) |
892 | + return ( |
893 | + IStore(Specification) |
894 | + .find(Specification, distribution=self, name=name) |
895 | + .one() |
896 | + ) |
897 | |
898 | def getAllowedSpecificationInformationTypes(self): |
899 | """See `ISpecificationTarget`.""" |
900 | diff --git a/lib/lp/registry/model/distroseries.py b/lib/lp/registry/model/distroseries.py |
901 | index c3f912d..41f4e9a 100644 |
902 | --- a/lib/lp/registry/model/distroseries.py |
903 | +++ b/lib/lp/registry/model/distroseries.py |
904 | @@ -974,7 +974,7 @@ class DistroSeries( |
905 | - informationalness: if nothing is said, ANY |
906 | |
907 | """ |
908 | - base_clauses = [Specification.distroseriesID == self.id] |
909 | + base_clauses = [Specification.distroseries == self] |
910 | return search_specifications( |
911 | self, |
912 | base_clauses, |
913 | diff --git a/lib/lp/registry/model/milestone.py b/lib/lp/registry/model/milestone.py |
914 | index 0171a61..f7b1abb 100644 |
915 | --- a/lib/lp/registry/model/milestone.py |
916 | +++ b/lib/lp/registry/model/milestone.py |
917 | @@ -147,7 +147,7 @@ class MilestoneData: |
918 | from lp.blueprints.model.specification import Specification |
919 | |
920 | return Store.of(self).find( |
921 | - Specification, Specification.milestoneID == self.id |
922 | + Specification, Specification.milestone == self |
923 | ) |
924 | |
925 | def getSpecifications(self, user): |
926 | @@ -166,7 +166,9 @@ class MilestoneData: |
927 | product_origin, clauses = get_specification_active_product_filter(self) |
928 | origin.extend(product_origin) |
929 | clauses.extend(get_specification_privacy_filter(user)) |
930 | - origin.append(LeftJoin(Person, Specification._assigneeID == Person.id)) |
931 | + origin.append( |
932 | + LeftJoin(Person, Specification._assignee_id == Person.id) |
933 | + ) |
934 | milestones = self._milestone_ids_expr(user) |
935 | |
936 | results = ( |
937 | @@ -180,7 +182,7 @@ class MilestoneData: |
938 | Specification.id, |
939 | tables=[Specification], |
940 | where=( |
941 | - Specification.milestoneID.is_in(milestones) |
942 | + Specification.milestone_id.is_in(milestones) |
943 | ), |
944 | ), |
945 | Select( |
946 | diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py |
947 | index db8a777..9239372 100644 |
948 | --- a/lib/lp/registry/model/person.py |
949 | +++ b/lib/lp/registry/model/person.py |
950 | @@ -1630,7 +1630,7 @@ class Person( |
951 | SpecificationWorkItem.specification_id.is_in( |
952 | Select( |
953 | Specification.id, |
954 | - where=Specification._assigneeID.is_in( |
955 | + where=Specification._assignee_id.is_in( |
956 | self.participant_ids |
957 | ), |
958 | ) |
959 | @@ -1670,7 +1670,7 @@ class Person( |
960 | Milestone, |
961 | Coalesce( |
962 | SpecificationWorkItem.milestone_id, |
963 | - Specification.milestoneID, |
964 | + Specification.milestone_id, |
965 | ) |
966 | == Milestone.id, |
967 | ), |
968 | @@ -1697,17 +1697,17 @@ class Person( |
969 | specs = bulk.load_related( |
970 | Specification, workitems, ["specification_id"] |
971 | ) |
972 | - bulk.load_related(Product, specs, ["productID"]) |
973 | - bulk.load_related(Distribution, specs, ["distributionID"]) |
974 | + bulk.load_related(Product, specs, ["product_id"]) |
975 | + bulk.load_related(Distribution, specs, ["distribution_id"]) |
976 | assignee_ids = set( |
977 | [workitem.assignee_id for workitem in workitems] |
978 | - + [spec._assigneeID for spec in specs] |
979 | + + [spec._assignee_id for spec in specs] |
980 | ) |
981 | assignee_ids.discard(None) |
982 | bulk.load(Person, assignee_ids, store) |
983 | milestone_ids = set( |
984 | [workitem.milestone_id for workitem in workitems] |
985 | - + [spec.milestoneID for spec in specs] |
986 | + + [spec.milestone_id for spec in specs] |
987 | ) |
988 | milestone_ids.discard(None) |
989 | bulk.load(Milestone, milestone_ids, store) |
990 | diff --git a/lib/lp/registry/model/product.py b/lib/lp/registry/model/product.py |
991 | index 357e5c4..3cae421 100644 |
992 | --- a/lib/lp/registry/model/product.py |
993 | +++ b/lib/lp/registry/model/product.py |
994 | @@ -1418,7 +1418,7 @@ class Product( |
995 | need_workitems=False, |
996 | ): |
997 | """See `IHasSpecifications`.""" |
998 | - base_clauses = [Specification.productID == self.id] |
999 | + base_clauses = [Specification.product == self] |
1000 | return search_specifications( |
1001 | self, |
1002 | base_clauses, |
1003 | @@ -1433,7 +1433,11 @@ class Product( |
1004 | |
1005 | def getSpecification(self, name): |
1006 | """See `ISpecificationTarget`.""" |
1007 | - return Specification.selectOneBy(product=self, name=name) |
1008 | + return ( |
1009 | + IStore(Specification) |
1010 | + .find(Specification, product=self, name=name) |
1011 | + .one() |
1012 | + ) |
1013 | |
1014 | def getSeries(self, name): |
1015 | """See `IProduct`.""" |
1016 | diff --git a/lib/lp/registry/model/productseries.py b/lib/lp/registry/model/productseries.py |
1017 | index 16cbb10..0edd632 100644 |
1018 | --- a/lib/lp/registry/model/productseries.py |
1019 | +++ b/lib/lp/registry/model/productseries.py |
1020 | @@ -348,7 +348,7 @@ class ProductSeries( |
1021 | - informational, which defaults to showing BOTH if nothing is said |
1022 | |
1023 | """ |
1024 | - base_clauses = [Specification.productseriesID == self.id] |
1025 | + base_clauses = [Specification.productseries == self] |
1026 | return search_specifications( |
1027 | self, |
1028 | base_clauses, |
1029 | @@ -365,7 +365,7 @@ class ProductSeries( |
1030 | @property |
1031 | def all_specifications(self): |
1032 | return Store.of(self).find( |
1033 | - Specification, Specification.productseriesID == self.id |
1034 | + Specification, Specification.productseries == self |
1035 | ) |
1036 | |
1037 | def _customizeSearchParams(self, search_params): |
1038 | diff --git a/lib/lp/registry/model/projectgroup.py b/lib/lp/registry/model/projectgroup.py |
1039 | index b50b11c..0dda2e0 100644 |
1040 | --- a/lib/lp/registry/model/projectgroup.py |
1041 | +++ b/lib/lp/registry/model/projectgroup.py |
1042 | @@ -287,7 +287,7 @@ class ProjectGroup( |
1043 | ): |
1044 | """See `IHasSpecifications`.""" |
1045 | base_clauses = [ |
1046 | - Specification.productID == Product.id, |
1047 | + Specification.product_id == Product.id, |
1048 | Product.projectgroupID == self.id, |
1049 | ] |
1050 | tables = [Specification] |
1051 | @@ -296,7 +296,7 @@ class ProjectGroup( |
1052 | tables.append( |
1053 | Join( |
1054 | ProductSeries, |
1055 | - Specification.productseriesID == ProductSeries.id, |
1056 | + Specification.productseries_id == ProductSeries.id, |
1057 | ) |
1058 | ) |
1059 | return search_specifications( |
1060 | diff --git a/lib/lp/registry/services/sharingservice.py b/lib/lp/registry/services/sharingservice.py |
1061 | index 5548b4a..b628808 100644 |
1062 | --- a/lib/lp/registry/services/sharingservice.py |
1063 | +++ b/lib/lp/registry/services/sharingservice.py |
1064 | @@ -435,9 +435,9 @@ class SharingService: |
1065 | AccessPolicy, |
1066 | And( |
1067 | Or( |
1068 | - Specification.distributionID |
1069 | + Specification.distribution_id |
1070 | == AccessPolicy.distribution_id, |
1071 | - Specification.productID == AccessPolicy.product_id, |
1072 | + Specification.product_id == AccessPolicy.product_id, |
1073 | ), |
1074 | AccessPolicy.type == Specification.information_type, |
1075 | ), |
1076 | diff --git a/lib/lp/registry/tests/test_person.py b/lib/lp/registry/tests/test_person.py |
1077 | index 7fa6c28..2fa9c5c 100644 |
1078 | --- a/lib/lp/registry/tests/test_person.py |
1079 | +++ b/lib/lp/registry/tests/test_person.py |
1080 | @@ -1027,7 +1027,7 @@ class TestPersonStates(TestCaseWithFactory): |
1081 | ) |
1082 | |
1083 | def test_Specification_person_validator(self): |
1084 | - specification = Specification.select(limit=1)[0] |
1085 | + specification = IStore(Specification).find(Specification).first() |
1086 | for attr_name in [ |
1087 | "assignee", |
1088 | "drafter", |
1089 | diff --git a/lib/lp/registry/tests/test_sharingjob.py b/lib/lp/registry/tests/test_sharingjob.py |
1090 | index 6c7c65a..e017e72 100644 |
1091 | --- a/lib/lp/registry/tests/test_sharingjob.py |
1092 | +++ b/lib/lp/registry/tests/test_sharingjob.py |
1093 | @@ -159,6 +159,7 @@ class SharingJobDerivedTestCase(TestCaseWithFactory): |
1094 | def test_repr_specifications(self): |
1095 | requestor = self.factory.makePerson() |
1096 | specification = self.factory.makeSpecification() |
1097 | + IStore(specification).flush() |
1098 | job = getUtility(IRemoveArtifactSubscriptionsJobSource).create( |
1099 | requestor, artifacts=[specification] |
1100 | ) |
1101 | diff --git a/lib/lp/scripts/harness.py b/lib/lp/scripts/harness.py |
1102 | index c33077c..4bf8084 100644 |
1103 | --- a/lib/lp/scripts/harness.py |
1104 | +++ b/lib/lp/scripts/harness.py |
1105 | @@ -81,8 +81,8 @@ def _get_locals(): |
1106 | proj = ProjectGroup.get(1) |
1107 | b2 = Bug.get(2) |
1108 | b1 = Bug.get(1) |
1109 | - s = Specification.get(1) |
1110 | - q = Question.get(1) |
1111 | + s = store.get(Specification, 1) |
1112 | + q = store.get(Question, 1) |
1113 | # Silence unused name warnings |
1114 | d, p, ds, prod, proj, b2, b1, s, q |
1115 |