From 8ab4f60506451aeb97c16b221a0918baebac6020 Mon Sep 17 00:00:00 2001 From: Jakob Gamper <97gamjak@gmail.com> Date: Mon, 6 May 2024 00:35:23 +0200 Subject: [PATCH] now possible to check also for logger exception types --- PQAnalysis/traj/trajectory.py | 18 +++++++++++------- PQAnalysis/utils/custom_logging.py | 29 +++++++++++++---------------- tests/conftest.py | 30 +++++++++++++++++++++++++----- tests/topology/test_topology.py | 21 +++++++++++---------- 4 files changed, 60 insertions(+), 38 deletions(-) diff --git a/PQAnalysis/traj/trajectory.py b/PQAnalysis/traj/trajectory.py index 829b35e8..f9a9bda3 100644 --- a/PQAnalysis/traj/trajectory.py +++ b/PQAnalysis/traj/trajectory.py @@ -184,8 +184,8 @@ def window( ------- If not all frames are included in the windows, a warning is issued. - Returns - ------- + Yields + ------ Iterable[Trajectory] An iterable over the windows of the trajectory with the specified window size and gap. """ @@ -194,28 +194,32 @@ def window( if window_stop is None: window_stop = len(self) - # If window_start is less than 0 or greater than the length of the trajectory, raise an IndexError + # If window_start is less than 0 or greater than the + # length of the trajectory, raise an IndexError if window_start < 0 or window_start > len(self): self.logger.error( "start index is less than 0 or greater than the length of the trajectory", exception=IndexError, ) - # If window_stop is less than 0 or greater than the length of the trajectory, raise an IndexError + # If window_stop is less than 0 or greater than the + # length of the trajectory, raise an IndexError if window_stop < 0 or window_stop > len(self): self.logger.error( "stop index is less than 0 or greater than the length of the trajectory", exception=IndexError, ) - # If window_step is less than 1 or greater than the length of the trajectory, raise an IndexError + # If window_step is less than 1 or greater than + # the length of the trajectory, raise an IndexError if window_size < 1 or window_size > len(self): self.logger.error( "window size can not be less than 1 or greater than the length of the trajectory", exception=IndexError, ) - # If window_gap is less than 1 or greater than the length of the trajectory, raise an IndexError + # If window_gap is less than 1 or greater than + # the length of the trajectory, raise an IndexError if window_gap < 1 or window_gap > len(self): self.logger.error( "window gap can not be less than 1 or greater than the length of the trajectory", @@ -245,7 +249,7 @@ def window( # generate the window of the trajectory for i in range(window_start, window_stop - window_size + 1, window_gap): - yield self[i : i + window_size] + yield self[i: i + window_size] def __contains__(self, item: AtomicSystem) -> bool: """ diff --git a/PQAnalysis/utils/custom_logging.py b/PQAnalysis/utils/custom_logging.py index c913dd4b..e16ea680 100644 --- a/PQAnalysis/utils/custom_logging.py +++ b/PQAnalysis/utils/custom_logging.py @@ -107,12 +107,16 @@ def _log(self, # pylint: disable=arguments-differ if the level is logging.ERROR or logging.CRITICAL and the logger is not enabled for logging.DEBUG. """ - self.custom_exception = exception + if exception is not None: + extra = {'custom_exception': exception} + else: + extra = None self._original_log( level, msg, args, + extra, **kwargs ) @@ -147,6 +151,7 @@ def _original_log(self, level: Any, msg: Any, args: Any, + extra=None, **kwargs) -> None: """ The original _log method of the logging.Logger class. @@ -162,22 +167,11 @@ def _original_log(self, The message to log. args : Any The arguments of the log message. + extra : Any, optional + Additional information to log, by default None. """ - super()._log(level, msg, args, **kwargs) - - def makeRecord(self, name, level, fn, lno, msg, args, exc_info, - func=None, extra=None, sinfo=None): - """ - This method creates a log record. - """ - - record = super().makeRecord(name, level, fn, lno, msg, args, exc_info, - func=func, extra=extra, sinfo=sinfo) - if hasattr(self, 'custom_exception'): - setattr(record, 'custom_exception', self.custom_exception) - - return record + super()._log(level, msg, args, extra=extra, **kwargs) def error(self, msg: Any, @@ -338,7 +332,10 @@ def format(self, record: logging.LogRecord) -> str: name = record.name if hasattr(record, 'custom_exception'): - header = f'{formatted_level} {name} - {record.custom_exception}\n\n' + header = ( + f'{formatted_level} {name} - ' + f'{record.custom_exception.__qualname__}\n\n' + ) else: header = f'{formatted_level} {name}\n\n' diff --git a/tests/conftest.py b/tests/conftest.py index d46b4b9c..00bd0356 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -88,7 +88,7 @@ def caplog_for_logger(caplog, logger_name, level): logger.removeHandler(caplog.handler) -def assert_logging(caplog, logging_name, logging_level, message_to_test, function, *args, **kwargs): +def assert_logging_with_exception(caplog, logging_name, logging_level, message_to_test, exception, function, *args, **kwargs): with caplog_for_logger(caplog, __package_name__ + "." + logging_name, logging_level): result = None try: @@ -96,11 +96,18 @@ def assert_logging(caplog, logging_name, logging_level, message_to_test, functio except SystemExit: pass - assert caplog.record_tuples[0][0] == __package_name__ + \ + record = caplog.records[0] + + assert record.name == __package_name__ + \ "." + logging_name - assert caplog.record_tuples[0][1] == logging.getLevelName( - logging_level) - message = caplog.record_tuples[0][2] + assert record.levelno == logging.getLevelName( + logging_level + ) + + if exception is not None: + assert record.custom_exception == exception + + message = record.msg messages = [message.strip() for message in message.split("\n")] @@ -108,3 +115,16 @@ def assert_logging(caplog, logging_name, logging_level, message_to_test, functio assert message in message_to_test return result + + +def assert_logging(caplog, logging_name, logging_level, message_to_test, function, *args, **kwargs): + return assert_logging_with_exception( + caplog, + logging_name, + logging_level, + message_to_test, + None, + function, + *args, + **kwargs + ) diff --git a/tests/topology/test_topology.py b/tests/topology/test_topology.py index 6c340b50..7c02aec2 100644 --- a/tests/topology/test_topology.py +++ b/tests/topology/test_topology.py @@ -147,17 +147,17 @@ def test_setup_residues(self, caplog): topology.reference_residues = reference_residues assert_logging( - caplog, - Topology.__qualname__, - "ERROR", - ( + caplog=caplog, + logging_name=Topology.__qualname__, + logging_level="ERROR", + message_to_test=( "The element of atom 0 is not set. If any reference residues are given the " "program tries to automatically deduce the residues from the residue ids and " "the reference residues. This means that any atom with an unknown element " "raises an error. To avoid deducing residue information please set 'check_residues' " "to False" ), - topology._setup_residues, + function=topology._setup_residues, residue_ids=residue_ids, atoms=atoms ) @@ -167,19 +167,20 @@ def test_setup_residues(self, caplog): topology.reference_residues = reference_residues residues, new_atoms = assert_logging( - caplog, - Topology.__qualname__, - "WARNING", - ( + caplog=caplog, + logging_name=Topology.__qualname__, + logging_level="WARNING", + message_to_test=( "The element of atom 1 (Element(c, 6, 12.0107)) does not match " "the element of the reference residue ALA (Element(h, 1, 1.00794)). " "Therefore the element type of the residue description will be used " "within the topology format!" ), - topology._setup_residues, + function=topology._setup_residues, residue_ids=residue_ids, atoms=atoms, ) + assert len(residues) == 2 assert new_atoms == atoms assert residues[0] == QMResidue(Element('C'))