summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cordery <cordery@gmail.com>2023-11-07 12:32:19 +0100
committerNatalia Bidart <124304+nessita@users.noreply.github.com>2023-11-13 14:03:48 -0300
commitad41f1c53aa9f2c938df32e4386d8a80138923fc (patch)
treee9df9c959dc3aed7f86ff30449921f8732c4579e
parentb863c5ffde0bafa5eaa9f262103eaeb71877787c (diff)
Fixed #34952 -- Copied dir list when processing locale folders to avoid missing entries during os.walk traversal.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
-rw-r--r--django/core/management/commands/compilemessages.py3
-rw-r--r--tests/i18n/test_compilation.py58
2 files changed, 60 insertions, 1 deletions
diff --git a/django/core/management/commands/compilemessages.py b/django/core/management/commands/compilemessages.py
index 9ed3ef7c31..eddf31b794 100644
--- a/django/core/management/commands/compilemessages.py
+++ b/django/core/management/commands/compilemessages.py
@@ -91,7 +91,8 @@ class Command(BaseCommand):
# Walk entire tree, looking for locale directories
for dirpath, dirnames, filenames in os.walk(".", topdown=True):
- for dirname in dirnames:
+ # As we may modify dirnames, iterate through a copy of it instead
+ for dirname in list(dirnames):
if is_ignored_path(
os.path.normpath(os.path.join(dirpath, dirname)), ignore_patterns
):
diff --git a/tests/i18n/test_compilation.py b/tests/i18n/test_compilation.py
index ab74927c40..7da95ba9e9 100644
--- a/tests/i18n/test_compilation.py
+++ b/tests/i18n/test_compilation.py
@@ -195,6 +195,64 @@ class IgnoreDirectoryCompilationTests(MessageCompilationTests):
self.assertNoneExist(self.CACHE_DIR, ["en", "fr", "it"])
self.assertNoneExist(self.NESTED_DIR, ["en", "fr", "it"])
+ def test_no_dirs_accidentally_skipped(self):
+ os_walk_results = [
+ # To discover .po filepaths, compilemessages uses with a starting list of
+ # basedirs to inspect, which in this scenario are:
+ # ["conf/locale", "locale"]
+ # Then os.walk is used to discover other locale dirs, ignoring dirs matching
+ # `ignore_patterns`. Mock the results to place an ignored directory directly
+ # before and after a directory named "locale".
+ [("somedir", ["ignore", "locale", "ignore"], [])],
+ # This will result in three basedirs discovered:
+ # ["conf/locale", "locale", "somedir/locale"]
+ # os.walk is called for each locale in each basedir looking for .po files.
+ # In this scenario, we need to mock os.walk results for "en", "fr", and "it"
+ # locales for each basedir:
+ [("exclude/locale/LC_MESSAGES", [], ["en.po"])],
+ [("exclude/locale/LC_MESSAGES", [], ["fr.po"])],
+ [("exclude/locale/LC_MESSAGES", [], ["it.po"])],
+ [("exclude/conf/locale/LC_MESSAGES", [], ["en.po"])],
+ [("exclude/conf/locale/LC_MESSAGES", [], ["fr.po"])],
+ [("exclude/conf/locale/LC_MESSAGES", [], ["it.po"])],
+ [("exclude/somedir/locale/LC_MESSAGES", [], ["en.po"])],
+ [("exclude/somedir/locale/LC_MESSAGES", [], ["fr.po"])],
+ [("exclude/somedir/locale/LC_MESSAGES", [], ["it.po"])],
+ ]
+
+ module_path = "django.core.management.commands.compilemessages"
+ with mock.patch(f"{module_path}.os.walk", side_effect=os_walk_results):
+ with mock.patch(f"{module_path}.os.path.isdir", return_value=True):
+ with mock.patch(
+ f"{module_path}.Command.compile_messages"
+ ) as mock_compile_messages:
+ call_command("compilemessages", ignore=["ignore"], verbosity=4)
+
+ expected = [
+ (
+ [
+ ("exclude/locale/LC_MESSAGES", "en.po"),
+ ("exclude/locale/LC_MESSAGES", "fr.po"),
+ ("exclude/locale/LC_MESSAGES", "it.po"),
+ ],
+ ),
+ (
+ [
+ ("exclude/conf/locale/LC_MESSAGES", "en.po"),
+ ("exclude/conf/locale/LC_MESSAGES", "fr.po"),
+ ("exclude/conf/locale/LC_MESSAGES", "it.po"),
+ ],
+ ),
+ (
+ [
+ ("exclude/somedir/locale/LC_MESSAGES", "en.po"),
+ ("exclude/somedir/locale/LC_MESSAGES", "fr.po"),
+ ("exclude/somedir/locale/LC_MESSAGES", "it.po"),
+ ],
+ ),
+ ]
+ self.assertEqual([c.args for c in mock_compile_messages.mock_calls], expected)
+
class CompilationErrorHandling(MessageCompilationTests):
def test_error_reported_by_msgfmt(self):