Hi Jeroen,
Thanks for this branch and new tool. It looks good except for a few minor things. r=bac, merge-conditional
> === added file 'lib/lp/translations/scripts/tests/test_validate_translations_file.py' > --- lib/lp/translations/scripts/tests/test_validate_translations_file.py 1970-01-01 00:00:00 +0000 > +++ lib/lp/translations/scripts/tests/test_validate_translations_file.py 2010-01-05 17:14:16 +0000 > @@ -0,0 +1,133 @@ > +#! /usr/bin/python2.5 > +# > +# Copyright 2010 Canonical Ltd. This software is licensed under the > +# GNU Affero General Public License version 3 (see the file LICENSE).
You win brownie points for getting the year right!
> +"""Test the validate-translations-file script.""" > + > +import logging > +import os.path > +from textwrap import dedent > +from unittest import TestCase, TestLoader > + > +from canonical.launchpad.ftests.script import run_script > + > +import lp.translations > + > +from lp.translations.scripts.validate_translations_file import ( > + UnknownFileType, ValidateTranslationsFile) > +from lp.translations.utilities.tests.xpi_helpers import ( > + get_en_US_xpi_file_to_import) > + > + > +class TestValidateTranslationsFile(TestCase): > + > + def _makeValidator(self, test_args=None): > + """Produce a ValidateTranslationsFile.""" > + if test_args is None: > + test_args = [] > + validator = ValidateTranslationsFile(test_args=test_args) > + validator.logger.setLevel(logging.CRITICAL) > + return validator > + > + def _strip(self, file_contents): > + """Remove leading newlines & indentation from file_contents.""" > + return dedent(file_contents.strip()) > + > + def _findTestData(self): > + """Return base path to this test's test data.""" > + return os.path.join( > + os.path.dirname(lp.translations.__file__), > + 'scripts/tests/test-data') > + > + def test_validate_unknown(self): > + # Unknown filename extensions result in UnknownFileType. > + validator = self._makeValidator(['foo.bar'])
The argument list here is confusing. Does it serve any purpose? If not please remove it.
> === added file 'lib/lp/translations/scripts/validate_translations_file.py' > --- lib/lp/translations/scripts/validate_translations_file.py 1970-01-01 00:00:00 +0000 > +++ lib/lp/translations/scripts/validate_translations_file.py 2010-01-05 17:14:16 +0000 > @@ -0,0 +1,131 @@ > +# Copyright 2010 Canonical Ltd. This software is licensed under the > +# GNU Affero General Public License version 3 (see the file LICENSE). > + > +__metaclass__ = type > + > +__all__ = [ > + 'UnknownFileType', > + 'ValidateTranslationsFile', > + ] > + > +from cStringIO import StringIO > +import logging > +from optparse import OptionParser > +import os.path > + > +from canonical.launchpad import scripts > +from lp.translations.utilities.gettext_po_parser import POParser > +from lp.translations.utilities.mozilla_xpi_importer import ( > + DtdFile, MozillaZipImportParser) > +from lp.translations.utilities.xpi_manifest import XpiManifest > + > + > +class UnknownFileType(Exception): > + """File's type is not recognized.""" > + > + > +def validate_unknown_file_type(filename, content): > + """Fail validation: unknown file type.""" > + raise UnknownFileType("Unrecognized file type for '%s'." % filename) > + > + > +def validate_dtd(filename, content): > + """Validate XPI DTD file.""" > + DtdFile(filename, filename, content) > + > + > +def validate_po(filename, content): > + """Validate a gettext PO or POT file.""" > + POParser().parse(content) > + > + > +def validate_xpi(filename, content): > + """Validate an XPI archive.""" > + MozillaZipImportParser(filename, StringIO(content)) > + > + > +def validate_xpi_manifest(filename, content): > + """Validate XPI manifest.""" > + XpiManifest(content) > + > + > +
Remove the one extra blank line.
> +class ValidateTranslationsFile: > + """Parse translations files to see if they are well-formed.""" > + > + name = 'validate-translations-file' > + > + validators = { > + 'dtd': validate_dtd, > + 'manifest': validate_xpi_manifest, > + 'po': validate_po, > + 'pot': validate_po, > + 'xpi': validate_xpi, > + } > + > + def __init__(self, test_args=None): > + """Set up basic facilities, similar to `LaunchpadScript`.""" > + self.parser = OptionParser() > + scripts.logger_options(self.parser, default=logging.INFO) > + self.options, self.args = self.parser.parse_args(args=test_args) > + self.logger = scripts.logger(self.options, self.name) > + > + def main(self): > + """Validate file(s).""" > + failures = 0 > + files = len(self.args) > + self.logger.info("Validating %d file(s)." % files) > + > + for filename in self.args: > + if not self._readAndValidate(filename): > + failures += 1 > + > + if failures == 0: > + self.logger.info("OK.") > + elif failures > 1: > + self.logger.error("%d failures in %d files." % (failures, files)) > + elif files > 1: > + self.logger.error("1 failure in %d files." % files) > + else: > + self.logger.error("Validation failed.") > + > + if failures == 0: > + return 0 > + else: > + return 1 > + > + def _pickValidator(self, filename): > + """Select the appropriate validator for a file.""" > + base, ext = os.path.splitext(filename) > + if ext is not None and ext.startswith('.'): > + ext = ext[1:] > + return self.validators.get(ext, validate_unknown_file_type)
Nice.
> === added file 'scripts/rosetta/validate-translations-file.py' > --- scripts/rosetta/validate-translations-file.py 1970-01-01 00:00:00 +0000 > +++ scripts/rosetta/validate-translations-file.py 2010-01-05 17:14:16 +0000 > @@ -0,0 +1,18 @@ > +#! /usr/bin/python2.5 > +# Copyright 2009 Canonical Ltd. This software is licensed under the
Oops, brownie_points -= 1
> +# GNU Affero General Public License version 3 (see the file LICENSE). > + > +# pylint: disable-msg=W0403 > + > +__metaclass__ = type > + > +import _pythonpath > + > +import sys > + > +from lp.translations.scripts.validate_translations_file import ( > + ValidateTranslationsFile) > + > + > +if __name__ == "__main__": > + sys.exit(ValidateTranslationsFile().main())
« Back to merge proposal
Hi Jeroen,
Thanks for this branch and new tool. It looks good except for a few minor things. r=bac, merge-conditional
> === added file 'lib/lp/ translations/ scripts/ tests/test_ validate_ translations_ file.py' translations/ scripts/ tests/test_ validate_ translations_ file.py 1970-01-01 00:00:00 +0000 translations/ scripts/ tests/test_ validate_ translations_ file.py 2010-01-05 17:14:16 +0000
> --- lib/lp/
> +++ lib/lp/
> @@ -0,0 +1,133 @@
> +#! /usr/bin/python2.5
> +#
> +# Copyright 2010 Canonical Ltd. This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
You win brownie points for getting the year right!
> +"""Test the validate- translations- file script.""" launchpad. ftests. script import run_script .scripts. validate_ translations_ file import ( tionsFile) .utilities. tests.xpi_ helpers import ( US_xpi_ file_to_ import) nslationsFile( TestCase) : self, test_args=None): tionsFile. """ tionsFile( test_args= test_args) logger. setLevel( logging. CRITICAL) file_contents. strip() ) self): dirname( lp.translations .__file_ _), tests/test- data') unknown( self): ator([' foo.bar' ])
> +
> +import logging
> +import os.path
> +from textwrap import dedent
> +from unittest import TestCase, TestLoader
> +
> +from canonical.
> +
> +import lp.translations
> +
> +from lp.translations
> + UnknownFileType, ValidateTransla
> +from lp.translations
> + get_en_
> +
> +
> +class TestValidateTra
> +
> + def _makeValidator(
> + """Produce a ValidateTransla
> + if test_args is None:
> + test_args = []
> + validator = ValidateTransla
> + validator.
> + return validator
> +
> + def _strip(self, file_contents):
> + """Remove leading newlines & indentation from file_contents."""
> + return dedent(
> +
> + def _findTestData(
> + """Return base path to this test's test data."""
> + return os.path.join(
> + os.path.
> + 'scripts/
> +
> + def test_validate_
> + # Unknown filename extensions result in UnknownFileType.
> + validator = self._makeValid
The argument list here is confusing. Does it serve any purpose? If
not please remove it.
> === added file 'lib/lp/ translations/ scripts/ validate_ translations_ file.py' translations/ scripts/ validate_ translations_ file.py 1970-01-01 00:00:00 +0000 translations/ scripts/ validate_ translations_ file.py 2010-01-05 17:14:16 +0000 ationsFile' , .utilities. gettext_ po_parser import POParser .utilities. mozilla_ xpi_importer import ( tParser) .utilities. xpi_manifest import XpiManifest (Exception) : unknown_ file_type( filename, content): ("Unrecognized file type for '%s'." % filename) dtd(filename, content): po(filename, content): ).parse( content) xpi(filename, content): tParser( filename, StringIO(content)) xpi_manifest( filename, content): content)
> --- lib/lp/
> +++ lib/lp/
> @@ -0,0 +1,131 @@
> +# Copyright 2010 Canonical Ltd. This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +__metaclass__ = type
> +
> +__all__ = [
> + 'UnknownFileType',
> + 'ValidateTransl
> + ]
> +
> +from cStringIO import StringIO
> +import logging
> +from optparse import OptionParser
> +import os.path
> +
> +from canonical.launchpad import scripts
> +from lp.translations
> +from lp.translations
> + DtdFile, MozillaZipImpor
> +from lp.translations
> +
> +
> +class UnknownFileType
> + """File's type is not recognized."""
> +
> +
> +def validate_
> + """Fail validation: unknown file type."""
> + raise UnknownFileType
> +
> +
> +def validate_
> + """Validate XPI DTD file."""
> + DtdFile(filename, filename, content)
> +
> +
> +def validate_
> + """Validate a gettext PO or POT file."""
> + POParser(
> +
> +
> +def validate_
> + """Validate an XPI archive."""
> + MozillaZipImpor
> +
> +
> +def validate_
> + """Validate XPI manifest."""
> + XpiManifest(
> +
> +
> +
Remove the one extra blank line.
> +class ValidateTransla tionsFile: translations- file' xpi_manifest, t`.""" logger_ options( self.parser, default= logging. INFO) parse_args( args=test_ args) logger( self.options, self.name) info("Validatin g %d file(s)." % files) lidate( filename) : info("OK. ") error(" %d failures in %d files." % (failures, files)) error(" 1 failure in %d files." % files) error(" Validation failed.") self, filename): splitext( filename) '.'): .get(ext, validate_ unknown_ file_type)
> + """Parse translations files to see if they are well-formed."""
> +
> + name = 'validate-
> +
> + validators = {
> + 'dtd': validate_dtd,
> + 'manifest': validate_
> + 'po': validate_po,
> + 'pot': validate_po,
> + 'xpi': validate_xpi,
> + }
> +
> + def __init__(self, test_args=None):
> + """Set up basic facilities, similar to `LaunchpadScrip
> + self.parser = OptionParser()
> + scripts.
> + self.options, self.args = self.parser.
> + self.logger = scripts.
> +
> + def main(self):
> + """Validate file(s)."""
> + failures = 0
> + files = len(self.args)
> + self.logger.
> +
> + for filename in self.args:
> + if not self._readAndVa
> + failures += 1
> +
> + if failures == 0:
> + self.logger.
> + elif failures > 1:
> + self.logger.
> + elif files > 1:
> + self.logger.
> + else:
> + self.logger.
> +
> + if failures == 0:
> + return 0
> + else:
> + return 1
> +
> + def _pickValidator(
> + """Select the appropriate validator for a file."""
> + base, ext = os.path.
> + if ext is not None and ext.startswith(
> + ext = ext[1:]
> + return self.validators
Nice.
> === added file 'scripts/ rosetta/ validate- translations- file.py' rosetta/ validate- translations- file.py 1970-01-01 00:00:00 +0000 rosetta/ validate- translations- file.py 2010-01-05 17:14:16 +0000
> --- scripts/
> +++ scripts/
> @@ -0,0 +1,18 @@
> +#! /usr/bin/python2.5
> +# Copyright 2009 Canonical Ltd. This software is licensed under the
Oops, brownie_points -= 1
> +# GNU Affero General Public License version 3 (see the file LICENSE). .scripts. validate_ translations_ file import ( tionsFile) ValidateTransla tionsFile( ).main( ))
> +
> +# pylint: disable-msg=W0403
> +
> +__metaclass__ = type
> +
> +import _pythonpath
> +
> +import sys
> +
> +from lp.translations
> + ValidateTransla
> +
> +
> +if __name__ == "__main__":
> + sys.exit(