Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/logger #36

Merged
merged 3 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions PQAnalysis/traj/trajectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand All @@ -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",
Expand Down Expand Up @@ -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:
"""
Expand Down
20 changes: 18 additions & 2 deletions PQAnalysis/utils/custom_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +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.
"""
if exception is not None:
extra = {'custom_exception': exception}
else:
extra = None

self._original_log(
level,
msg,
args,
extra,
**kwargs
)

Expand Down Expand Up @@ -145,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.
Expand All @@ -160,9 +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)
super()._log(level, msg, args, extra=extra, **kwargs)

def error(self,
msg: Any,
Expand Down Expand Up @@ -321,7 +330,14 @@ def format(self, record: logging.LogRecord) -> str:
longest_level_key = max(level_keys, key=len)

name = record.name
header = f'{formatted_level} {name}\n\n'

if hasattr(record, 'custom_exception'):
header = (
f'{formatted_level} {name} - '
f'{record.custom_exception.__qualname__}\n\n'
)
else:
header = f'{formatted_level} {name}\n\n'

messages = message.split('\n')
wrapper = textwrap.TextWrapper(
Expand Down
30 changes: 25 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,23 +88,43 @@ 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:
result = function(*args, **kwargs)
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")]

for message in messages:
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
)
21 changes: 11 additions & 10 deletions tests/topology/test_topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand All @@ -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'))
Expand Down
80 changes: 50 additions & 30 deletions tests/traj/test_trajectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import pytest
import numpy as np

from ..conftest import assert_logging
from ..conftest import assert_logging, assert_logging_with_exception

from PQAnalysis.traj import Trajectory
from PQAnalysis.core import Cell, Atom
Expand Down Expand Up @@ -163,70 +163,90 @@ def test_window(self, caplog):
traj.window(2, 2).__next__,
)

assert_logging(
assert_logging_with_exception(
caplog,
Trajectory.__qualname__,
exception=IndexError,
logging_level="ERROR",
message_to_test=(
"window size can not be less than 1 or greater than the length of the trajectory"
),
function=traj.window(0).__next__,
)

assert_logging(
assert_logging_with_exception(
caplog,
Trajectory.__qualname__,
"ERROR",
"window size can not be less than 1 or greater than the length of the trajectory",
traj.window(4).__next__,
exception=IndexError,
logging_level="ERROR",
message_to_test=(
"window size can not be less than 1 or greater than the length of the trajectory"
),
function=traj.window(4).__next__,
)

assert_logging(
assert_logging_with_exception(
caplog,
Trajectory.__qualname__,
"ERROR",
"window gap can not be less than 1 or greater than the length of the trajectory",
traj.window(1, 0).__next__,
exception=IndexError,
logging_level="ERROR",
message_to_test=(
"window gap can not be less than 1 or greater than the length of the trajectory"
),
function=traj.window(1, 0).__next__,
)

assert_logging(
assert_logging_with_exception(
caplog,
Trajectory.__qualname__,
"ERROR",
"window gap can not be less than 1 or greater than the length of the trajectory",
traj.window(1, 4).__next__,
exception=IndexError,
logging_level="ERROR",
message_to_test=(
"window gap can not be less than 1 or greater than the length of the trajectory"
),
function=traj.window(1, 4).__next__,
)

assert_logging(
assert_logging_with_exception(
caplog,
Trajectory.__qualname__,
"ERROR",
"start index is less than 0 or greater than the length of the trajectory",
traj.window(1, 1, window_start=-1).__next__,
exception=IndexError,
logging_level="ERROR",
message_to_test=(
"start index is less than 0 or greater than the length of the trajectory"
),
function=traj.window(1, 1, window_start=-1).__next__,
)

assert_logging(
assert_logging_with_exception(
caplog,
Trajectory.__qualname__,
"ERROR",
"stop index is less than 0 or greater than the length of the trajectory",
traj.window(1, 1, window_stop=-1).__next__,
exception=IndexError,
logging_level="ERROR",
message_to_test=(
"stop index is less than 0 or greater than the length of the trajectory"
),
function=traj.window(1, 1, window_stop=-1).__next__,
)

assert_logging(
assert_logging_with_exception(
caplog,
Trajectory.__qualname__,
"ERROR",
"start index is greater than or equal to the stop index",
traj.window(1, 1, window_start=2, window_stop=1).__next__,
exception=IndexError,
logging_level="ERROR",
message_to_test=("start index is greater than or equal to the stop index"),
function=traj.window(1, 1, window_start=2, window_stop=1).__next__,
)

assert_logging(
assert_logging_with_exception(
caplog,
Trajectory.__qualname__,
"ERROR",
"window size is greater than the window_stop - window_start",
traj.window(3, 1, window_start=1, window_stop=3).__next__,
exception=IndexError,
logging_level="ERROR",
message_to_test=(
"window size is greater than the window_stop - window_start"
),
function=traj.window(3, 1, window_start=1, window_stop=3).__next__,
)

def test__iter__(self):
Expand Down
Loading