1
0
mirror of https://github.com/django/django.git synced 2025-08-21 01:09:13 +00:00

Fixed #26583 -- Silenced individual clashing name warnings in collectstatic's default verbosity.

Made collectstatic report individual destination conflicts only at verbosity 2+.
Made verbosity level 1 report a summary count of skipped files.
This commit is contained in:
James Bligh 2025-07-26 13:50:34 +01:00 committed by Sarah Boyce
parent 6537732585
commit 6142e3f347
3 changed files with 56 additions and 13 deletions

View File

@ -25,6 +25,7 @@ class Command(BaseCommand):
self.symlinked_files = []
self.unmodified_files = []
self.post_processed_files = []
self.skipped_files = []
self.storage = staticfiles_storage
self.style = no_style()
@ -134,12 +135,13 @@ class Command(BaseCommand):
found_files[prefixed_path] = (storage, path)
handler(path, prefixed_path, storage)
else:
self.skipped_files.append(prefixed_path)
self.log(
"Found another file with the destination path '%s'. It "
"will be ignored since only the first encountered file "
"is collected. If this is not what you want, make sure "
"every static file has a unique path." % prefixed_path,
level=1,
level=2,
)
# Storage backends may define a post_process() method.
@ -165,6 +167,7 @@ class Command(BaseCommand):
"modified": self.copied_files + self.symlinked_files,
"unmodified": self.unmodified_files,
"post_processed": self.post_processed_files,
"skipped": self.skipped_files,
}
def handle(self, **options):
@ -212,9 +215,10 @@ class Command(BaseCommand):
modified_count = len(collected["modified"])
unmodified_count = len(collected["unmodified"])
post_processed_count = len(collected["post_processed"])
skipped_count = len(collected["skipped"])
return (
"\n%(modified_count)s %(identifier)s %(action)s"
"%(destination)s%(unmodified)s%(post_processed)s."
"%(destination)s%(unmodified)s%(post_processed)s%(skipped)s."
) % {
"modified_count": modified_count,
"identifier": "static file" + ("" if modified_count == 1 else "s"),
@ -232,6 +236,11 @@ class Command(BaseCommand):
and ", %s post-processed" % post_processed_count
or ""
),
"skipped": (
", %s skipped due to conflict" % skipped_count
if collected["skipped"]
else ""
),
}
def log(self, msg, level=2):

View File

@ -470,6 +470,10 @@ Miscellaneous
* The minimum supported version of ``asgiref`` is increased from 3.8.1 to
3.9.1.
* The :djadmin:`collectstatic` command now reports only a summary of skipped
files due to conflicts when ``--verbosity`` is 1. To see warnings for each
conflicting destination path, set the ``--verbosity`` flag to 2 or higher.
.. _deprecated-features-6.0:
Features deprecated in 6.0

View File

@ -508,15 +508,17 @@ class TestCollectionOverwriteWarning(CollectionTestCase):
# looking for was emitted.
warning_string = "Found another file"
def _collectstatic_output(self, **kwargs):
def _collectstatic_output(self, verbosity=3, **kwargs):
"""
Run collectstatic, and capture and return the output. We want to run
the command at highest verbosity, which is why we can't
just call e.g. BaseCollectionTestCase.run_collectstatic()
Run collectstatic, and capture and return the output.
"""
out = StringIO()
call_command(
"collectstatic", interactive=False, verbosity=3, stdout=out, **kwargs
"collectstatic",
interactive=False,
verbosity=verbosity,
stdout=out,
**kwargs,
)
return out.getvalue()
@ -527,9 +529,10 @@ class TestCollectionOverwriteWarning(CollectionTestCase):
output = self._collectstatic_output(clear=True)
self.assertNotIn(self.warning_string, output)
def test_warning(self):
def test_warning_at_verbosity_2(self):
"""
There is a warning when there are duplicate destinations.
There is a warning when there are duplicate destinations at verbosity
2+.
"""
with tempfile.TemporaryDirectory() as static_dir:
duplicate = os.path.join(static_dir, "test", "file.txt")
@ -538,15 +541,42 @@ class TestCollectionOverwriteWarning(CollectionTestCase):
f.write("duplicate of file.txt")
with self.settings(STATICFILES_DIRS=[static_dir]):
output = self._collectstatic_output(clear=True)
output = self._collectstatic_output(clear=True, verbosity=2)
self.assertIn(self.warning_string, output)
os.remove(duplicate)
def test_no_warning_at_verbosity_1(self):
"""
There is no individual warning at verbosity 1, but summary is shown.
"""
with tempfile.TemporaryDirectory() as static_dir:
duplicate = os.path.join(static_dir, "test", "file.txt")
os.mkdir(os.path.dirname(duplicate))
with open(duplicate, "w+") as f:
f.write("duplicate of file.txt")
# Make sure the warning went away again.
with self.settings(STATICFILES_DIRS=[static_dir]):
output = self._collectstatic_output(clear=True)
output = self._collectstatic_output(clear=True, verbosity=1)
self.assertNotIn(self.warning_string, output)
self.assertIn("1 skipped due to conflict", output)
def test_summary_multiple_conflicts(self):
"""
Summary shows correct count for multiple conflicts.
"""
with tempfile.TemporaryDirectory() as static_dir:
duplicate1 = os.path.join(static_dir, "test", "file.txt")
os.makedirs(os.path.dirname(duplicate1))
with open(duplicate1, "w+") as f:
f.write("duplicate of file.txt")
duplicate2 = os.path.join(static_dir, "test", "file1.txt")
with open(duplicate2, "w+") as f:
f.write("duplicate of file1.txt")
duplicate3 = os.path.join(static_dir, "test", "nonascii.css")
shutil.copy2(duplicate1, duplicate3)
with self.settings(STATICFILES_DIRS=[static_dir]):
output = self._collectstatic_output(clear=True, verbosity=1)
self.assertIn("3 skipped due to conflict", output)
@override_settings(