Files
changedetection.io/changedetectionio/tests/unit/test_magic_puremagic_logging.py
James TannahillandClaude Opus 5.5 e3e51a3a33 Log puremagic "Could not identify file" at debug instead of warning (#4533)
* Log puremagic 'Could not identify file' at debug, not warning

puremagic raises PureError when no signature matches, which is the normal
result for plain text and most HTML pages. guess_stream_type() caught it
with every other exception and logged a warning on many checks, although
the content-based detection that follows handles it as designed. Other
puremagic failures still log a warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Skip puremagic on empty content and catch PureError directly

puremagic.magic_string() raises ValueError('Input was empty') for empty
input, which is as normal as an unidentified signature, so skip the call
then. Import puremagic before the try (it is a hard dependency) so the
except clause can name PureError instead of comparing the class name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep the puremagic import inside the try so a missing library falls back

ImportError is caught before puremagic.PureError, so that clause is only
evaluated once the import has succeeded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 11:58:55 +02:00

56 lines
2.1 KiB
Python

#!/usr/bin/env python3
# coding=utf-8
# run from dir above changedetectionio/ dir
# python3 -m unittest changedetectionio.tests.unit.test_magic_puremagic_logging
"""puremagic raises PureError when no file signature matches, which is the normal result for
plain text and most HTML, and ValueError on empty input. Neither is an error and neither should
be logged as a warning, but any other failure from puremagic still should be."""
import unittest
from unittest import mock
from loguru import logger
from changedetectionio.processors.magic import guess_stream_type
class TestPuremagicLogging(unittest.TestCase):
def setUp(self):
self.records = []
self.sink_id = logger.add(lambda m: self.records.append(m.record), level="DEBUG")
def tearDown(self):
logger.remove(self.sink_id)
def warnings(self):
return [r for r in self.records if r["level"].name == "WARNING" and "puremagic" in r["message"]]
def test_unidentified_content_is_not_a_warning(self):
result = guess_stream_type(http_content_header="text/plain", content="just some plain text, no signature")
self.assertTrue(result.is_plaintext)
self.assertEqual(self.warnings(), [])
def test_empty_content_is_not_a_warning(self):
guess_stream_type(http_content_header="text/html", content="")
self.assertEqual(self.warnings(), [])
def test_other_puremagic_failures_still_warn(self):
with mock.patch("puremagic.magic_string", side_effect=ValueError("boom")):
result = guess_stream_type(http_content_header="text/plain", content="just some plain text")
self.assertTrue(result.is_plaintext)
self.assertEqual(len(self.warnings()), 1)
def test_missing_library_falls_back(self):
# A None entry in sys.modules makes "import puremagic" raise ImportError
with mock.patch.dict("sys.modules", {"puremagic": None}):
result = guess_stream_type(http_content_header="text/plain", content="just some plain text")
self.assertTrue(result.is_plaintext)
self.assertEqual(len(self.warnings()), 1)
if __name__ == '__main__':
unittest.main()