Merge lp:~jtv/launchpad/recife-traits into lp:~launchpad/launchpad/recife
- recife-traits
- Merge into recife
Status: | Merged |
---|---|
Approved by: | Jeroen T. Vermeulen |
Approved revision: | no longer in the source branch. |
Merged at revision: | 9149 |
Proposed branch: | lp:~jtv/launchpad/recife-traits |
Merge into: | lp:~launchpad/launchpad/recife |
Diff against target: |
1222 lines (+519/-195) 10 files modified
lib/lp/translations/configure.zcml (+13/-0) lib/lp/translations/interfaces/side.py (+71/-0) lib/lp/translations/interfaces/translationmessage.py (+10/-4) lib/lp/translations/interfaces/translations.py (+0/-10) lib/lp/translations/model/potmsgset.py (+68/-101) lib/lp/translations/model/side.py (+79/-0) lib/lp/translations/model/translationmessage.py (+6/-7) lib/lp/translations/tests/test_potmsgset.py (+83/-70) lib/lp/translations/tests/test_setcurrenttranslation.py (+3/-3) lib/lp/translations/tests/test_side.py (+186/-0) |
To merge this branch: | bzr merge lp:~jtv/launchpad/recife-traits |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Henning Eggers (community) | code | Approve | |
Review via email: mp+31729@code.launchpad.net |
Commit message
Translation side traits.
Description of the change
= Translation side traits =
For merging into our "recife" feature branch, which changes how we model how Ubuntu and non-Ubuntu translations interact and which translation messages are the "current" ones.
This is a pattern that came in handy while implementing POTMsgSet.
A lot of the changes appear unrelated: since the traits are provided by a utility, I had to involve Zope in some existing tests that then stumbled over security proxies. That meant more logins and one or two interface extensions.
There's a few tiny bits of lint left where I'm not sure the linter is right: a comment that counts as a blank line and two cases where the formatting for list comprehensions that we were once told to employ is considered whitespace-
To test:
{{{
./bin/test -vvc -m lp.translations
}}}
Jeroen
Preview Diff
1 | === modified file 'lib/lp/translations/configure.zcml' |
2 | --- lib/lp/translations/configure.zcml 2010-07-23 09:41:07 +0000 |
3 | +++ lib/lp/translations/configure.zcml 2010-08-06 07:43:48 +0000 |
4 | @@ -570,6 +570,19 @@ |
5 | <allow |
6 | interface="lp.translations.interfaces.translationmessage.ITranslationMessageSet"/> |
7 | </securedutility> |
8 | + |
9 | + <!-- TranslationSideTraits --> |
10 | + <class class="lp.translations.model.side.TranslationSideTraits"> |
11 | + <allow interface="lp.translations.interfaces.side.ITranslationSideTraits"/> |
12 | + </class> |
13 | + |
14 | + <!-- TranslationSideTraitsSet --> |
15 | + <securedutility |
16 | + class="lp.translations.model.side.TranslationSideTraitsSet" |
17 | + provides="lp.translations.interfaces.side.ITranslationSideTraitsSet"> |
18 | + <allow |
19 | + interface="lp.translations.interfaces.side.ITranslationSideTraitsSet"/> |
20 | + </securedutility> |
21 | </facet> |
22 | <adapter |
23 | provides="canonical.launchpad.webapp.interfaces.IBreadcrumb" |
24 | |
25 | === added file 'lib/lp/translations/interfaces/side.py' |
26 | --- lib/lp/translations/interfaces/side.py 1970-01-01 00:00:00 +0000 |
27 | +++ lib/lp/translations/interfaces/side.py 2010-08-06 07:43:48 +0000 |
28 | @@ -0,0 +1,71 @@ |
29 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
30 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
31 | + |
32 | +"""Traits of the two "sides" of translation: Ubuntu and upstream.""" |
33 | + |
34 | +__metaclass__ = type |
35 | +__all__ = [ |
36 | + 'ITranslationSideTraits', |
37 | + 'ITranslationSideTraitsSet', |
38 | + 'TranslationSide', |
39 | + ] |
40 | + |
41 | +from zope.interface import Attribute, Interface |
42 | +from zope.schema import TextLine |
43 | + |
44 | +from lazr.restful.fields import Reference |
45 | + |
46 | + |
47 | +class TranslationSide: |
48 | + """The two "sides" of software that can be translated in Launchpad. |
49 | + |
50 | + These are "upstream" and "Ubuntu." |
51 | + """ |
52 | + UPSTREAM = 1 |
53 | + UBUNTU = 2 |
54 | + |
55 | + |
56 | +class ITranslationSideTraits(Interface): |
57 | + """Traits describing a "side": upstream or Ubuntu. |
58 | + |
59 | + Encapsulates primitives that depend on translation side: finding the |
60 | + message that is current on the given side, checking the flag that |
61 | + says whether a message is current on this side, setting or clearing |
62 | + the flag, and providing the same capabilities for the other side. |
63 | + |
64 | + For an introduction to the Traits pattern, see |
65 | + http://www.cantrip.org/traits.html |
66 | + """ |
67 | + side = Attribute("This TranslationSide") |
68 | + other_side_traits = Reference( |
69 | + Interface, title=u"Traits for other side.", required=True, |
70 | + readonly=True) |
71 | + flag_name = TextLine( |
72 | + title=u"The TranslationMessage flag for this side", |
73 | + required=True, readonly=True) |
74 | + |
75 | + def getCurrentMessage(potemplate, potmsgset, language): |
76 | + """Find the current message on this side, if any.""" |
77 | + |
78 | + def getFlag(translationmessage): |
79 | + """Retrieve a message's "current" flag for this side.""" |
80 | + |
81 | + def setFlag(translationmessage, value): |
82 | + """Set a message's "current" flag for this side. |
83 | + |
84 | + This is a dumb operation. It does not worry about conflicting |
85 | + other messages. |
86 | + """ |
87 | + |
88 | + |
89 | +class ITranslationSideTraitsSet(Interface): |
90 | + """Utility for `TranslationSideTraits`.""" |
91 | + |
92 | + def getTraits(side): |
93 | + """Retrieve the `TranslationSideTraits` for `side`.""" |
94 | + |
95 | + def getForTemplate(potemplate): |
96 | + """Get the `TranslationSideTraits` for `potemplate`s side.""" |
97 | + |
98 | + def getAllTraits(): |
99 | + """Return dict mapping `TranslationSide` to traits objects.""" |
100 | |
101 | === modified file 'lib/lp/translations/interfaces/translationmessage.py' |
102 | --- lib/lp/translations/interfaces/translationmessage.py 2010-06-18 10:50:07 +0000 |
103 | +++ lib/lp/translations/interfaces/translationmessage.py 2010-08-06 07:43:48 +0000 |
104 | @@ -125,9 +125,8 @@ |
105 | readonly=False, required=False) |
106 | |
107 | reviewer = Object( |
108 | - title=_( |
109 | - "The person who did the review and accepted current translations" |
110 | - ), readonly=False, required=False, schema=IPerson) |
111 | + title=_("The person who reviewed and accepted this translation"), |
112 | + readonly=False, required=False, schema=IPerson) |
113 | |
114 | # Message references for up to TranslationConstants.MAX_PLURAL_FORMS |
115 | # plural forms. |
116 | @@ -218,6 +217,14 @@ |
117 | def getOnePOFile(): |
118 | """Get any POFile containing this translation.""" |
119 | |
120 | + def shareIfPossible(): |
121 | + """Make this message shared, if possible. |
122 | + |
123 | + If there is already a similar message that is shared, this |
124 | + message's information is merged into that of the existing one, |
125 | + and self is deleted. |
126 | + """ |
127 | + |
128 | def isHidden(pofile): |
129 | """Whether this is an unused, hidden suggestion in `pofile`. |
130 | |
131 | @@ -258,7 +265,6 @@ |
132 | """ |
133 | |
134 | |
135 | - |
136 | class ITranslationMessageSuggestions(Interface): |
137 | """Suggested `ITranslationMessage`s for a `POTMsgSet`. |
138 | |
139 | |
140 | === modified file 'lib/lp/translations/interfaces/translations.py' |
141 | --- lib/lp/translations/interfaces/translations.py 2010-08-04 11:00:51 +0000 |
142 | +++ lib/lp/translations/interfaces/translations.py 2010-08-06 07:43:48 +0000 |
143 | @@ -10,7 +10,6 @@ |
144 | __all__ = [ |
145 | 'TranslationConstants', |
146 | 'TranslationsBranchImportMode', |
147 | - 'TranslationSide', |
148 | ] |
149 | |
150 | |
151 | @@ -52,12 +51,3 @@ |
152 | Import all translation files (templates and translations) |
153 | found in the branch. |
154 | """) |
155 | - |
156 | - |
157 | -class TranslationSide: |
158 | - """The two "sides" of software that can be translated in Launchpad. |
159 | - |
160 | - These are "upstream" and "Ubuntu." |
161 | - """ |
162 | - UPSTREAM = 1 |
163 | - UBUNTU = 2 |
164 | |
165 | === modified file 'lib/lp/translations/model/potmsgset.py' |
166 | --- lib/lp/translations/model/potmsgset.py 2010-08-04 11:00:51 +0000 |
167 | +++ lib/lp/translations/model/potmsgset.py 2010-08-06 07:43:48 +0000 |
168 | @@ -5,7 +5,7 @@ |
169 | |
170 | __metaclass__ = type |
171 | __all__ = [ |
172 | - 'make_translation_side_message_traits', |
173 | + 'make_message_side_helpers', |
174 | 'POTMsgSet', |
175 | ] |
176 | |
177 | @@ -38,6 +38,8 @@ |
178 | IPOTMsgSet, |
179 | POTMsgSetInIncompatibleTemplatesError, |
180 | TranslationCreditsType) |
181 | +from lp.translations.interfaces.side import ( |
182 | + ITranslationSideTraitsSet, TranslationSide) |
183 | from lp.translations.interfaces.translationfileformat import ( |
184 | TranslationFileFormat) |
185 | from lp.translations.interfaces.translationimporter import ( |
186 | @@ -46,8 +48,7 @@ |
187 | RosettaTranslationOrigin, |
188 | TranslationConflict, |
189 | TranslationValidationStatus) |
190 | -from lp.translations.interfaces.translations import ( |
191 | - TranslationConstants, TranslationSide) |
192 | +from lp.translations.interfaces.translations import TranslationConstants |
193 | from lp.translations.model.pomsgid import POMsgID |
194 | from lp.translations.model.potranslation import POTranslation |
195 | from lp.translations.model.translationmessage import ( |
196 | @@ -85,99 +86,68 @@ |
197 | u'credits are counted as translated.') |
198 | |
199 | |
200 | -class TranslationSideMessageTraits: |
201 | - """Dealing with a `POTMsgSet` on either `TranslationSide`. |
202 | - |
203 | - Encapsulates primitives that depend on translation side: finding the |
204 | - message that is current on the given side, checking the flag that |
205 | - says whether a message is current on this side, setting or clearing |
206 | - the flag, and providing the same capabilities for the other side. |
207 | - |
208 | - For an introduction to the Traits pattern, see |
209 | - http://www.cantrip.org/traits.html |
210 | +# Marker for "no incumbent message found yet." |
211 | +incumbent_unknown = object() |
212 | + |
213 | + |
214 | +class MessageSideHelper: |
215 | + """Helper for manipulating messages on one `TranslationSide`. |
216 | + |
217 | + Does some caching so that the caller doesn't need to worry about |
218 | + unnecessary queries e.g. when disabling a previously current |
219 | + message. |
220 | """ |
221 | - # The TranslationSide that these Traits are for. |
222 | - side = None |
223 | - |
224 | - # TranslationSideMessageTraits for this message on the "other side." |
225 | + |
226 | + # The TranslationSideTraits that this helper is for. |
227 | + traits = None |
228 | + |
229 | + # MessageSideHelper for this message on the "other side." |
230 | other_side = None |
231 | |
232 | - # Name of this side's flag. |
233 | - flag_name = None |
234 | + _incumbent = incumbent_unknown |
235 | |
236 | - def __init__(self, potmsgset, potemplate=None, language=None, |
237 | - variant=None): |
238 | + def __init__(self, side, potmsgset, potemplate=None, language=None): |
239 | + self.traits = getUtility(ITranslationSideTraitsSet).getTraits(side) |
240 | self.potmsgset = potmsgset |
241 | self.potemplate = potemplate |
242 | self.language = language |
243 | - self.variant = variant |
244 | - |
245 | - self._found_incumbent = False |
246 | |
247 | @property |
248 | def incumbent_message(self): |
249 | """Message that currently has the flag.""" |
250 | - if not self._found_incumbent: |
251 | - self._incumbent = self._getIncumbentMessage() |
252 | - self._found_incumbent = True |
253 | + if self._incumbent == incumbent_unknown: |
254 | + self._incumbent = self.traits.getCurrentMessage( |
255 | + self.potmsgset, self.potemplate, self.language) |
256 | return self._incumbent |
257 | |
258 | - def getFlag(self, translationmessage): |
259 | - """Is this message the current one on this side?""" |
260 | - return getattr(translationmessage, self.flag_name) |
261 | - |
262 | def setFlag(self, translationmessage, value): |
263 | """Set or clear a message's "current" flag for this side.""" |
264 | - if value == self.getFlag(translationmessage): |
265 | + if value == self.traits.getFlag(translationmessage): |
266 | return |
267 | |
268 | - if value and self.incumbent_message is not None: |
269 | - Store.of(self.incumbent_message).add_flush_order( |
270 | - self.incumbent_message, translationmessage) |
271 | - self.setFlag(self.incumbent_message, False) |
272 | - |
273 | - setattr(translationmessage, self.flag_name, value) |
274 | - self._found_incumbent = False |
275 | - |
276 | - def _getIncumbentMessage(self): |
277 | - """Get the message that is current on this side, if any.""" |
278 | - raise NotImplementedError('_getIncumbentMessage') |
279 | - |
280 | - |
281 | -class UpstreamSideTraits(TranslationSideMessageTraits): |
282 | - """Traits for upstream translations.""" |
283 | - |
284 | - side = TranslationSide.UPSTREAM |
285 | - |
286 | - flag_name = 'is_current_upstream' |
287 | - |
288 | - def _getIncumbentMessage(self): |
289 | - """See `TranslationSideMessageTraits`.""" |
290 | - return self.potmsgset.getImportedTranslationMessage( |
291 | - self.potemplate, self.language, variant=self.variant) |
292 | - |
293 | - |
294 | -class UbuntuSideTraits(TranslationSideMessageTraits): |
295 | - """Traits for Ubuntu translations.""" |
296 | - |
297 | - side = TranslationSide.UBUNTU |
298 | - |
299 | - flag_name = 'is_current_ubuntu' |
300 | - |
301 | - def _getIncumbentMessage(self): |
302 | - """See `TranslationSideMessageTraits`.""" |
303 | - return self.potmsgset.getCurrentTranslationMessage( |
304 | - self.potemplate, self.language, variant=self.variant) |
305 | - |
306 | - |
307 | -def make_translation_side_message_traits(side, potmsgset, potemplate, |
308 | - language, variant=None): |
309 | - """Create `TranslationSideTraits` object of the appropriate subtype.""" |
310 | - ubuntu = UbuntuSideTraits(potmsgset, potemplate, language, variant) |
311 | - upstream = UpstreamSideTraits(potmsgset, potemplate, language, variant) |
312 | + if value: |
313 | + if self.incumbent_message is not None: |
314 | + Store.of(self.incumbent_message).add_flush_order( |
315 | + self.incumbent_message, translationmessage) |
316 | + self.setFlag(self.incumbent_message, False) |
317 | + self._incumbent = translationmessage |
318 | + else: |
319 | + self._incumbent = incumbent_unknown |
320 | + |
321 | + self.traits.setFlag(translationmessage, value) |
322 | + |
323 | + |
324 | +def make_message_side_helpers(side, potmsgset, potemplate, language): |
325 | + """Create `MessageSideHelper` object of the appropriate subtype.""" |
326 | + upstream = MessageSideHelper( |
327 | + TranslationSide.UPSTREAM, potmsgset, potemplate, language) |
328 | + ubuntu = MessageSideHelper( |
329 | + TranslationSide.UBUNTU, potmsgset, potemplate, language) |
330 | upstream.other_side = ubuntu |
331 | ubuntu.other_side = upstream |
332 | - mapping = dict((traits.side, traits) for traits in (ubuntu, upstream)) |
333 | + mapping = dict( |
334 | + (helper.traits.side, helper) |
335 | + for helper in (ubuntu, upstream)) |
336 | return mapping[side] |
337 | |
338 | |
339 | @@ -469,8 +439,9 @@ |
340 | WHERE |
341 | POTMsgSet.id <> %s AND |
342 | msgid_singular = %s AND |
343 | - POTemplate.iscurrent AND |
344 | - (Product.official_rosetta OR Distribution.official_rosetta) |
345 | + POTemplate.iscurrent AND ( |
346 | + Product.official_rosetta OR |
347 | + Distribution.official_rosetta) |
348 | )''' % sqlvalues(self, self.msgid_singular)) |
349 | |
350 | # Subquery to find the ids of TranslationMessages that are |
351 | @@ -485,7 +456,7 @@ |
352 | for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)]) |
353 | ids_query_params = { |
354 | 'msgstrs': msgstrs, |
355 | - 'where': ' AND '.join(query) |
356 | + 'where': ' AND '.join(query), |
357 | } |
358 | ids_query = ''' |
359 | SELECT DISTINCT ON (%(msgstrs)s) |
360 | @@ -826,7 +797,6 @@ |
361 | if is_current_upstream or new_message == upstream_message: |
362 | new_message.makeCurrentUpstream() |
363 | |
364 | - |
365 | def _isTranslationMessageASuggestion(self, force_suggestion, |
366 | pofile, submitter, |
367 | force_edition_rights, |
368 | @@ -1079,7 +1049,7 @@ |
369 | return 'none' |
370 | elif message.is_diverged: |
371 | return 'diverged' |
372 | - elif translation_side_traits.other_side.getFlag(message): |
373 | + elif translation_side_traits.other_side_traits.getFlag(message): |
374 | return 'other_shared' |
375 | else: |
376 | return 'shared' |
377 | @@ -1100,8 +1070,7 @@ |
378 | |
379 | translation_args = dict( |
380 | ('msgstr%d' % form, translation) |
381 | - for form, translation in translations.iteritems() |
382 | - ) |
383 | + for form, translation in translations.iteritems()) |
384 | |
385 | return TranslationMessage( |
386 | potmsgset=self, |
387 | @@ -1117,14 +1086,13 @@ |
388 | def setCurrentTranslation(self, pofile, submitter, translations, origin, |
389 | translation_side, share_with_other_side=False): |
390 | """See `IPOTMsgSet`.""" |
391 | - traits = make_translation_side_message_traits( |
392 | - translation_side, self, pofile.potemplate, pofile.language, |
393 | - variant=pofile.variant) |
394 | + helper = make_message_side_helpers( |
395 | + translation_side, self, pofile.potemplate, pofile.language) |
396 | |
397 | translations = self._findPOTranslations(translations) |
398 | |
399 | # The current message on this translation side, if any. |
400 | - incumbent_message = traits.incumbent_message |
401 | + incumbent_message = helper.incumbent_message |
402 | |
403 | # An already existing message, if any, that's either shared, or |
404 | # diverged for the template/pofile we're working on, whose |
405 | @@ -1174,8 +1142,8 @@ |
406 | } |
407 | |
408 | incumbent_state = "incumbent_%s" % self._nameMessageStatus( |
409 | - incumbent_message, traits) |
410 | - twin_state = "twin_%s" % self._nameMessageStatus(twin, traits) |
411 | + incumbent_message, helper.traits) |
412 | + twin_state = "twin_%s" % self._nameMessageStatus(twin, helper.traits) |
413 | |
414 | decisions = decision_matrix[incumbent_state][twin_state] |
415 | assert re.match('[ABZ]?[124567]?[+*]?$', decisions), ( |
416 | @@ -1185,11 +1153,11 @@ |
417 | if character == 'A': |
418 | # Deactivate & converge. |
419 | # There may be an identical shared message. |
420 | - traits.setFlag(incumbent_message, False) |
421 | + helper.traits.setFlag(incumbent_message, False) |
422 | incumbent_message.shareIfPossible() |
423 | elif character == 'B': |
424 | # Deactivate. |
425 | - traits.setFlag(incumbent_message, False) |
426 | + helper.setFlag(incumbent_message, False) |
427 | elif character == 'Z': |
428 | # There is no incumbent message, so do nothing to it. |
429 | assert incumbent_message is None, ( |
430 | @@ -1210,14 +1178,14 @@ |
431 | # (If not, it's already active and has been unmasked by |
432 | # our deactivating the incumbent). |
433 | message = twin |
434 | - if not traits.getFlag(twin): |
435 | - assert not traits.other_side.getFlag(twin), ( |
436 | + if not helper.traits.getFlag(twin): |
437 | + assert not helper.other_side.traits.getFlag(twin), ( |
438 | "Trying to diverge a message that is current on the " |
439 | "other side.") |
440 | message.potemplate = pofile.potemplate |
441 | elif character == '6': |
442 | # If other is not active, fork a diverged message. |
443 | - if traits.getFlag(twin): |
444 | + if helper.traits.getFlag(twin): |
445 | message = twin |
446 | else: |
447 | # The twin is used on the other side, so we can't |
448 | @@ -1232,11 +1200,11 @@ |
449 | message.shareIfPossible() |
450 | elif character == '*': |
451 | if share_with_other_side: |
452 | - if traits.other_side.incumbent_message is None: |
453 | - traits.other_side.setFlag(message, True) |
454 | + if helper.other_side.incumbent_message is None: |
455 | + helper.other_side.setFlag(message, True) |
456 | elif character == '+': |
457 | if share_with_other_side: |
458 | - traits.other_side.setFlag(message, True) |
459 | + helper.other_side.setFlag(message, True) |
460 | else: |
461 | raise AssertionError( |
462 | "Bad character in decision string: %s" % character) |
463 | @@ -1244,7 +1212,7 @@ |
464 | if decisions == '': |
465 | message = twin |
466 | |
467 | - traits.setFlag(message, True) |
468 | + helper.setFlag(message, True) |
469 | |
470 | return message |
471 | |
472 | @@ -1263,7 +1231,7 @@ |
473 | current.is_current_ubuntu = False |
474 | # Converge the current translation only if it is diverged and not |
475 | # current upstream. |
476 | - is_diverged = current.potemplate is not None |
477 | + is_diverged = current.potemplate is not None |
478 | if is_diverged and not current.is_current_upstream: |
479 | current.potemplate = None |
480 | pofile.date_changed = UTC_NOW |
481 | @@ -1494,4 +1462,3 @@ |
482 | """See `IPOTMsgSet`.""" |
483 | return TranslationTemplateItem.selectBy( |
484 | potmsgset=self, orderBy=['id']) |
485 | - |
486 | |
487 | === added file 'lib/lp/translations/model/side.py' |
488 | --- lib/lp/translations/model/side.py 1970-01-01 00:00:00 +0000 |
489 | +++ lib/lp/translations/model/side.py 2010-08-06 07:43:48 +0000 |
490 | @@ -0,0 +1,79 @@ |
491 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
492 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
493 | + |
494 | +"""`TranslationSideTraits` implementations.""" |
495 | + |
496 | +__metaclass__ = type |
497 | +__all__ = [ |
498 | + 'TranslationSideTraits', |
499 | + 'TranslationSideTraitsSet', |
500 | + ] |
501 | + |
502 | +from zope.interface import implements |
503 | + |
504 | +from lp.translations.interfaces.side import ( |
505 | + ITranslationSideTraits, |
506 | + ITranslationSideTraitsSet, |
507 | + TranslationSide) |
508 | + |
509 | + |
510 | +class TranslationSideTraits: |
511 | + """See `ITranslationSideTraits`.""" |
512 | + implements(ITranslationSideTraits) |
513 | + |
514 | + def __init__(self, side, flag_name): |
515 | + self.side = side |
516 | + self.other_side_traits = None |
517 | + self.flag_name = flag_name |
518 | + |
519 | + def getFlag(self, translationmessage): |
520 | + """See `ITranslationSideTraits`.""" |
521 | + return getattr(translationmessage, self.flag_name) |
522 | + |
523 | + def getCurrentMessage(self, potmsgset, potemplate, language): |
524 | + """See `ITranslationSideTraits`.""" |
525 | + if self.side == TranslationSide.UPSTREAM: |
526 | + return potmsgset.getImportedTranslationMessage( |
527 | + potemplate, language) |
528 | + else: |
529 | + return potmsgset.getCurrentTranslationMessage( |
530 | + potemplate, language) |
531 | + |
532 | + def setFlag(self, translationmessage, value): |
533 | + """See `ITranslationSideTraits`.""" |
534 | + if self.side == TranslationSide.UPSTREAM: |
535 | + translationmessage.makeCurrentUpstream(value) |
536 | + else: |
537 | + translationmessage.makeCurrentUbuntu(value) |
538 | + |
539 | + |
540 | +class TranslationSideTraitsSet: |
541 | + """See `ITranslationSideTraitsSet`.""" |
542 | + implements(ITranslationSideTraitsSet) |
543 | + |
544 | + def __init__(self): |
545 | + upstream = TranslationSideTraits( |
546 | + TranslationSide.UPSTREAM, 'is_current_upstream') |
547 | + ubuntu = TranslationSideTraits( |
548 | + TranslationSide.UBUNTU, 'is_current_ubuntu') |
549 | + ubuntu.other_side_traits = upstream |
550 | + upstream.other_side_traits = ubuntu |
551 | + self.traits = dict( |
552 | + (traits.side, traits) |
553 | + for traits in [ubuntu, upstream]) |
554 | + |
555 | + def getTraits(self, side): |
556 | + """See `ITranslationSideTraitsSet`.""" |
557 | + return self.traits[side] |
558 | + |
559 | + def getForTemplate(self, potemplate): |
560 | + """See `ITranslationSideTraitsSet`.""" |
561 | + if potemplate.productseries is not None: |
562 | + side = TranslationSide.UPSTREAM |
563 | + else: |
564 | + side = TranslationSide.UBUNTU |
565 | + return self.getTraits(side) |
566 | + |
567 | + def getAllTraits(self): |
568 | + """See `ITranslationSideTraitsSet`.""" |
569 | + return self.traits |
570 | |
571 | === modified file 'lib/lp/translations/model/translationmessage.py' |
572 | --- lib/lp/translations/model/translationmessage.py 2010-08-04 11:00:51 +0000 |
573 | +++ lib/lp/translations/model/translationmessage.py 2010-08-06 07:43:48 +0000 |
574 | @@ -161,11 +161,16 @@ |
575 | return |
576 | |
577 | def makeCurrentUbuntu(self, new_value=True): |
578 | + """See `ITranslationMessage`.""" |
579 | self.is_current_ubuntu = new_value |
580 | |
581 | def makeCurrentUpstream(self, new_value=True): |
582 | + """See `ITranslationMessage`.""" |
583 | self.is_current_upstream = new_value |
584 | |
585 | + def shareIfPossible(self): |
586 | + """See `ITranslationMessage`.""" |
587 | + |
588 | |
589 | class TranslationMessage(SQLBase, TranslationMessageMixIn): |
590 | implements(ITranslationMessage) |
591 | @@ -350,12 +355,7 @@ |
592 | return Store.of(self).find(TranslationMessage, where_clause).one() |
593 | |
594 | def shareIfPossible(self): |
595 | - """Make this message shared, if possible. |
596 | - |
597 | - If there is already a similar message that is shared, this |
598 | - message's information is merged into that of the existing one, |
599 | - and self is deleted. |
600 | - """ |
601 | + """See `ITranslationMessage`.""" |
602 | if self.potemplate is None: |
603 | # Already converged. |
604 | return |
605 | @@ -458,7 +458,6 @@ |
606 | self.is_current_upstream = new_value |
607 | |
608 | |
609 | - |
610 | class TranslationMessageSet: |
611 | """See `ITranslationMessageSet`.""" |
612 | implements(ITranslationMessageSet) |
613 | |
614 | === modified file 'lib/lp/translations/tests/test_potmsgset.py' |
615 | --- lib/lp/translations/tests/test_potmsgset.py 2010-07-27 11:31:46 +0000 |
616 | +++ lib/lp/translations/tests/test_potmsgset.py 2010-08-06 07:43:48 +0000 |
617 | @@ -24,32 +24,32 @@ |
618 | TranslationFileFormat) |
619 | from lp.translations.interfaces.translationmessage import ( |
620 | RosettaTranslationOrigin, TranslationConflict) |
621 | -from lp.translations.interfaces.translations import TranslationSide |
622 | -from lp.translations.model.potmsgset import ( |
623 | - make_translation_side_message_traits) |
624 | +from lp.translations.interfaces.side import TranslationSide |
625 | +from lp.translations.model.potmsgset import make_message_side_helpers |
626 | from lp.translations.model.translationmessage import ( |
627 | DummyTranslationMessage) |
628 | |
629 | from lp.testing import TestCaseWithFactory |
630 | -from canonical.testing import ZopelessDatabaseLayer |
631 | +from canonical.testing import DatabaseFunctionalLayer, ZopelessDatabaseLayer |
632 | |
633 | |
634 | class TestTranslationSharedPOTMsgSets(TestCaseWithFactory): |
635 | """Test discovery of translation suggestions.""" |
636 | |
637 | - layer = ZopelessDatabaseLayer |
638 | + layer = DatabaseFunctionalLayer |
639 | |
640 | def setUp(self): |
641 | """Set up context to test in.""" |
642 | # Create a product with two series and a shared POTemplate |
643 | # in different series ('devel' and 'stable'). |
644 | - super(TestTranslationSharedPOTMsgSets, self).setUp() |
645 | + super(TestTranslationSharedPOTMsgSets, self).setUp( |
646 | + 'carlos@canonical.com') |
647 | self.foo = self.factory.makeProduct() |
648 | self.foo_devel = self.factory.makeProductSeries( |
649 | name='devel', product=self.foo) |
650 | self.foo_stable = self.factory.makeProductSeries( |
651 | name='stable', product=self.foo) |
652 | - self.foo.official_rosetta = True |
653 | + removeSecurityProxy(self.foo).official_rosetta = True |
654 | |
655 | # POTemplate is 'shared' if it has the same name ('messages'). |
656 | self.devel_potemplate = self.factory.makePOTemplate( |
657 | @@ -154,8 +154,7 @@ |
658 | # is not used as a singular_text. |
659 | translation = self.factory.makeTranslationMessage( |
660 | pofile=en_pofile, potmsgset=potmsgset, |
661 | - translations=[DIVERGED_ENGLISH_STRING]) |
662 | - translation.potemplate = self.devel_potemplate |
663 | + translations=[DIVERGED_ENGLISH_STRING], force_diverged=True) |
664 | self.assertEquals(potmsgset.singular_text, ENGLISH_STRING) |
665 | |
666 | def test_getCurrentDummyTranslationMessage(self): |
667 | @@ -324,7 +323,8 @@ |
668 | # Create an external POTemplate with a POTMsgSet using |
669 | # the same English string as the one in self.potmsgset. |
670 | external_template = self.factory.makePOTemplate() |
671 | - external_template.productseries.product.official_rosetta = True |
672 | + product = external_template.productseries.product |
673 | + removeSecurityProxy(product).official_rosetta = True |
674 | external_potmsgset = self.factory.makePOTMsgSet( |
675 | external_template, |
676 | singular=self.potmsgset.singular_text) |
677 | @@ -357,7 +357,7 @@ |
678 | imported_translation = self.factory.makeSharedTranslationMessage( |
679 | pofile=external_pofile, potmsgset=external_potmsgset, |
680 | suggestion=False, is_current_upstream=True) |
681 | - imported_translation.is_current_ubuntu = False |
682 | + imported_translation.makeCurrentUbuntu(False) |
683 | |
684 | transaction.commit() |
685 | |
686 | @@ -383,7 +383,8 @@ |
687 | # Create an external POTemplate with a POTMsgSet using |
688 | # the same English string as the one in self.potmsgset. |
689 | external_template = self.factory.makePOTemplate() |
690 | - external_template.productseries.product.official_rosetta = True |
691 | + product = external_template.productseries.product |
692 | + removeSecurityProxy(product).official_rosetta = True |
693 | external_potmsgset = self.factory.makePOTMsgSet( |
694 | external_template, |
695 | singular=self.potmsgset.singular_text) |
696 | @@ -416,7 +417,7 @@ |
697 | imported_translation = self.factory.makeSharedTranslationMessage( |
698 | pofile=external_pofile, potmsgset=external_potmsgset, |
699 | suggestion=False, is_current_upstream=True) |
700 | - imported_translation.is_current_ubuntu = False |
701 | + imported_translation.makeCurrentUbuntu(False) |
702 | |
703 | transaction.commit() |
704 | |
705 | @@ -460,7 +461,7 @@ |
706 | |
707 | # If the current upstream translation is also current in Ubuntu, |
708 | # it's not changed in Ubuntu. |
709 | - current_shared.is_current_ubuntu = False |
710 | + current_shared.makeCurrentUbuntu(False) |
711 | imported_shared = self.factory.makeSharedTranslationMessage( |
712 | pofile=sr_pofile, potmsgset=self.potmsgset, |
713 | is_current_upstream=True) |
714 | @@ -471,7 +472,7 @@ |
715 | |
716 | # If there's a current, diverged translation, and an imported |
717 | # non-current one, it's changed in Ubuntu. |
718 | - imported_shared.is_current_ubuntu = False |
719 | + imported_shared.makeCurrentUbuntu(False) |
720 | current_diverged = self.factory.makeTranslationMessage( |
721 | pofile=sr_pofile, potmsgset=self.potmsgset, |
722 | is_current_upstream=False) |
723 | @@ -482,7 +483,7 @@ |
724 | |
725 | # If the upstream one is shared and used in Ubuntu, yet there is |
726 | # a diverged Ubuntu translation as well, it is changed in Ubuntu. |
727 | - imported_shared.is_current_ubuntu = False |
728 | + imported_shared.makeCurrentUbuntu(False) |
729 | self.assertEquals( |
730 | self.potmsgset.hasTranslationChangedInLaunchpad( |
731 | self.devel_potemplate, serbian), |
732 | @@ -688,8 +689,8 @@ |
733 | potemplate, es_pofile.language) |
734 | # Let's make sure this message is also marked as imported |
735 | # and diverged. |
736 | - es_current.is_current_upstream = True |
737 | - es_current.potemplate = potemplate |
738 | + es_current.makeCurrentUpstream(True) |
739 | + removeSecurityProxy(es_current).potemplate = potemplate |
740 | |
741 | self.assertTrue(es_current.is_current_ubuntu) |
742 | self.assertNotEqual(None, es_current.potemplate) |
743 | @@ -720,13 +721,19 @@ |
744 | class TestPOTMsgSetSuggestions(TestCaseWithFactory): |
745 | """Test retrieval and dismissal of translation suggestions.""" |
746 | |
747 | - layer = ZopelessDatabaseLayer |
748 | + layer = DatabaseFunctionalLayer |
749 | |
750 | def _setDateCreated(self, tm): |
751 | removeSecurityProxy(tm).date_created = self.now() |
752 | |
753 | def _setDateReviewed(self, tm): |
754 | - removeSecurityProxy(tm).date_reviewed = self.now() |
755 | + naked_tm = removeSecurityProxy(tm) |
756 | + if naked_tm.reviewer is None: |
757 | + naked_tm.reviewer = self.factory.makePerson() |
758 | + naked_tm.date_reviewed = self.now() |
759 | + |
760 | + def _setDateUpdated(self, tm): |
761 | + removeSecurityProxy(tm).date_updated = self.now() |
762 | |
763 | def gen_now(self): |
764 | now = datetime.now(pytz.UTC) |
765 | @@ -737,12 +744,12 @@ |
766 | def setUp(self): |
767 | # Create a product with all the boilerplate objects to be able to |
768 | # create TranslationMessage objects. |
769 | - super(TestPOTMsgSetSuggestions, self).setUp() |
770 | + super(TestPOTMsgSetSuggestions, self).setUp('carlos@canonical.com') |
771 | self.now = self.gen_now().next |
772 | self.foo = self.factory.makeProduct() |
773 | self.foo_main = self.factory.makeProductSeries( |
774 | name='main', product=self.foo) |
775 | - self.foo.official_rosetta = True |
776 | + removeSecurityProxy(self.foo).official_rosetta = True |
777 | |
778 | self.potemplate = self.factory.makePOTemplate( |
779 | productseries=self.foo_main, name="messages") |
780 | @@ -752,14 +759,17 @@ |
781 | # Set up some translation messages with dummy timestamps that will be |
782 | # changed in the tests. |
783 | self.translation = self.factory.makeTranslationMessage( |
784 | - self.pofile, self.potmsgset, translations=[u'trans1'], |
785 | - reviewer=self.factory.makePerson(), date_updated=self.now()) |
786 | + removeSecurityProxy(self.pofile), self.potmsgset, |
787 | + translations=[u'trans1'], reviewer=self.factory.makePerson(), |
788 | + is_current_upstream=True, date_updated=self.now()) |
789 | self.suggestion1 = self.factory.makeTranslationMessage( |
790 | self.pofile, self.potmsgset, suggestion=True, |
791 | - translations=[u'sugg1'], date_updated=self.now()) |
792 | + translations=[u'sugg1'], reviewer=self.factory.makePerson(), |
793 | + date_updated=self.now()) |
794 | self.suggestion2 = self.factory.makeTranslationMessage( |
795 | self.pofile, self.potmsgset, suggestion=True, |
796 | translations=[u'sugg2'], date_updated=self.now()) |
797 | + self._setDateCreated(self.suggestion2) |
798 | |
799 | def test_dismiss_all(self): |
800 | # Set order of creation and review. |
801 | @@ -841,7 +851,8 @@ |
802 | transaction.commit() |
803 | # Make the translation a suggestion, too. |
804 | suggestion3 = self.translation |
805 | - suggestion3.is_current_ubuntu = False |
806 | + suggestion3.makeCurrentUbuntu(False) |
807 | + suggestion3.makeCurrentUpstream(False) |
808 | self._setDateCreated(suggestion3) |
809 | transaction.commit() |
810 | # All suggestions are visible. |
811 | @@ -914,7 +925,7 @@ |
812 | class TestPOTMsgSetResetTranslation(TestCaseWithFactory): |
813 | """Test resetting the current translation.""" |
814 | |
815 | - layer = ZopelessDatabaseLayer |
816 | + layer = DatabaseFunctionalLayer |
817 | |
818 | def gen_now(self): |
819 | now = datetime.now(pytz.UTC) |
820 | @@ -925,12 +936,13 @@ |
821 | def setUp(self): |
822 | # Create a product with all the boilerplate objects to be able to |
823 | # create TranslationMessage objects. |
824 | - super(TestPOTMsgSetResetTranslation, self).setUp() |
825 | + super(TestPOTMsgSetResetTranslation, self).setUp( |
826 | + 'carlos@canonical.com') |
827 | self.now = self.gen_now().next |
828 | self.foo = self.factory.makeProduct() |
829 | self.foo_main = self.factory.makeProductSeries( |
830 | name='main', product=self.foo) |
831 | - self.foo.official_rosetta = True |
832 | + removeSecurityProxy(self.foo).official_rosetta = True |
833 | |
834 | self.potemplate = self.factory.makePOTemplate( |
835 | productseries=self.foo_main, name="messages") |
836 | @@ -997,7 +1009,7 @@ |
837 | class TestPOTMsgSetCornerCases(TestCaseWithFactory): |
838 | """Test corner cases and constraints.""" |
839 | |
840 | - layer = ZopelessDatabaseLayer |
841 | + layer = DatabaseFunctionalLayer |
842 | |
843 | def gen_now(self): |
844 | now = datetime.now(pytz.UTC) |
845 | @@ -1009,7 +1021,7 @@ |
846 | """Set up context to test in.""" |
847 | # Create a product with two series and a shared POTemplate |
848 | # in different series ('devel' and 'stable'). |
849 | - super(TestPOTMsgSetCornerCases, self).setUp() |
850 | + super(TestPOTMsgSetCornerCases, self).setUp('carlos@canonical.com') |
851 | |
852 | self.pofile = self.factory.makePOFile('sr') |
853 | self.potemplate = self.pofile.potemplate |
854 | @@ -1126,12 +1138,11 @@ |
855 | tm1 = self.potmsgset.updateTranslation( |
856 | self.pofile, self.uploader, [u"tm1"], lock_timestamp=self.now(), |
857 | is_current_upstream=True, force_shared=True) |
858 | + self.assertTrue(tm1.is_current_ubuntu) |
859 | tm2 = self.potmsgset.updateTranslation( |
860 | self.pofile, self.uploader, [u"tm2"], lock_timestamp=self.now(), |
861 | is_current_upstream=True, force_diverged=True) |
862 | - tm2.is_current_ubuntu = False |
863 | - self.assertTrue(tm1.is_current_ubuntu) |
864 | - self.assertFalse(tm2.is_current_ubuntu) |
865 | + tm2.makeCurrentUbuntu(False) |
866 | |
867 | self.potmsgset.updateTranslation( |
868 | self.pofile, self.uploader, [u"tm1"], lock_timestamp=self.now(), |
869 | @@ -1184,7 +1195,7 @@ |
870 | tm2 = self.potmsgset.updateTranslation( |
871 | self.pofile, self.uploader, [u"tm2"], lock_timestamp=self.now(), |
872 | is_current_upstream=True, force_diverged=True) |
873 | - tm2.is_current_ubuntu = False |
874 | + tm2.makeCurrentUbuntu(False) |
875 | |
876 | self.assertEquals(None, tm1.potemplate) |
877 | self.assertEquals(self.pofile.potemplate, tm2.potemplate) |
878 | @@ -1249,10 +1260,11 @@ |
879 | class TestPOTMsgSetTranslationCredits(TestCaseWithFactory): |
880 | """Test methods related to TranslationCredits.""" |
881 | |
882 | - layer = ZopelessDatabaseLayer |
883 | + layer = DatabaseFunctionalLayer |
884 | |
885 | def setUp(self): |
886 | - super(TestPOTMsgSetTranslationCredits, self).setUp() |
887 | + super(TestPOTMsgSetTranslationCredits, self).setUp( |
888 | + 'carlos@canonical.com') |
889 | self.potemplate = self.factory.makePOTemplate() |
890 | |
891 | def test_creation_credits(self): |
892 | @@ -1368,10 +1380,8 @@ |
893 | """Set up `KarmaRecorder` on `pofile`.""" |
894 | template = pofile.potemplate |
895 | return self.installKarmaRecorder( |
896 | - person=template.owner, |
897 | - action_name='translationsuggestionadded', |
898 | - product=template.product, |
899 | - distribution=template.distribution, |
900 | + person=template.owner, action_name='translationsuggestionadded', |
901 | + product=template.product, distribution=template.distribution, |
902 | sourcepackagename=template.sourcepackagename) |
903 | |
904 | def test_new_suggestion(self): |
905 | @@ -1571,7 +1581,10 @@ |
906 | |
907 | |
908 | class TestSetCurrentTranslation(TestCaseWithFactory): |
909 | - layer = ZopelessDatabaseLayer |
910 | + layer = DatabaseFunctionalLayer |
911 | + |
912 | + def setUp(self): |
913 | + super(TestSetCurrentTranslation, self).setUp('carlos@canonical.com') |
914 | |
915 | def _makePOFileAndPOTMsgSet(self): |
916 | pofile = self.factory.makePOFile('nl') |
917 | @@ -1599,62 +1612,62 @@ |
918 | pofile.potemplate, pofile.language)) |
919 | self.assertEqual(origin, message.origin) |
920 | |
921 | - def test_make_translation_side_message_traits(self): |
922 | - # make_translation_side_message_traits is a factory for traits |
923 | - # objects that help setCurrentTranslations deal with the |
924 | - # dichotomy between upstream and Ubuntu translations. |
925 | + def test_make_message_side_helpers(self): |
926 | + # make_message_side_helpers is a factory for helpers that help |
927 | + # setCurrentTranslations deal with the dichotomy between |
928 | + # upstream and Ubuntu translations. |
929 | pofile, potmsgset = self._makePOFileAndPOTMsgSet() |
930 | sides = (TranslationSide.UPSTREAM, TranslationSide.UBUNTU) |
931 | for side in sides: |
932 | - traits = make_translation_side_message_traits( |
933 | + helper = make_message_side_helpers( |
934 | side, potmsgset, pofile.potemplate, pofile.language) |
935 | - self.assertEqual(side, traits.side) |
936 | - self.assertNotEqual(side, traits.other_side.side) |
937 | - self.assertIn(traits.other_side.side, sides) |
938 | - self.assertIs(traits, traits.other_side.other_side) |
939 | + self.assertEqual(side, helper.traits.side) |
940 | + self.assertNotEqual(side, helper.other_side.traits.side) |
941 | + self.assertIn(helper.other_side.traits.side, sides) |
942 | + self.assertIs(helper, helper.other_side.other_side) |
943 | |
944 | def test_UpstreamSideTraits_upstream(self): |
945 | pofile, potmsgset = self._makePOFileAndPOTMsgSet() |
946 | message = self.factory.makeTranslationMessage( |
947 | pofile=pofile, potmsgset=potmsgset) |
948 | |
949 | - traits = make_translation_side_message_traits( |
950 | + helper = make_message_side_helpers( |
951 | TranslationSide.UPSTREAM, potmsgset, pofile.potemplate, |
952 | pofile.language) |
953 | |
954 | - self.assertEqual('is_current_upstream', traits.flag_name) |
955 | + self.assertEqual('is_current_upstream', helper.traits.flag_name) |
956 | |
957 | - self.assertFalse(traits.getFlag(message)) |
958 | + self.assertFalse(helper.traits.getFlag(message)) |
959 | self.assertFalse(message.is_current_upstream) |
960 | - self.assertEquals(None, traits.incumbent_message) |
961 | - |
962 | - traits.setFlag(message, True) |
963 | - |
964 | - self.assertTrue(traits.getFlag(message)) |
965 | + self.assertEquals(None, helper.incumbent_message) |
966 | + |
967 | + helper.setFlag(message, True) |
968 | + |
969 | + self.assertTrue(helper.traits.getFlag(message)) |
970 | self.assertTrue(message.is_current_upstream) |
971 | - self.assertEquals(message, traits.incumbent_message) |
972 | + self.assertEquals(message, helper.incumbent_message) |
973 | |
974 | def test_UpstreamSideTraits_ubuntu(self): |
975 | pofile, potmsgset = self._makePOFileAndPOTMsgSet() |
976 | message = self.factory.makeTranslationMessage( |
977 | pofile=pofile, potmsgset=potmsgset) |
978 | - message.is_current_ubuntu = False |
979 | + message.makeCurrentUbuntu(False) |
980 | |
981 | - traits = make_translation_side_message_traits( |
982 | + helper = make_message_side_helpers( |
983 | TranslationSide.UBUNTU, potmsgset, pofile.potemplate, |
984 | pofile.language) |
985 | |
986 | - self.assertEqual('is_current_ubuntu', traits.flag_name) |
987 | + self.assertEqual('is_current_ubuntu', helper.traits.flag_name) |
988 | |
989 | - self.assertFalse(traits.getFlag(message)) |
990 | + self.assertFalse(helper.traits.getFlag(message)) |
991 | self.assertFalse(message.is_current_ubuntu) |
992 | - self.assertEquals(None, traits.incumbent_message) |
993 | - |
994 | - traits.setFlag(message, True) |
995 | - |
996 | - self.assertTrue(traits.getFlag(message)) |
997 | + self.assertEquals(None, helper.incumbent_message) |
998 | + |
999 | + helper.setFlag(message, True) |
1000 | + |
1001 | + self.assertTrue(helper.traits.getFlag(message)) |
1002 | self.assertTrue(message.is_current_ubuntu) |
1003 | - self.assertEquals(message, traits.incumbent_message) |
1004 | + self.assertEquals(message, helper.incumbent_message) |
1005 | |
1006 | def test_identical(self): |
1007 | # Setting the same message twice leaves the original as-is. |
1008 | |
1009 | === modified file 'lib/lp/translations/tests/test_setcurrenttranslation.py' |
1010 | --- lib/lp/translations/tests/test_setcurrenttranslation.py 2010-07-06 09:27:37 +0000 |
1011 | +++ lib/lp/translations/tests/test_setcurrenttranslation.py 2010-08-06 07:43:48 +0000 |
1012 | @@ -13,8 +13,7 @@ |
1013 | from lp.testing import TestCaseWithFactory |
1014 | from lp.translations.interfaces.translationmessage import ( |
1015 | RosettaTranslationOrigin) |
1016 | -from lp.translations.interfaces.translations import ( |
1017 | - TranslationSide) |
1018 | +from lp.translations.interfaces.side import TranslationSide |
1019 | from lp.translations.model.translationmessage import ( |
1020 | TranslationMessage) |
1021 | |
1022 | @@ -87,7 +86,8 @@ |
1023 | * current: represents a current shared translation for this context. |
1024 | * diverged: represents a diverged translation for this context. |
1025 | * other_shared: represents a shared translation for "other" context. |
1026 | - * divergences_elsewhere: a list of other divergences in both contexts. |
1027 | + * divergences_elsewhere: a list of other divergences in both |
1028 | + contexts. |
1029 | """ |
1030 | new_current, new_diverged, new_other, new_divergences = ( |
1031 | summarize_current_translations(self.pofile, self.potmsgset)) |
1032 | |
1033 | === added file 'lib/lp/translations/tests/test_side.py' |
1034 | --- lib/lp/translations/tests/test_side.py 1970-01-01 00:00:00 +0000 |
1035 | +++ lib/lp/translations/tests/test_side.py 2010-08-06 07:43:48 +0000 |
1036 | @@ -0,0 +1,186 @@ |
1037 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
1038 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
1039 | + |
1040 | +"""Test `TranslationSide` and friends.""" |
1041 | + |
1042 | +__metaclass__ = type |
1043 | + |
1044 | +from canonical.testing import DatabaseFunctionalLayer |
1045 | +from lp.testing import TestCaseWithFactory |
1046 | + |
1047 | +from zope.component import getUtility |
1048 | +from zope.interface.verify import verifyObject |
1049 | + |
1050 | +from lp.translations.interfaces.side import ( |
1051 | + ITranslationSideTraits, |
1052 | + ITranslationSideTraitsSet, |
1053 | + TranslationSide) |
1054 | + |
1055 | + |
1056 | +class TestTranslationSideTraitsSet(TestCaseWithFactory): |
1057 | + layer = DatabaseFunctionalLayer |
1058 | + |
1059 | + def test_baseline(self): |
1060 | + utility = getUtility(ITranslationSideTraitsSet) |
1061 | + self.assertTrue(verifyObject(ITranslationSideTraitsSet, utility)) |
1062 | + for traits in utility.getAllTraits().itervalues(): |
1063 | + self.assertTrue(verifyObject(ITranslationSideTraits, traits)) |
1064 | + |
1065 | + def test_other_sides(self): |
1066 | + utility = getUtility(ITranslationSideTraitsSet) |
1067 | + upstream = utility.getTraits(TranslationSide.UPSTREAM) |
1068 | + ubuntu = utility.getTraits(TranslationSide.UBUNTU) |
1069 | + |
1070 | + self.assertEqual(ubuntu, upstream.other_side_traits) |
1071 | + self.assertEqual(upstream, ubuntu.other_side_traits) |
1072 | + |
1073 | + def test_getTraits(self): |
1074 | + utility = getUtility(ITranslationSideTraitsSet) |
1075 | + for side in [TranslationSide.UPSTREAM, TranslationSide.UBUNTU]: |
1076 | + traits = utility.getTraits(side) |
1077 | + self.assertTrue(verifyObject(ITranslationSideTraits, traits)) |
1078 | + |
1079 | + def test_getForTemplate_upstream(self): |
1080 | + utility = getUtility(ITranslationSideTraitsSet) |
1081 | + productseries = self.factory.makeProductSeries() |
1082 | + template = self.factory.makePOTemplate(productseries=productseries) |
1083 | + traits = utility.getForTemplate(template) |
1084 | + self.assertEqual(TranslationSide.UPSTREAM, traits.side) |
1085 | + |
1086 | + def test_getForTemplate_ubuntu(self): |
1087 | + utility = getUtility(ITranslationSideTraitsSet) |
1088 | + package = self.factory.makeSourcePackage() |
1089 | + template = self.factory.makePOTemplate( |
1090 | + distroseries=package.distroseries, |
1091 | + sourcepackagename=package.sourcepackagename) |
1092 | + traits = utility.getForTemplate(template) |
1093 | + self.assertEqual(TranslationSide.UBUNTU, traits.side) |
1094 | + |
1095 | + def test_getAllTraits(self): |
1096 | + utility = getUtility(ITranslationSideTraitsSet) |
1097 | + traits_dict = utility.getAllTraits() |
1098 | + |
1099 | + self.assertContentEqual( |
1100 | + [TranslationSide.UPSTREAM, TranslationSide.UBUNTU], |
1101 | + traits_dict.keys()) |
1102 | + |
1103 | + for side, traits in traits_dict.iteritems(): |
1104 | + self.assertEqual(side, traits.side) |
1105 | + self.assertEqual(traits, utility.getTraits(side)) |
1106 | + |
1107 | + |
1108 | +class TraitsScenario: |
1109 | + """Tests that can be run on either the upstream or the Ubuntu side.""" |
1110 | + |
1111 | + def _makeTemplate(self): |
1112 | + """Create a template for the side being tested.""" |
1113 | + raise NotImplementedError() |
1114 | + |
1115 | + def _makeTemplateAndTranslationMessage(self): |
1116 | + """Create a POTemplate with a TranslationMessage. |
1117 | + |
1118 | + Creates a POFile and POTMsgSet along the way. |
1119 | + |
1120 | + The TranslationMessage will not be current. |
1121 | + """ |
1122 | + template = self._makeTemplate() |
1123 | + pofile = self.factory.makePOFile('nl', template) |
1124 | + potmsgset = self.factory.makePOTMsgSet(template, sequence=1) |
1125 | + translationmessage = potmsgset.submitSuggestion( |
1126 | + pofile, self.factory.makePerson(), |
1127 | + [self.factory.getUniqueString()]) |
1128 | + return template, translationmessage |
1129 | + |
1130 | + def _getTraits(self, template): |
1131 | + """Shortcut: get TranslationSideTraits for template.""" |
1132 | + return getUtility(ITranslationSideTraitsSet).getForTemplate(template) |
1133 | + |
1134 | + def test_getFlag_and_setFlag(self): |
1135 | + template, message = self._makeTemplateAndTranslationMessage() |
1136 | + traits = self._getTraits(template) |
1137 | + other_side_traits = traits.other_side_traits |
1138 | + |
1139 | + traits.setFlag(message, True) |
1140 | + |
1141 | + self.assertEqual( |
1142 | + (True, False), |
1143 | + (traits.getFlag(message), other_side_traits.getFlag(message))) |
1144 | + |
1145 | + traits.setFlag(message, False) |
1146 | + |
1147 | + self.assertEqual( |
1148 | + (False, False), |
1149 | + (traits.getFlag(message), other_side_traits.getFlag(message))) |
1150 | + |
1151 | + def test_getCurrentMessage(self): |
1152 | + template, message = self._makeTemplateAndTranslationMessage() |
1153 | + traits = self._getTraits(template) |
1154 | + |
1155 | + traits.setFlag(message, True) |
1156 | + |
1157 | + current_message = traits.getCurrentMessage( |
1158 | + message.potmsgset, template, message.language) |
1159 | + self.assertEqual(message, current_message) |
1160 | + |
1161 | + traits.setFlag(message, False) |
1162 | + |
1163 | + current_message = traits.getCurrentMessage( |
1164 | + message.potmsgset, template, message.language) |
1165 | + self.assertIs(None, current_message) |
1166 | + |
1167 | + def test_getCurrentMessage_ignores_other_flag(self): |
1168 | + template, message = self._makeTemplateAndTranslationMessage() |
1169 | + traits = self._getTraits(template) |
1170 | + other_side_traits = traits.other_side_traits |
1171 | + |
1172 | + other_side_traits.setFlag(message, True) |
1173 | + |
1174 | + current_message = traits.getCurrentMessage( |
1175 | + message.potmsgset, template, message.language) |
1176 | + self.assertIs(None, current_message) |
1177 | + |
1178 | + other_side_traits.setFlag(message, False) |
1179 | + |
1180 | + current_message = traits.getCurrentMessage( |
1181 | + message.potmsgset, template, message.language) |
1182 | + self.assertIs(None, current_message) |
1183 | + |
1184 | + |
1185 | +class UpstreamTranslationSideTraitsTest(TraitsScenario, TestCaseWithFactory): |
1186 | + """Run the TraitsScenario tests on the upstream side.""" |
1187 | + layer = DatabaseFunctionalLayer |
1188 | + |
1189 | + def _makeTemplate(self): |
1190 | + """See `TraitsScenario`.""" |
1191 | + return self.factory.makePOTemplate( |
1192 | + productseries=self.factory.makeProductSeries()) |
1193 | + |
1194 | + def test_getFlag_reads_upstream_flag(self): |
1195 | + # This test case looks on the upstream side. We're really |
1196 | + # working with the is_current_upstream flag underneath the |
1197 | + # traits interface. |
1198 | + template, message = self._makeTemplateAndTranslationMessage() |
1199 | + traits = self._getTraits(template) |
1200 | + traits.setFlag(message, True) |
1201 | + self.assertTrue(message.is_current_upstream) |
1202 | + |
1203 | + |
1204 | +class UbuntuTranslationSideTraitsTest(TraitsScenario, TestCaseWithFactory): |
1205 | + """Run the TraitsScenario tests on the Ubuntu side.""" |
1206 | + layer = DatabaseFunctionalLayer |
1207 | + |
1208 | + def _makeTemplate(self): |
1209 | + """See `TraitsScenario`.""" |
1210 | + package = self.factory.makeSourcePackage() |
1211 | + return self.factory.makePOTemplate( |
1212 | + distroseries=package.distroseries, |
1213 | + sourcepackagename=package.sourcepackagename) |
1214 | + |
1215 | + def test_getFlag_reads_ubuntu_flag(self): |
1216 | + # This test case looks on the Ubuntu side. We're really |
1217 | + # working with the is_current_ubuntu flag underneath the traits |
1218 | + # interface. |
1219 | + template, message = self._makeTemplateAndTranslationMessage() |
1220 | + traits = self._getTraits(template) |
1221 | + traits.setFlag(message, True) |
1222 | + self.assertTrue(message.is_current_ubuntu) |
Thanks for the traits! ;-)
I think they are a good idea but we will have to watch to keep them simple. We talked about the helper class that is left in here for historical reason and I would be glad to see it removed in another branch soon.
Other than that I didn't find any problems. ;-)