Merge lp:~jtv/launchpad/bug-403992 into lp:launchpad

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Brad Crittenden
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~jtv/launchpad/bug-403992
Merge into: lp:launchpad
Diff against target: None lines
To merge this branch: bzr merge lp:~jtv/launchpad/bug-403992
Reviewer Review Type Date Requested Status
Brad Crittenden (community) Approve
Review via email: mp+9690@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

= Bug 403992 =

This is a more complete fix for bug 403992 than the one I'm hoping to
cherrypick from lp:~jtv/launchpad/cp-bug-403992. You could see it as
all-part-of-the-service aftercare.

Besides the fix in that branch, this one adds some related improvements:

 * Make sure the database knows it's dirty after running the script in
   the doctest. It doesn't seem to change anything, but it's the right
   thing to do.

 * Cache some stuff in the script object, mostly so the identifiers get
   a bit shorter and the main code easier to read. A matter of taste,
   mostly.

 * When trying to diverge a shared message that can't be accommodated as
   shared on the representative potmsgset, try it on the most
   representative of the potemplates it participates in first, then the
   second-best, and so on. This is slightly more proper than sorting
   purely by id, although it probably doesn't matter too much.

 * Cull some now-dead methods and variables: current_tms, imported_tms,
   _findUsedMessages. And their unit tests, of course.

 * Make the unit tests' setUp pass test_args to the script object
   constructor. Otherwise the script would receive the arguments that
   the test driver (./bin/test) got on the command line. That _usually_
   isn't a problem, but when the test driver invokes itself recursively
   to run this test, it adds a --resume-layer argument which of course
   means nothing to the script object. This broke the unit tests in
   some combined test runs, but not in individual ones or more fortunate
   combinations.

To test,
{{{
./bin/test -vv -t message.sharing
}}}

To Q/A, run this on staging:
{{{
scripts/rosetta/message-sharing-merge -vvv -P -p elisa
}}}

No lint complaints.

Jeroen

Revision history for this message
Brad Crittenden (bac) wrote :
Download full text (17.4 KiB)

Hi Jeroen,

This branch is a nice clean up. I've got a few comments on style.

I'm curious also about your/Danilo's choice to re-open a bug that was
fix-committed to make these clean-up changes. Seems like an odd way
to handle it, but not really any of my concern here.

> === modified file 'lib/lp/translations/doc/message-sharing-merge-script.txt'
> --- lib/lp/translations/doc/message-sharing-merge-script.txt 2009-07-06 08:04:08 +0000
> +++ lib/lp/translations/doc/message-sharing-merge-script.txt 2009-08-04 13:37:57 +0000
> @@ -15,3 +15,10 @@
>
> >>> retcode
> 0
> +
> +
> +# The script modified the database, even though the database layer may
> +# not have noticed it.
> +
> + >>> from canonical.launchpad.ftests.harness import LaunchpadTestSetup
> + >>> LaunchpadTestSetup().force_dirty_database()

> === modified file 'lib/lp/translations/scripts/message_sharing_migration.py'
> --- lib/lp/translations/scripts/message_sharing_migration.py 2009-07-19 04:41:14 +0000
> +++ lib/lp/translations/scripts/message_sharing_migration.py 2009-08-05 11:44:49 +0000

Would you mind fixing the __all__ line to make it multi-line (is that our convention when there is just one entry?) or remove the extra spaces.

