launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #01506
[Merge] lp:~jtv/launchpad/recife-pre-sharing-permissions into lp:~launchpad/launchpad/recife
Jeroen T. Vermeulen has proposed merging lp:~jtv/launchpad/recife-pre-sharing-permissions into lp:~launchpad/launchpad/recife.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers): code
= Cleanups prior to Recife sharing permissions checks =
This is a cleanup to be merged into the Recife feature branch.
I'm working on the part of the Recife model change where we check if a particular translation submission for Ubuntu should be shared with upstream, or vice versa. In my preparations I came across some things that needed cleaning up:
* The basic translation view checked far too many separate things in one big method.
* View failures generated some truly horrible error messages.
* Existing permissions checks needed breaking down into smaller chunks to be comprehensible.
* Some inefficient "do we know how plural forms work for this POFile" logic was also redundant.
* Reading of "lock_timestamp" was tested in a doctest instead of a view unit test.
* Lots and lots of trailing whitespace.
I sped up the inefficient logic by doing the cheapest (and often sufficient) test first, centralized it into a single method, and replaced the view properties that duplicated it with a single attribute.
To test, best run all Translations tests really:
{{{
./bin/test -vvc lp.translations
}}}
There's a bit of lint left, most related to comment blocks that aren't directly attached to their respective next lines. I think that style is valid where the comment applies to a section of a class, as these do, so I didn't touch these cases. The other source of lint is Moin-style headings in doctests, which I didn't touch in order to stay under the review limit.
Jeroen
--
https://code.launchpad.net/~jtv/launchpad/recife-pre-sharing-permissions/+merge/38407
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jtv/launchpad/recife-pre-sharing-permissions into lp:~launchpad/launchpad/recife.
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-10-05 17:06:23 +0000
+++ lib/lp/testing/factory.py 2010-10-14 11:26:43 +0000
@@ -1794,16 +1794,22 @@
MessageChunk(message=message, sequence=1, content=content)
return message
- def makeLanguage(self, language_code=None, name=None, pluralforms=None):
+ def makeLanguage(self, language_code=None, name=None, pluralforms=None,
+ plural_expression=None):
"""Makes a language given the language_code and name."""
if language_code is None:
language_code = self.getUniqueString('lang')
if name is None:
name = "Language %s" % language_code
+ if plural_expression is None and pluralforms is not None:
+ # If the number of plural forms is known, the language
+ # should also have a plural expression and vice versa.
+ plural_expression = 'n %% %d' % pluralforms
language_set = getUtility(ILanguageSet)
return language_set.createLanguage(
- language_code, name, pluralforms=pluralforms)
+ language_code, name, pluralforms=pluralforms,
+ pluralexpression=plural_expression)
def makeLibraryFileAlias(self, filename=None, content=None,
content_type='text/plain', restricted=False,
=== modified file 'lib/lp/testing/tests/test_factory.py'
--- lib/lp/testing/tests/test_factory.py 2010-09-30 17:57:01 +0000
+++ lib/lp/testing/tests/test_factory.py 2010-10-14 11:26:43 +0000
@@ -431,6 +431,14 @@
for number_of_forms in [None, 1, 3]:
language = self.factory.makeLanguage(pluralforms=number_of_forms)
self.assertEqual(number_of_forms, language.pluralforms)
+ self.assertEqual(
+ number_of_forms is None, language.pluralexpression is None)
+
+ def test_makeLanguage_with_plural_expression(self):
+ expression = '(n+1) % 5'
+ language = self.factory.makeLanguage(
+ pluralforms=5, plural_expression=expression)
+ self.assertEqual(expression, language.pluralexpression)
# makeSourcePackagePublishingHistory
def test_makeSourcePackagePublishingHistory_returns_ISPPH(self):
=== modified file 'lib/lp/translations/browser/pofile.py'
--- lib/lp/translations/browser/pofile.py 2010-09-06 10:40:54 +0000
+++ lib/lp/translations/browser/pofile.py 2010-10-14 11:26:43 +0000
@@ -364,15 +364,6 @@
return statement
@property
- def has_plural_form_information(self):
- """Return whether we know the plural forms for this language."""
- if self.context.potemplate.hasPluralMessage():
- return self.context.language.pluralforms is not None
- # If there are no plural forms, we assume that we have the
- # plural form information for this language.
- return True
-
- @property
def number_of_plural_forms(self):
"""The number of plural forms for the language or 1 if not known."""
if self.context.language.pluralforms is not None:
=== modified file 'lib/lp/translations/browser/tests/pofile-base-views.txt'
--- lib/lp/translations/browser/tests/pofile-base-views.txt 2009-09-09 18:03:44 +0000
+++ lib/lp/translations/browser/tests/pofile-base-views.txt 2010-10-14 11:26:43 +0000
@@ -37,8 +37,6 @@
The view has information about the languages plural forms:
- >>> print view.has_plural_form_information
- True
>>> print view.number_of_plural_forms
2
>>> print view.plural_expression
=== modified file 'lib/lp/translations/browser/tests/test_translationmessage_view.py'
--- lib/lp/translations/browser/tests/test_translationmessage_view.py 2010-08-23 08:35:29 +0000
+++ lib/lp/translations/browser/tests/test_translationmessage_view.py 2010-10-14 11:26:43 +0000
@@ -1,22 +1,30 @@
# Copyright 2009 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import with_statement
+
__metaclass__ = type
from datetime import (
datetime,
timedelta,
)
-from unittest import TestLoader
import pytz
from canonical.launchpad.webapp.servers import LaunchpadTestRequest
from canonical.testing import ZopelessDatabaseLayer
-from lp.testing import TestCaseWithFactory
+from lp.app.errors import UnexpectedFormData
+from lp.testing import (
+ anonymous_logged_in,
+ person_logged_in,
+ TestCaseWithFactory,
+ )
from lp.translations.browser.translationmessage import (
+ CurrentTranslationMessagePageView,
CurrentTranslationMessageView,
)
+from lp.translations.interfaces.translationsperson import ITranslationsPerson
class TestCurrentTranslationMessage_can_dismiss(TestCaseWithFactory):
@@ -168,5 +176,58 @@
self._assertConfirmEmptyPluralPackaged(True, False, False, False)
-def test_suite():
- return TestLoader().loadTestsFromName(__name__)
+class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
+ """Test `CurrentTranslationMessagePageView` and its base class."""
+
+ layer = ZopelessDatabaseLayer
+
+ def _makeView(self, blank_timestamp=False):
+ message = self.factory.makeTranslationMessage()
+ request = LaunchpadTestRequest()
+ view = CurrentTranslationMessagePageView(message, request)
+ if blank_timestamp:
+ view.lock_timestamp = None
+ else:
+ view.lock_timestamp = datetime.now(pytz.utc)
+ return view
+
+ def test_extractLockTimestamp(self):
+ view = self._makeView()
+ view.request.form['lock_timestamp'] = u'2010-01-01 00:00:00 UTC'
+ self.assertEqual(
+ datetime(2010, 01, 01, tzinfo=pytz.utc),
+ view._extractLockTimestamp())
+
+ def test_extractLockTimestamp_returns_None_by_default(self):
+ view = self._makeView()
+ self.assertIs(None, view._extractLockTimestamp())
+
+ def test_extractLockTimestamp_returns_None_for_bogus_timestamp(self):
+ view = self._makeView()
+ view.request.form['lock_timestamp'] = u'Hi mom!'
+ self.assertIs(None, view._extractLockTimestamp())
+
+ def test_checkSubmitConditions_passes(self):
+ with person_logged_in(self.factory.makePerson()):
+ view = self._makeView()
+ view._checkSubmitConditions()
+
+ def test_checkSubmitConditions_requires_lock_timestamp(self):
+ with person_logged_in(self.factory.makePerson()):
+ view = self._makeView(blank_timestamp=True)
+ self.assertRaises(UnexpectedFormData, view._checkSubmitConditions)
+
+ def test_checkSubmitConditions_rejects_anonymous_request(self):
+ with anonymous_logged_in():
+ view = self._makeView()
+ self.assertRaises(UnexpectedFormData, view._checkSubmitConditions)
+
+ def test_checkSubmitConditions_rejects_license_decliners(self):
+ # Users who have declined the relicensing agreement can't post
+ # translations.
+ decliner = self.factory.makePerson()
+ ITranslationsPerson(decliner).translations_relicensing_agreement = (
+ False)
+ with person_logged_in(decliner):
+ view = self._makeView()
+ self.assertRaises(UnexpectedFormData, view._checkSubmitConditions)
=== modified file 'lib/lp/translations/browser/tests/translationmessage-views.txt'
--- lib/lp/translations/browser/tests/translationmessage-views.txt 2010-09-06 10:40:54 +0000
+++ lib/lp/translations/browser/tests/translationmessage-views.txt 2010-10-14 11:26:43 +0000
@@ -11,8 +11,8 @@
>>> from lp.services.worlddata.interfaces.language import ILanguageSet
>>> from canonical.launchpad.webapp import canonical_url
-All the tests will be submitted as comming from Kurem, an editor for the POFile
-that we are going to edit.
+All the tests will be submitted as comming from Kurem, an editor for the
+POFile that we are going to edit.
>>> login('kurem@xxxxxxxxx')
@@ -230,30 +230,6 @@
A new translation is submitted through the view.
- >>> server_url = '/'.join(
- ... [canonical_url(translationmessage), '+translate'])
- >>> form = {
- ... 'alt': None,
- ... 'msgset_1': None,
- ... 'msgset_1_es_translation_0_new_checkbox': True,
- ... 'msgset_1_es_translation_0_new': 'Foo',
- ... 'submit_translations': 'Save & Continue'}
- >>> translationmessage_page_view = create_view(
- ... translationmessage, "+translate", form=form,
- ... layer=TranslationsLayer, server_url=server_url)
- >>> translationmessage_page_view.request.method = 'POST'
-
-And when we initialise the view class, we detect that we missed the timestamp
-that allow us to know whether we are working with latest submitted value or
-someone updated the database while we were working on those translations.
-
- >>> translationmessage_page_view.initialize()
- Traceback (most recent call last):
- ...
- UnexpectedFormData: We didn't find the timestamp...
-
-We do a new submit, but this time including a lock_timestamp field.
-
>>> form = {
... 'lock_timestamp': '2006-11-28T13:00:00+00:00',
... 'alt': None,
@@ -269,8 +245,6 @@
>>> translationmessage_page_view.initialize()
>>> transaction.commit()
-This time we didn't get any problem with the submission.
-
Now, let's see how the system prevents a submission that has a timestamp older
than when last current translation was submitted.
=== modified file 'lib/lp/translations/browser/translationmessage.py'
--- lib/lp/translations/browser/translationmessage.py 2010-09-06 10:40:54 +0000
+++ lib/lp/translations/browser/translationmessage.py 2010-10-14 11:26:43 +0000
@@ -36,6 +36,7 @@
from zope.interface import implements
from zope.schema.vocabulary import getVocabularyRegistry
+from canonical.launchpad.readonly import is_read_only
from canonical.launchpad.webapp import (
ApplicationMenu,
canonical_url,
@@ -64,6 +65,7 @@
RosettaTranslationOrigin,
TranslationConflict,
)
+from lp.translations.interfaces.translations import TranslationConstants
from lp.translations.interfaces.translationsperson import ITranslationsPerson
from lp.translations.utilities.validate import GettextValidationError
@@ -230,9 +232,6 @@
"""
pofile = None
- # There will never be 100 plural forms. Usually, we'll be iterating
- # over just two or three.
- MAX_PLURAL_FORMS = 100
@property
def label(self):
@@ -246,6 +245,9 @@
def initialize(self):
assert self.pofile, "Child class must define self.pofile"
+ self.has_plural_form_information = (
+ self.pofile.hasPluralFormInformation())
+
# These two dictionaries hold translation data parsed from the
# form submission. They exist mainly because of the need to
# redisplay posted translations when they contain errors; if not
@@ -286,6 +288,16 @@
self._initializeAltLanguage()
+ method = self.request.method
+ if method == 'POST':
+ self.lock_timestamp = self._extractLockTimestamp()
+ self._checkSubmitConditions()
+ else:
+ # It's not a POST, so we should generate lock_timestamp.
+ UTC = pytz.timezone('UTC')
+ self.lock_timestamp = datetime.datetime.now(UTC)
+
+
# The batch navigator needs to be initialized early, before
# _submitTranslations is called; the reason for this is that
# _submitTranslations, in the case of no errors, redirects to
@@ -297,50 +309,65 @@
self.start = self.batchnav.start
self.size = self.batchnav.currentBatch().size
- if self.request.method == 'POST':
- if self.user is None:
- raise UnexpectedFormData(
- "Anonymous users or users who are not accepting our "
- "licensing terms cannot do POST submissions.")
- translations_person = ITranslationsPerson(self.user)
- if (translations_person.translations_relicensing_agreement
- is not None and
- not translations_person.translations_relicensing_agreement):
- raise UnexpectedFormData(
- "Users who do not agree to licensing terms "
- "cannot do POST submissions.")
- try:
- # Try to get the timestamp when the submitted form was
- # created. We use it to detect whether someone else updated
- # the translation we are working on in the elapsed time
- # between the form loading and its later submission.
- self.lock_timestamp = zope_datetime.parseDatetimetz(
- self.request.form.get('lock_timestamp', u''))
- except zope_datetime.DateTimeError:
- # invalid format. Either we don't have the timestamp in the
- # submitted form or it has the wrong format.
- raise UnexpectedFormData(
- "We didn't find the timestamp that tells us when was"
- " generated the submitted form.")
-
- # Check if this is really the form we are listening for..
- if self.request.form.get("submit_translations"):
- # Check if this is really the form we are listening for..
- if self._submitTranslations():
- # .. and if no errors occurred, adios. Otherwise, we
- # need to set up the subviews for error display and
- # correction.
- return
- else:
- # It's not a POST, so we should generate lock_timestamp.
- UTC = pytz.timezone('UTC')
- self.lock_timestamp = datetime.datetime.now(UTC)
+ if method == 'POST' and self.request.form.get('submit_translations'):
+ if self._submitTranslations():
+ # If no errors occurred, adios. Otherwise, we need to set up
+ # the subviews for error display and correction.
+ return
# Slave view initialization depends on _submitTranslations being
# called, because the form data needs to be passed in to it --
# again, because of error handling.
self._initializeTranslationMessageViews()
+ def _extractLockTimestamp(self):
+ """Extract the lock timestamp from the request.
+
+ The lock_timestamp is used to detect conflicting concurrent
+ translation updates: if the translation that is being changed
+ has been set after the current form was generated, the user
+ chose a translation based on outdated information. In that
+ case there is a conflict.
+ """
+ try:
+ return zope_datetime.parseDatetimetz(
+ self.request.form.get('lock_timestamp', u''))
+ except zope_datetime.DateTimeError:
+ # invalid format. Either we don't have the timestamp in the
+ # submitted form or it has the wrong format.
+ return None
+
+ def _checkSubmitConditions(self):
+ """Verify that this submission is possible and valid.
+
+ :raises: `UnexpectedFormData` if conditions are not met. In
+ principle the user should not have been given the option to
+ submit the current request.
+ """
+ if is_read_only():
+ raise UnexpectedFormData(
+ "Launchpad is currently in read-only mode for maintenance. "
+ "Please try again later.")
+
+ if self.user is None:
+ raise UnexpectedFormData("You are not logged in.")
+
+ # Users who have declined the licensing agreement can't post
+ # translations. We don't stop users who haven't made a decision
+ # yet at this point; they may be project owners making
+ # corrections.
+ translations_person = ITranslationsPerson(self.user)
+ relicensing = translations_person.translations_relicensing_agreement
+ if relicensing is not None and not relicensing:
+ raise UnexpectedFormData(
+ "You can't post translations since you have not agreed to "
+ "our translations licensing terms.")
+
+ if self.lock_timestamp is None:
+ raise UnexpectedFormData(
+ "Your form submission did not contain the lock_timestamp "
+ "that tells Launchpad when the submitted form was generated.")
+
#
# API Hooks
#
@@ -587,15 +614,6 @@
self.second_lang_code = second_lang_code
@property
- def has_plural_form_information(self):
- """Return whether we know the plural forms for this language."""
- if self.pofile.potemplate.hasPluralMessage():
- return self.pofile.language.pluralforms is not None
- # If there are no plural forms, we assume that we have the
- # plural form information for this language.
- return True
-
- @property
def user_is_official_translator(self):
"""Determine whether the current user is an official translator."""
return self.pofile.canEditTranslations(self.user)
@@ -658,7 +676,7 @@
# Extract the translations from the form, and store them in
# self.form_posted_translations. We try plural forms in turn,
# starting at 0.
- for pluralform in xrange(self.MAX_PLURAL_FORMS):
+ for pluralform in xrange(TranslationConstants.MAX_PLURAL_FORMS):
msgset_ID_LANGCODE_translation_PLURALFORM_new = '%s%d_new' % (
msgset_ID_LANGCODE_translation_, pluralform)
if msgset_ID_LANGCODE_translation_PLURALFORM_new not in form:
@@ -737,7 +755,7 @@
potmsgset].append(pluralform)
else:
raise AssertionError('More than %d plural forms were submitted!'
- % self.MAX_PLURAL_FORMS)
+ % TranslationConstants.MAX_PLURAL_FORMS)
def _observeTranslationUpdate(self, potmsgset):
"""Observe that a translation was updated for the potmsgset.
@@ -1056,7 +1074,7 @@
diverged_and_have_shared = (
self.context.potemplate is not None and
- self.shared_translationmessage is not None)
+ self.shared_translationmessage is not None)
if diverged_and_have_shared:
pofile = self.shared_translationmessage.ensureBrowserPOFile()
if pofile is None:
@@ -1155,10 +1173,10 @@
def _setOnePOFile(self, messages):
"""Return a list of messages that all have a browser_pofile set.
-
+
If a pofile cannot be found for a message, it is not included in
the resulting list.
- """
+ """
result = []
for message in messages:
if message.browser_pofile is None:
@@ -1170,7 +1188,7 @@
message.setPOFile(pofile)
result.append(message)
return result
-
+
def _buildAllSuggestions(self):
"""Builds all suggestions and puts them into suggestions_block.
=== modified file 'lib/lp/translations/interfaces/pofile.py'
--- lib/lp/translations/interfaces/pofile.py 2010-09-06 10:40:54 +0000
+++ lib/lp/translations/interfaces/pofile.py 2010-10-14 11:26:43 +0000
@@ -168,6 +168,9 @@
for.
"""
+ def hasPluralFormInformation():
+ """Do we know the plural-forms information for this `POFile`?"""
+
def getHeader():
"""Return an `ITranslationHeaderData` representing its header."""
=== modified file 'lib/lp/translations/model/pofile.py'
--- lib/lp/translations/model/pofile.py 2010-09-30 08:51:21 +0000
+++ lib/lp/translations/model/pofile.py 2010-10-14 11:26:43 +0000
@@ -177,6 +177,24 @@
return False
+def is_admin(user):
+ """Is `user` an admin or Translations admin?"""
+ celebs = getUtility(ILaunchpadCelebrities)
+ return user.inTeam(celebs.admin) or user.inTeam(celebs.rosetta_experts)
+
+
+def is_product_owner(user, potemplate):
+ """Is `user` the owner of a `Product` that `potemplate` belongs to?
+
+ A product's owners have edit rights on the product's translations.
+ """
+ productseries = potemplate.productseries
+ if productseries is None:
+ return False
+
+ return user.inTeam(productseries.product.owner)
+
+
def _can_edit_translations(pofile, person):
"""Say if a person is able to edit existing translations.
@@ -190,29 +208,25 @@
translation team for the given `IPOFile`.translationpermission and the
language associated with this `IPOFile`.
"""
+ if person is None:
+ # Anonymous users can't edit anything.
+ return False
+
if is_read_only():
# Nothing can be edited in read-only mode.
return False
- # If the person is None, then they cannot edit
- if person is None:
- return False
-
# XXX Carlos Perello Marin 2006-02-07 bug=4814:
# We should not check the permissions here but use the standard
# security system.
# Rosetta experts and admins can always edit translations.
- admins = getUtility(ILaunchpadCelebrities).admin
- rosetta_experts = getUtility(ILaunchpadCelebrities).rosetta_experts
- if (person.inTeam(admins) or person.inTeam(rosetta_experts)):
+ if is_admin(person):
return True
# The owner of the product is also able to edit translations.
- if pofile.potemplate.productseries is not None:
- product = pofile.potemplate.productseries.product
- if person.inTeam(product.owner):
- return True
+ if is_product_owner(person, pofile.potemplate):
+ return True
# If a person has decided not to license their translations under BSD
# license they can't edit translations.
@@ -284,6 +298,16 @@
"""See `IPOFile`."""
return self.language.guessed_pluralforms
+ def hasPluralFormInformation(self):
+ """See `IPOFile`."""
+ if self.language.pluralforms is None:
+ # We have no plural information for this language. It
+ # doesn't actually matter unless the template contains
+ # messages with plural forms.
+ return not self.potemplate.hasPluralMessage()
+ else:
+ return True
+
def canEditTranslations(self, person):
"""See `IPOFile`."""
return _can_edit_translations(self, person)
=== modified file 'lib/lp/translations/tests/test_pofile.py'
--- lib/lp/translations/tests/test_pofile.py 2010-09-30 17:57:01 +0000
+++ lib/lp/translations/tests/test_pofile.py 2010-10-14 11:26:43 +0000
@@ -1888,6 +1888,31 @@
self.pofile.markChanged(translator=translator)
self.assertEqual(translator, self.pofile.lasttranslator)
+ def test_hasPluralFormInformation_bluffs_if_irrelevant(self):
+ # If the template has no messages that use plural forms, the
+ # POFile has all the relevant plural-form information regardless
+ # of whether we know the plural forms for the language.
+ language = self.factory.makeLanguage()
+ pofile, potmsgset = self.factory.makePOFileAndPOTMsgSet(
+ language.code, with_plural=False)
+ self.assertTrue(pofile.hasPluralFormInformation())
+
+ def test_hasPluralFormInformation_admits_defeat(self):
+ # If there are messages with plurals, hasPluralFormInformation
+ # needs the plural-form information for the language.
+ language = self.factory.makeLanguage()
+ pofile, potmsgset = self.factory.makePOFileAndPOTMsgSet(
+ language.code, with_plural=True)
+ self.assertFalse(pofile.hasPluralFormInformation())
+
+ def test_hasPluralFormInformation_uses_language_info(self):
+ # hasPluralFormInformation returns True if plural forms
+ # information is available for the language.
+ language = self.factory.makeLanguage(pluralforms=5)
+ pofile, potmsgset = self.factory.makePOFileAndPOTMsgSet(
+ language.code, with_plural=True)
+ self.assertTrue(pofile.hasPluralFormInformation())
+
class TestPOFileTranslationMessages(TestCaseWithFactory):
"""Test PO file getTranslationMessages method."""
@@ -1905,66 +1930,66 @@
# A shared message is included in this POFile's messages.
message = self.factory.makeTranslationMessage(
potmsgset=self.potmsgset, pofile=self.pofile, force_shared=True)
-
+
self.assertEqual(
[message], list(self.pofile.getTranslationMessages()))
-
+
def test_getTranslationMessages_current_diverged(self):
# A diverged message is included in this POFile's messages.
message = self.factory.makeTranslationMessage(
potmsgset=self.potmsgset, pofile=self.pofile, force_diverged=True)
-
+
self.assertEqual(
[message], list(self.pofile.getTranslationMessages()))
-
+
def test_getTranslationMessages_suggestion(self):
# A suggestion is included in this POFile's messages.
message = self.factory.makeTranslationMessage(
potmsgset=self.potmsgset, pofile=self.pofile)
-
+
self.assertEqual(
[message], list(self.pofile.getTranslationMessages()))
-
+
def test_getTranslationMessages_obsolete(self):
# A message on an obsolete POTMsgSEt is included in this
# POFile's messages.
potmsgset = self.factory.makePOTMsgSet(self.potemplate, sequence=0)
message = self.factory.makeTranslationMessage(
potmsgset=potmsgset, pofile=self.pofile, force_shared=True)
-
+
self.assertEqual(
[message], list(self.pofile.getTranslationMessages()))
-
+
def test_getTranslationMessages_other_pofile(self):
# A message from another POFiles is not included.
other_pofile = self.factory.makePOFile('de')
self.factory.makeTranslationMessage(
potmsgset=self.potmsgset, pofile=other_pofile)
-
+
self.assertEqual([], list(self.pofile.getTranslationMessages()))
-
+
def test_getTranslationMessages_condition_matches(self):
# A message matching the given condition is included.
# Diverged messages are linked to a specific POTemplate.
message = self.factory.makeTranslationMessage(
potmsgset=self.potmsgset, pofile=self.pofile, force_diverged=True)
-
+
self.assertContentEqual(
[message],
self.pofile.getTranslationMessages(
"TranslationMessage.potemplate IS NOT NULL"))
-
+
def test_getTranslationMessages_condition_matches_not(self):
# A message not matching the given condition is excluded.
# Shared messages are not linked to a POTemplate.
self.factory.makeTranslationMessage(
potmsgset=self.potmsgset, pofile=self.pofile, force_shared=True)
-
+
self.assertContentEqual(
[],
self.pofile.getTranslationMessages(
"TranslationMessage.potemplate IS NOT NULL"))
-
+
def test_getTranslationMessages_condition_matches_in_other_pofile(self):
# A message matching given condition but located in another POFile
# is not included.
@@ -1972,12 +1997,12 @@
self.factory.makeTranslationMessage(
potmsgset=self.potmsgset, pofile=other_pofile,
force_diverged=True)
-
+
self.assertContentEqual(
[],
self.pofile.getTranslationMessages(
"TranslationMessage.potemplate IS NOT NULL"))
-
+
def test_getTranslationMessages_diverged_elsewhere(self):
# Diverged messages from sharing POTemplates are not included.
# Create a sharing potemplate in another product series and share
@@ -1992,9 +2017,9 @@
self.factory.makeTranslationMessage(
potmsgset=self.potmsgset, pofile=other_pofile,
force_diverged=True)
-
+
self.assertEqual([], list(self.pofile.getTranslationMessages()))
-
+
class TestPOFileToTranslationFileDataAdapter(TestCaseWithFactory):
"""Test POFile being adapted to IPOFileToTranslationFileData."""
=== modified file 'lib/lp/translations/utilities/tests/test_file_importer.py'
--- lib/lp/translations/utilities/tests/test_file_importer.py 2010-10-06 11:05:13 +0000
+++ lib/lp/translations/utilities/tests/test_file_importer.py 2010-10-14 11:26:43 +0000
@@ -613,7 +613,7 @@
if side == self.UPSTREAM:
potemplate = self.upstream_template
else:
- # Create a template in a source package.
+ # Create a template in a source package.
ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
distroseries = self.factory.makeDistroSeries(distribution=ubuntu)
ubuntu.translation_focus = distroseries
@@ -639,7 +639,7 @@
uploader=uploader, content=self.POFILE)
entry.potemplate = potemplate
entry.pofile = pofile
- # The uploaded file is only created in the librarian by a commit.
+ # The uploaded file is only created in the librarian by a commit.
transaction.commit()
return entry
=== modified file 'lib/lp/translations/utilities/translation_import.py'
--- lib/lp/translations/utilities/translation_import.py 2010-10-01 14:37:53 +0000
+++ lib/lp/translations/utilities/translation_import.py 2010-10-14 11:26:43 +0000
@@ -493,7 +493,7 @@
"""Are these English strings instead of translations?
If this template uses symbolic message ids, the English POFile
- will contain the English original texts that correspond to the
+ will contain the English original texts that correspond to the
symbols."""
return (
self.importer.uses_source_string_msgids and
Follow ups