From d7baf2c95345214ac4853c44b40b965fab3b9f8a Mon Sep 17 00:00:00 2001 From: Shadi Naif Date: Fri, 18 Aug 2023 11:48:57 +0300 Subject: [PATCH] feat: refactor extract command with its tests Refactor for more usability and readability. And to prepare tests to deal with options to be added to extract command in future pull-requests Refs: FC-0012 OEP-58 --- i18n/extract.py | 66 ++++++++++++++++++++++++------------------- tests/test_extract.py | 59 +++++++++++++++++++++++++++++++------- 2 files changed, 86 insertions(+), 39 deletions(-) diff --git a/i18n/extract.py b/i18n/extract.py index 8b5aaa3..3761e8b 100644 --- a/i18n/extract.py +++ b/i18n/extract.py @@ -95,35 +95,7 @@ def run(self, args): else: stderr = DEVNULL - # --keyword informs Babel that `interpolate()` is an expected - # gettext function, which is necessary because the `tokenize` function - # in the `markey` module marks it as such and passes it to Babel. - # (These functions are called in the django-babel-underscore module.) - babel_cmd_template = ( - 'pybabel {verbosity} extract --mapping={config} ' - '--add-comments="Translators:" --keyword="interpolate" ' - '. --output={output}' - ) - - babel_mako_cfg = self.base(configuration.locale_dir, 'babel_mako.cfg') - if babel_mako_cfg.exists(): - babel_mako_cmd = babel_cmd_template.format( - verbosity=babel_verbosity, - config=babel_mako_cfg, - output=self.base(configuration.source_messages_dir, 'mako.po'), - ) - - execute(babel_mako_cmd, working_directory=configuration.root_dir, stderr=stderr) - - babel_underscore_cfg = self.base(configuration.locale_dir, 'babel_underscore.cfg') - if babel_underscore_cfg.exists(): - babel_underscore_cmd = babel_cmd_template.format( - verbosity=babel_verbosity, - config=babel_underscore_cfg, - output=self.base(configuration.source_messages_dir, 'underscore.po'), - ) - - execute(babel_underscore_cmd, working_directory=configuration.root_dir, stderr=stderr) + self.babel_extract(stderr, babel_verbosity) makemessages = f"django-admin makemessages -l en -v{args.verbose}" ignores = " ".join(f'--ignore="{d}/*"' for d in configuration.ignore_dirs) @@ -181,6 +153,42 @@ def run(self, args): self.rename_source_file('django-saved.po', 'django.po') self.rename_source_file('djangojs-saved.po', 'djangojs.po') + def babel_extract(self, stderr, verbosity): + """ + Extract strings from mako templates. + """ + configuration = self.configuration + + # --keyword informs Babel that `interpolate()` is an expected + # gettext function, which is necessary because the `tokenize` function + # in the `markey` module marks it as such and passes it to Babel. + # (These functions are called in the django-babel-underscore module.) + babel_cmd_template = ( + 'pybabel {verbosity} extract --mapping={config} ' + '--add-comments="Translators:" --keyword="interpolate" ' + '. --output={output}' + ) + + babel_mako_cfg = self.base(configuration.locale_dir, 'babel_mako.cfg') + if babel_mako_cfg.exists(): + babel_mako_cmd = babel_cmd_template.format( + verbosity=verbosity, + config=babel_mako_cfg, + output=self.base(configuration.source_messages_dir, 'mako.po'), + ) + + execute(babel_mako_cmd, working_directory=configuration.root_dir, stderr=stderr) + + babel_underscore_cfg = self.base(configuration.locale_dir, 'babel_underscore.cfg') + if babel_underscore_cfg.exists(): + babel_underscore_cmd = babel_cmd_template.format( + verbosity=verbosity, + config=babel_underscore_cfg, + output=self.base(configuration.source_messages_dir, 'underscore.po'), + ) + + execute(babel_underscore_cmd, working_directory=configuration.root_dir, stderr=stderr) + def clean_pofile(path_name): """ diff --git a/tests/test_extract.py b/tests/test_extract.py index 32eaedc..55d2c59 100644 --- a/tests/test_extract.py +++ b/tests/test_extract.py @@ -1,20 +1,41 @@ -from datetime import datetime, timedelta import os +from datetime import datetime, timedelta +from functools import wraps import polib -from path import Path - from i18n import extract, config +from path import Path from . import I18nToolTestCase, MOCK_DJANGO_APP_DIR +def perform_extract(): + """ + Decorator for test methods in TestExtract class. + """ + def decorator(test_method): + """ + The decorator itself + """ + @wraps(test_method) + def wrapped(self): + """ + The wrapper function + """ + extract.main( + verbosity=0, + config=self.configuration._filename, + root_dir=MOCK_DJANGO_APP_DIR, + ) + test_method(self) + return wrapped + return decorator + + class TestExtract(I18nToolTestCase): """ Tests functionality of i18n/extract.py """ - generated_files = ('django-partial.po', 'djangojs-partial.po', 'mako.po') - def setUp(self): super().setUp() @@ -31,8 +52,19 @@ def setUp(self): ) self.configuration = config.Configuration(root_dir=MOCK_DJANGO_APP_DIR) - # Run extraction script - extract.main(verbosity=0, config=self.configuration._filename, root_dir=MOCK_DJANGO_APP_DIR) + @property + def django_po(self): + """ + Returns the name of the generated django file + """ + return 'django-partial.po' + + @property + def djangojs_po(self): + """ + Returns the name of the generated djangojs file + """ + return 'djangojs-partial.po' def get_files(self): """ @@ -40,13 +72,16 @@ def get_files(self): Returns the fully expanded filenames for all extracted files Fails assertion if one of the files doesn't exist. """ - for filename in self.generated_files: + generated_files = ('mako.po', self.django_po, self.djangojs_po,) + + for filename in generated_files: path = Path.joinpath(self.configuration.source_messages_dir, filename) exists = Path.exists(path) self.assertTrue(exists, msg='Missing file: %s' % path) - if exists: - yield path + yield path + + @perform_extract() def test_files(self): """ Asserts that each auto-generated file has been modified since 'extract' was launched. @@ -56,6 +91,7 @@ def test_files(self): self.assertTrue(datetime.fromtimestamp(os.path.getmtime(path)) > self.start_time, msg='File not recently modified: %s' % path) + @perform_extract() def test_is_keystring(self): """ Verifies is_keystring predicate @@ -67,6 +103,7 @@ def test_is_keystring(self): self.assertTrue(extract.is_key_string(entry1.msgid)) self.assertFalse(extract.is_key_string(entry2.msgid)) + @perform_extract() def test_headers(self): """ Verify all headers have been modified @@ -79,6 +116,7 @@ def test_headers(self): msg='Missing header in %s:\n"%s"' % (path, header) ) + @perform_extract() def test_metadata(self): """ Verify all metadata has been modified @@ -90,6 +128,7 @@ def test_metadata(self): expected = 'openedx-translation@googlegroups.com' self.assertEquals(expected, value) + @perform_extract() def test_metadata_no_create_date(self): """ Verify `POT-Creation-Date` metadata has been removed