> @@ -8,8 +8,9 @@
> from zope.component import getUtility
> from zope.security.proxy import removeSecurityProxy
>
> +from canonical.launchpad.utilities.orderingcheck import OrderingCheck
> from lp.translations.interfaces.potemplate import IPOTemplateSet
> -from canonical.launchpad.utilities.orderingcheck import OrderingCheck
> +from lp.translations.interfaces.translations import TranslationConstants
> from lp.registry.interfaces.product import IProductSet
> from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
> from lp.services.scripts.base import (
> @@ -146,6 +147,8 @@
>
> class MessageSharingMerge(LaunchpadScript):
>
> + templateset = None

How about 'template_set' as it follows our coding standard?

> def add_my_options(self):
> self.parser.add_option('-d', '--distribution', dest='distribution',
> help="Distribution to merge messages for.")
> @@ -166,6 +169,16 @@
> action='store_true',
> help="Dry run, don't really make any changes.")
>
> + def _setUpUtilities(self):
> + """Prepare a few members that several methods need.
> +
> + Calling this again later does nothing.
> + """
> + if self.templateset is None:
> + self.templateset = getUtility(IPOTemplateSet)
> + self.compare_template_precedence = (
> + self.templateset.compareSharingPrecedence)
> +
> def main(self):
> actions = (
> self.options.merge_potmsgsets or
> @@ -214,7 +227,9 @@
> "Unknown source package name: '%s'" %
> self.options.sourcepackage)
>
> - subset = getUtility(IPOTemplateSet).getSharingSubset(
> + self._setUpUtilities()
> +
> + subset = self.templateset.getSharingSubset(
> product=product, distribution=distribution,
> sourcepackagename=sourcepackagename)
> equivalence...

review: Approve
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Hi Brad! Thanks for the review. This branch has been lying around for
a while, waiting for someone to review it. Unlike its cherry-pickable
sibling it's not urgent, but I'm glad to have it out of the way.

> I'm curious also about your/Danilo's choice to re-open a bug that was
> fix-committed to make these clean-up changes. Seems like an odd way
> to handle it, but not really any of my concern here.

I wouldn't say that was our "choice." What happened was that I prepared
two branches for the same problem: one immediate, absolutely minimal fix
for cherry-picking, and this conventional full fix as a superset of the
former. The cherry-picking branch has landed, and the bug went through
a brief tentative phase of being "fix committed" because of that. But
it all happened well after this branch here went up for review.

> > === modified file 'lib/lp/translations/scripts/message_sharing_migration.py'
> > --- lib/lp/translations/scripts/message_sharing_migration.py 2009-07-19
> 04:41:14 +0000
> > +++ lib/lp/translations/scripts/message_sharing_migration.py 2009-08-05
> 11:44:49 +0000
>
> Would you mind fixing the __all__ line to make it multi-line (is that our
> convention when there is just one entry?) or remove the extra spaces.

Don't mind at all. Done.

> > @@ -146,6 +147,8 @@
> >
> > class MessageSharingMerge(LaunchpadScript):
> >
> > + templateset = None
>
> How about 'template_set' as it follows our coding standard?

In English you never really know two words have become one until one of
them changes, like the "sheep" in "shepherd."

I think I chose "templateset" to distinguish the utility from a mere set
of templates. Then again, naming variables after their type should not
be taken this far anyway.

> > @@ -361,7 +370,13 @@
> > potmsgset (because we start out with one) and potemplate (because
> > that's sorted out in the nested dicts).
> > """
> > - return (tm.language, tm.variant) + tuple(tm.all_msgstrs)
> > + tm = removeSecurityProxy(tm)
> > + msgstr_ids = [
> > + getattr(tm, 'msgstr%dID' % form)
> > + for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)
> > + ]
>
> The ] should be dedented by 4.

Ah, my editor is showing a mind of its own. Can't have that.

Hi ho, hi ho, to PQM I go!

Jeroen

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/translations/doc/message-sharing-merge-script.txt'
--- lib/lp/translations/doc/message-sharing-merge-script.txt 2009-07-06 08:04:08 +0000
+++ lib/lp/translations/doc/message-sharing-merge-script.txt 2009-08-04 13:37:57 +0000
@@ -15,3 +15,10 @@
1515
16 >>> retcode16 >>> retcode
17 017 0
18
19
20# The script modified the database, even though the database layer may
21# not have noticed it.
22
23 >>> from canonical.launchpad.ftests.harness import LaunchpadTestSetup
24 >>> LaunchpadTestSetup().force_dirty_database()
1825
=== modified file 'lib/lp/translations/scripts/message_sharing_migration.py'
--- lib/lp/translations/scripts/message_sharing_migration.py 2009-07-19 04:41:14 +0000
+++ lib/lp/translations/scripts/message_sharing_migration.py 2009-08-05 11:44:49 +0000
@@ -8,8 +8,9 @@
8from zope.component import getUtility8from zope.component import getUtility
9from zope.security.proxy import removeSecurityProxy9from zope.security.proxy import removeSecurityProxy
1010
11from canonical.launchpad.utilities.orderingcheck import OrderingCheck
11from lp.translations.interfaces.potemplate import IPOTemplateSet12from lp.translations.interfaces.potemplate import IPOTemplateSet
12from canonical.launchpad.utilities.orderingcheck import OrderingCheck13from lp.translations.interfaces.translations import TranslationConstants
13from lp.registry.interfaces.product import IProductSet14from lp.registry.interfaces.product import IProductSet
14from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet15from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
15from lp.services.scripts.base import (16from lp.services.scripts.base import (
@@ -146,6 +147,8 @@
146147
147class MessageSharingMerge(LaunchpadScript):148class MessageSharingMerge(LaunchpadScript):
148149
150 templateset = None
151
149 def add_my_options(self):152 def add_my_options(self):
150 self.parser.add_option('-d', '--distribution', dest='distribution',153 self.parser.add_option('-d', '--distribution', dest='distribution',
151 help="Distribution to merge messages for.")154 help="Distribution to merge messages for.")
@@ -166,6 +169,16 @@
166 action='store_true',169 action='store_true',
167 help="Dry run, don't really make any changes.")170 help="Dry run, don't really make any changes.")
168171
172 def _setUpUtilities(self):
173 """Prepare a few members that several methods need.
174
175 Calling this again later does nothing.
176 """
177 if self.templateset is None:
178 self.templateset = getUtility(IPOTemplateSet)
179 self.compare_template_precedence = (
180 self.templateset.compareSharingPrecedence)
181
169 def main(self):182 def main(self):
170 actions = (183 actions = (
171 self.options.merge_potmsgsets or184 self.options.merge_potmsgsets or
@@ -214,7 +227,9 @@
214 "Unknown source package name: '%s'" %227 "Unknown source package name: '%s'" %
215 self.options.sourcepackage)228 self.options.sourcepackage)
216229
217 subset = getUtility(IPOTemplateSet).getSharingSubset(230 self._setUpUtilities()
231
232 subset = self.templateset.getSharingSubset(
218 product=product, distribution=distribution,233 product=product, distribution=distribution,
219 sourcepackagename=sourcepackagename)234 sourcepackagename=sourcepackagename)
220 equivalence_classes = subset.groupEquivalentPOTemplates(235 equivalence_classes = subset.groupEquivalentPOTemplates(
@@ -250,6 +265,7 @@
250265
251 def _mergePOTMsgSets(self, potemplates):266 def _mergePOTMsgSets(self, potemplates):
252 """Merge POTMsgSets for given sequence of sharing templates."""267 """Merge POTMsgSets for given sequence of sharing templates."""
268 self._setUpUtilities()
253269
254 # Map each POTMsgSet key (context, msgid, plural) to its270 # Map each POTMsgSet key (context, msgid, plural) to its
255 # representative POTMsgSet.271 # representative POTMsgSet.
@@ -267,8 +283,7 @@
267 # through the templates, starting at the most representative and283 # through the templates, starting at the most representative and
268 # moving towards the least representative. For any unique potmsgset284 # moving towards the least representative. For any unique potmsgset
269 # key we find, the first POTMsgSet is the representative one.285 # key we find, the first POTMsgSet is the representative one.
270 templateset = getUtility(IPOTemplateSet)286 order_check = OrderingCheck(cmp=self.compare_template_precedence)
271 order_check = OrderingCheck(cmp=templateset.compareSharingPrecedence)
272287
273 for template in potemplates:288 for template in potemplates:
274 order_check.check(template)289 order_check.check(template)
@@ -288,13 +303,7 @@
288 # translation messages. We don't need do this for subordinates303 # translation messages. We don't need do this for subordinates
289 # because the algorithm will refuse to add new duplicates to the304 # because the algorithm will refuse to add new duplicates to the
290 # representative POTMsgSet anyway.305 # representative POTMsgSet anyway.
291 existing_tms = self._scrubPOTMsgSetTranslations(representative)306 self._scrubPOTMsgSetTranslations(representative)
292
293 # Keep track of current/imported TranslationMessages for
294 # representative. These will matter when we try to merge
295 # subordinate TranslationMessages into the representative, some
296 # of which may be current or imported as well.
297 current_tms, imported_tms = self._findUsedMessages(existing_tms)
298307
299 seen_potmsgsets = set([representative])308 seen_potmsgsets = set([representative])
300309
@@ -309,8 +318,8 @@
309 message = removeSecurityProxy(message)318 message = removeSecurityProxy(message)
310319
311 clashing_current, clashing_imported, twin = (320 clashing_current, clashing_imported, twin = (
312 self._findClashesFromDicts(321 self._findClashes(
313 existing_tms, current_tms, imported_tms, message))322 message, representative, message.potemplate))
314323
315 if clashing_current or clashing_imported:324 if clashing_current or clashing_imported:
316 saved = self._saveByDiverging(325 saved = self._saveByDiverging(
@@ -345,8 +354,8 @@
345354
346 def _mergeTranslationMessages(self, potemplates):355 def _mergeTranslationMessages(self, potemplates):
347 """Share `TranslationMessage`s between templates where possible."""356 """Share `TranslationMessage`s between templates where possible."""
348 templateset = getUtility(IPOTemplateSet)357 self._setUpUtilities()
349 order_check = OrderingCheck(cmp=templateset.compareSharingPrecedence)358 order_check = OrderingCheck(cmp=self.compare_template_precedence)
350 for template in potemplates:359 for template in potemplates:
351 order_check.check(template)360 order_check.check(template)
352 for potmsgset in template.getPOTMsgSets(False):361 for potmsgset in template.getPOTMsgSets(False):
@@ -361,7 +370,13 @@
361 potmsgset (because we start out with one) and potemplate (because370 potmsgset (because we start out with one) and potemplate (because
362 that's sorted out in the nested dicts).371 that's sorted out in the nested dicts).
363 """372 """
364 return (tm.language, tm.variant) + tuple(tm.all_msgstrs)373 tm = removeSecurityProxy(tm)
374 msgstr_ids = [
375 getattr(tm, 'msgstr%dID' % form)
376 for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)
377 ]
378
379 return (tm.language, tm.variant) + tuple(msgstr_ids)
365380
366 def _mapExistingMessages(self, potmsgset):381 def _mapExistingMessages(self, potmsgset):
367 """Map out the existing TranslationMessages for `potmsgset`.382 """Map out the existing TranslationMessages for `potmsgset`.
@@ -387,33 +402,6 @@
387402
388 return existing_tms403 return existing_tms
389404
390 def _findUsedMessages(self, translations):
391 """Fish current and imported messages out of translations dict.
392
393 :param translations: a dict as returned by
394 `_mapExistingMessages` or `_scrubPOTMsgSetTranslations`. All
395 information is taken from this dict; no other messages are
396 considered.
397 :return: a pair of dicts, each mapping (potemplate, language,
398 variant) to a TranslationMessage or to None. The dicts map
399 out current and imported messages, respectively. Shared
400 messages have a POTemplate of None.
401 """
402 current_messages = {}
403 imported_messages = {}
404 for per_template in translations.itervalues():
405 for tms in per_template.itervalues():
406 assert len(tms) == 1, (
407 "Unexpected list size: %d items." % len(tms))
408 tm = tms[0]
409 key = (tm.potemplate, tm.language, tm.variant)
410 if tm.is_current:
411 current_messages[key] = tm
412 if tm.is_imported:
413 imported_messages[key] = tm
414
415 return current_messages, imported_messages
416
417 def _scrubPOTMsgSetTranslations(self, potmsgset):405 def _scrubPOTMsgSetTranslations(self, potmsgset):
418 """Map out translations for `potmsgset`, and eliminate duplicates.406 """Map out translations for `potmsgset`, and eliminate duplicates.
419407
@@ -487,41 +475,6 @@
487 # message can be merged into the twin without problems.475 # message can be merged into the twin without problems.
488 return filter_clashes(clashing_current, clashing_imported, twin)476 return filter_clashes(clashing_current, clashing_imported, twin)
489477
490 def _findClashesFromDicts(self, existing_tms, current_tms, imported_tms,
491 message):
492 """Like `_findClashes`, but from cached dicts.
493
494 This saves some database querying for the common case.
495
496 :param existing_tms: a dict as returned by
497 `_mapExistingMessages`.
498 :param current_tms: a dict as returned by `_findUsedMessages`.
499 """
500 twins_dict = existing_tms.get(
501 self._getPOTMsgSetTranslationMessageKey(message))
502 if twins_dict is None:
503 twin = None
504 else:
505 twins = twins_dict.get(message.potemplate)
506 if twins is None:
507 twin = None
508 else:
509 assert len(twins) == 1, "Did not expect %d twins." % (
510 len(twins))
511 twin = twins[0]
512
513 subkey = message.potemplate, message.language, message.variant
514 if message.is_current:
515 clashing_current = current_tms.get(subkey)
516 else:
517 clashing_current = None
518 if message.is_imported:
519 clashing_imported = imported_tms.get(subkey)
520 else:
521 clashing_imported = None
522
523 return filter_clashes(clashing_current, clashing_imported, twin)
524
525 def _saveByDiverging(self, message, target_potmsgset, source_potmsgset):478 def _saveByDiverging(self, message, target_potmsgset, source_potmsgset):
526 """Avoid a TranslationMessage clash during POTMsgSet merge.479 """Avoid a TranslationMessage clash during POTMsgSet merge.
527480
@@ -539,8 +492,10 @@
539 # This message was shared. Maybe we can still save it for at492 # This message was shared. Maybe we can still save it for at
540 # least one template by making it diverged.493 # least one template by making it diverged.
541 target_ttis = source_potmsgset.getAllTranslationTemplateItems()494 target_ttis = source_potmsgset.getAllTranslationTemplateItems()
542 for tti in target_ttis:495 target_templates = [tti.potemplate for tti in target_ttis]
543 if self._divergeTo(message, target_potmsgset, tti.potemplate):496 target_templates.sort(self.compare_template_precedence)
497 for template in target_templates:
498 if self._divergeTo(message, target_potmsgset, template):
544 return True499 return True
545500
546 # No, there's no place where this message can be preserved. It'll501 # No, there's no place where this message can be preserved. It'll
547502
=== modified file 'lib/lp/translations/scripts/tests/test_message_sharing_migration.py'
--- lib/lp/translations/scripts/tests/test_message_sharing_migration.py 2009-07-19 04:41:14 +0000
+++ lib/lp/translations/scripts/tests/test_message_sharing_migration.py 2009-08-05 11:44:49 +0000
@@ -41,7 +41,7 @@
41 self.stable_template.iscurrent = False41 self.stable_template.iscurrent = False
42 self.templates = [self.trunk_template, self.stable_template]42 self.templates = [self.trunk_template, self.stable_template]
4343
44 self.script = MessageSharingMerge('tms-merging-test')44 self.script = MessageSharingMerge('tms-merging-test', test_args=[])
45 self.script.logger.setLevel(ERROR)45 self.script.logger.setLevel(ERROR)
4646
4747
@@ -617,47 +617,6 @@
617617
618 self.assertEqual(map, expected)618 self.assertEqual(map, expected)
619619
620 def test_FindNoUsedMessage(self):
621 # Test _findUsedMessage against a case where there are no used
622 # messages.
623 message = self._makeTranslationMessage(
624 pofile=self.trunk_pofile, potmsgset=self.trunk_potmsgset,
625 text='godot', diverged=False)
626 message.is_current = False
627 key = self.script._getPOTMsgSetTranslationMessageKey(message)
628 map = {key: {self.trunk_template: [message]}}
629
630 self.assertEqual(self.script._findUsedMessages(map), ({}, {}))
631
632 def test_FindUsedMessages(self):
633 # _findUsedMessages maps diverged messages based on template,
634 # language, and variant. The difference for shared messages is
635 # that their template is None.
636 imported_message = self._makeTranslationMessage(
637 pofile=self.trunk_pofile, potmsgset=self.trunk_potmsgset,
638 text='pog', diverged=True)
639 imported_message.is_current = False
640 imported_message.is_imported = True
641 current_message = self._makeTranslationMessage(
642 pofile=self.trunk_pofile, potmsgset=self.trunk_potmsgset,
643 text='klexdigal', diverged=False)
644
645 current_key = self.script._getPOTMsgSetTranslationMessageKey(
646 current_message)
647 imported_key = self.script._getPOTMsgSetTranslationMessageKey(
648 imported_message)
649
650 map = {
651 current_key: {self.trunk_template: [current_message]},
652 imported_key: { self.trunk_template: [imported_message]},
653 }
654
655 expected = (
656 {(None, self.dutch, None): current_message},
657 {(self.trunk_template, self.dutch, None): imported_message})
658
659 self.assertEqual(self.script._findUsedMessages(map), expected)
660
661 def test_ScrubPOTMsgSetTranslationsWithoutDuplication(self):620 def test_ScrubPOTMsgSetTranslationsWithoutDuplication(self):
662 # _scrubPOTMsgSetTranslations eliminates duplicated621 # _scrubPOTMsgSetTranslations eliminates duplicated
663 # TranslationMessages. If it doesn't find any, nothing happens.622 # TranslationMessages. If it doesn't find any, nothing happens.
@@ -776,95 +735,6 @@
776 self.assertEqual(imported_clash, None)735 self.assertEqual(imported_clash, None)
777 self.assertEqual(twin, trunk_message)736 self.assertEqual(twin, trunk_message)
778737
779 def test_FindCurrentClashFromDicts(self):
780 # Like test_FindCurrentClash, but using cached dicts.
781 trunk_message, stable_message = self._makeTranslationMessages(
782 'ex', 'why', trunk_diverged=False, stable_diverged=False)
783
784 trunk_key = self.script._getPOTMsgSetTranslationMessageKey(
785 trunk_message)
786 stable_key = self.script._getPOTMsgSetTranslationMessageKey(
787 stable_message)
788
789 existing = self.script._mapExistingMessages(self.trunk_potmsgset)
790 current, imported = self.script._findUsedMessages(existing)
791 current_clash, imported_clash, twin = (
792 self.script._findClashesFromDicts(
793 existing, current, imported, stable_message))
794
795 self.assertEqual(current_clash, trunk_message)
796 self.assertEqual(imported_clash, None)
797 self.assertEqual(twin, None)
798
799
800 def test_FindImportedClashFromDicts(self):
801 # Like test_FindImportedClash, but using cached dicts.
802 trunk_message, stable_message = self._makeTranslationMessages(
803 'ex', 'why', trunk_diverged=False, stable_diverged=False)
804
805 for message in (trunk_message, stable_message):
806 message.is_current = False
807 message.is_imported = True
808
809 existing = self.script._mapExistingMessages(self.trunk_potmsgset)
810 current, imported = self.script._findUsedMessages(existing)
811 current_clash, imported_clash, twin = (
812 self.script._findClashesFromDicts(
813 existing, current, imported, stable_message))
814
815 self.assertEqual(current_clash, None)
816 self.assertEqual(imported_clash, trunk_message)
817 self.assertEqual(twin, None)
818
819 def test_FindTwinFromDicts(self):
820 # Like test_FindTwin, but using cached dicts.
821 trunk_message, stable_message = self._makeTranslationMessages(
822 'klob', 'klob', trunk_diverged=False, stable_diverged=False)
823 trunk_message.is_current = False
824
825 existing = self.script._mapExistingMessages(self.trunk_potmsgset)
826 current, imported = self.script._findUsedMessages(existing)
827 current_clash, imported_clash, twin = (
828 self.script._findClashesFromDicts(
829 existing, current, imported, stable_message))
830
831 self.assertEqual(current_clash, None)
832 self.assertEqual(imported_clash, None)
833 self.assertEqual(twin, trunk_message)
834
835 def test_FindClashesWithTwinFromDicts(self):
836 # Like test_FindClashesWithTwin, but using cached dicts.
837 trunk_message, stable_message = self._makeTranslationMessages(
838 'sniw', 'sniw', trunk_diverged=False, stable_diverged=False)
839
840 existing = self.script._mapExistingMessages(self.trunk_potmsgset)
841 current, imported = self.script._findUsedMessages(existing)
842 current_clash, imported_clash, twin = (
843 self.script._findClashesFromDicts(
844 existing, current, imported, stable_message))
845
846 self.assertEqual(current_clash, None)
847 self.assertEqual(imported_clash, None)
848 self.assertEqual(twin, trunk_message)
849
850 def test_FindClashesWithNonTwinFromDicts(self):
851 # Like test_FindClashesWithNonTwin, but using cached dicts.
852 trunk_message, stable_message = self._makeTranslationMessages(
853 'sniw', 'sniw', trunk_diverged=False, stable_diverged=False)
854 trunk_message.is_current = False
855 current_message = self._makeTranslationMessage(
856 self.trunk_pofile, self.trunk_potmsgset, 'gah', False)
857
858 existing = self.script._mapExistingMessages(self.trunk_potmsgset)
859 current, imported = self.script._findUsedMessages(existing)
860 current_clash, imported_clash, twin = (
861 self.script._findClashesFromDicts(
862 existing, current, imported, stable_message))
863
864 self.assertEqual(current_clash, current_message)
865 self.assertEqual(imported_clash, None)
866 self.assertEqual(twin, trunk_message)
867
868738
869def test_suite():739def test_suite():
870 return TestLoader().loadTestsFromName(__name__)740 return TestLoader().loadTestsFromName(__name__)