Adds Functionality to Logger
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
from diceplayer.shared.utils.logger import Logger
|
||||||
|
|
||||||
|
|
||||||
|
logger = Logger(__name__)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from diceplayer.shared.interface.dice_interface import DiceInterface
|
from diceplayer.shared.interface.dice_interface import DiceInterface
|
||||||
from diceplayer.player import Player
|
from diceplayer.player import Player
|
||||||
|
from diceplayer import logger
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import argparse
|
import argparse
|
||||||
@@ -40,6 +41,7 @@ def main():
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Open OUTFILE for writing and print keywords and initial info
|
# Open OUTFILE for writing and print keywords and initial info
|
||||||
|
logger.set_logger(args.outfile, logging.INFO)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
@@ -55,12 +57,6 @@ def main():
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
sys.exit(err)
|
sys.exit(err)
|
||||||
|
|
||||||
logging.basicConfig(
|
|
||||||
filename=args.outfile,
|
|
||||||
format='%(message)s',
|
|
||||||
level=logging.INFO
|
|
||||||
)
|
|
||||||
|
|
||||||
player = Player(args.infile)
|
player = Player(args.infile)
|
||||||
|
|
||||||
player.start()
|
player.start()
|
||||||
|
|||||||
@@ -42,6 +42,29 @@ class System:
|
|||||||
raise TypeError("Error: nmols is not an integer")
|
raise TypeError("Error: nmols is not an integer")
|
||||||
self.nmols.append(nmols)
|
self.nmols.append(nmols)
|
||||||
|
|
||||||
|
def update_molecule(self, position: np.ndarray, fh: TextIO) -> None:
|
||||||
|
"""Updates the position of the molecule in the Output file
|
||||||
|
|
||||||
|
Args:
|
||||||
|
position (np.ndarray): numpy position vector
|
||||||
|
fh (TextIO): Output file
|
||||||
|
"""
|
||||||
|
|
||||||
|
position_in_ang = (position * BOHR2ANG).tolist()
|
||||||
|
self.add_type(self.nmols[0], deepcopy(self.molecule[0]))
|
||||||
|
|
||||||
|
for atom in self.molecule[-1].atom:
|
||||||
|
|
||||||
|
atom.rx = position_in_ang.pop(0)
|
||||||
|
atom.ry = position_in_ang.pop(0)
|
||||||
|
atom.rz = position_in_ang.pop(0)
|
||||||
|
|
||||||
|
rmsd, self.molecule[0] = self.rmsd_fit(-1, 0)
|
||||||
|
self.molecule.pop(-1)
|
||||||
|
|
||||||
|
fh.write("\nProjected new conformation of reference molecule with RMSD fit\n")
|
||||||
|
fh.write("RMSD = {:>8.5f} Angstrom\n".format(rmsd))
|
||||||
|
|
||||||
def rmsd_fit(self, p_index: int, r_index: int) -> Tuple[float, Molecule]:
|
def rmsd_fit(self, p_index: int, r_index: int) -> Tuple[float, Molecule]:
|
||||||
|
|
||||||
projecting_mol = self.molecule[p_index]
|
projecting_mol = self.molecule[p_index]
|
||||||
@@ -176,65 +199,43 @@ class System:
|
|||||||
# self.molecule.pop(-1)
|
# self.molecule.pop(-1)
|
||||||
#
|
#
|
||||||
# return min_dist, nearestmol
|
# return min_dist, nearestmol
|
||||||
def update_molecule(self, position: np.ndarray, fh: TextIO) -> None:
|
|
||||||
"""Updates the position of the molecule in the Output file
|
|
||||||
|
|
||||||
Args:
|
|
||||||
position (np.ndarray): numpy position vector
|
|
||||||
fh (TextIO): Output file
|
|
||||||
"""
|
|
||||||
|
|
||||||
position_in_ang = (position * BOHR2ANG).tolist()
|
|
||||||
self.add_type(self.nmols[0], deepcopy(self.molecule[0]))
|
|
||||||
|
|
||||||
for atom in self.molecule[-1].atom:
|
|
||||||
|
|
||||||
atom.rx = position_in_ang.pop(0)
|
|
||||||
atom.ry = position_in_ang.pop(0)
|
|
||||||
atom.rz = position_in_ang.pop(0)
|
|
||||||
|
|
||||||
rmsd, self.molecule[0] = self.rmsd_fit(-1, 0)
|
|
||||||
self.molecule.pop(-1)
|
|
||||||
|
|
||||||
fh.write("\nProjected new conformation of reference molecule with RMSD fit\n")
|
|
||||||
fh.write("RMSD = {:>8.5f} Angstrom\n".format(rmsd))
|
|
||||||
|
|
||||||
|
|
||||||
def print_geom(self, cycle: int, fh: TextIO) -> None:
|
# def print_geom(self, cycle: int, fh: TextIO) -> None:
|
||||||
"""
|
# """
|
||||||
Print the geometry of the molecule in the Output file
|
# Print the geometry of the molecule in the Output file
|
||||||
|
#
|
||||||
Args:
|
# Args:
|
||||||
cycle (int): Number of the cycle
|
# cycle (int): Number of the cycle
|
||||||
fh (TextIO): Output file
|
# fh (TextIO): Output file
|
||||||
"""
|
# """
|
||||||
|
#
|
||||||
fh.write("Cycle # {}\n".format(cycle))
|
# fh.write("Cycle # {}\n".format(cycle))
|
||||||
fh.write("Number of site: {}\n".format(len(self.molecule[0].atom)))
|
# fh.write("Number of site: {}\n".format(len(self.molecule[0].atom)))
|
||||||
for atom in self.molecule[0].atom:
|
# for atom in self.molecule[0].atom:
|
||||||
symbol = atomsymb[atom.na]
|
# symbol = atomsymb[atom.na]
|
||||||
fh.write(
|
# fh.write(
|
||||||
"{:<2s} {:>10.6f} {:>10.6f} {:>10.6f}\n".format(
|
# "{:<2s} {:>10.6f} {:>10.6f} {:>10.6f}\n".format(
|
||||||
symbol, atom.rx, atom.ry, atom.rz
|
# symbol, atom.rx, atom.ry, atom.rz
|
||||||
)
|
# )
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
def printChargesAndDipole(self, cycle: int, fh: TextIO) -> None:
|
# def printChargesAndDipole(self, cycle: int, fh: TextIO) -> None:
|
||||||
"""
|
# """
|
||||||
Print the charges and dipole of the molecule in the Output file
|
# Print the charges and dipole of the molecule in the Output file
|
||||||
|
#
|
||||||
Args:
|
# Args:
|
||||||
cycle (int): Number of the cycle
|
# cycle (int): Number of the cycle
|
||||||
fh (TextIO): Output file
|
# fh (TextIO): Output file
|
||||||
"""
|
# """
|
||||||
|
#
|
||||||
fh.write("Cycle # {}\n".format(cycle))
|
# fh.write("Cycle # {}\n".format(cycle))
|
||||||
fh.write("Number of site: {}\n".format(len(self.molecule[0].atom)))
|
# fh.write("Number of site: {}\n".format(len(self.molecule[0].atom)))
|
||||||
|
#
|
||||||
chargesAndDipole = self.molecule[0].charges_and_dipole()
|
# chargesAndDipole = self.molecule[0].charges_and_dipole()
|
||||||
|
#
|
||||||
fh.write(
|
# fh.write(
|
||||||
"{:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n".format(
|
# "{:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n".format(
|
||||||
chargesAndDipole[0], chargesAndDipole[1], chargesAndDipole[2], chargesAndDipole[3], chargesAndDipole[4]
|
# chargesAndDipole[0], chargesAndDipole[1], chargesAndDipole[2], chargesAndDipole[3], chargesAndDipole[4]
|
||||||
)
|
# )
|
||||||
)
|
# )
|
||||||
|
|||||||
@@ -1,27 +1,54 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
def valid_logger(func):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
logger = args[0]
|
||||||
|
assert logger._was_set, \
|
||||||
|
"Logger is not set. Please call set_logger() first."
|
||||||
|
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class Logger:
|
class Logger:
|
||||||
outfile = None
|
outfile = None
|
||||||
|
|
||||||
_logger = None
|
_logger = None
|
||||||
_instance = None
|
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
_was_set = False
|
||||||
if not getattr(cls, '_instance'):
|
|
||||||
cls._instance = super(Logger, cls).__new__(cls)
|
|
||||||
return cls._instance
|
|
||||||
|
|
||||||
def set_logger(self, logger_name, outfile='run.log', level=logging.INFO):
|
def __init__(self, logger_name):
|
||||||
|
if self._logger is None:
|
||||||
|
self._logger = logging.getLogger(logger_name)
|
||||||
|
|
||||||
|
def set_logger(self, outfile='run.log', level=logging.INFO):
|
||||||
self.outfile = outfile
|
self.outfile = outfile
|
||||||
|
|
||||||
self._logger = logging.getLogger(logger_name)
|
|
||||||
|
|
||||||
if level is not None:
|
if level is not None:
|
||||||
self._logger.setLevel(level)
|
self._logger.setLevel(level)
|
||||||
|
|
||||||
self._create_handlers()
|
self._create_handlers()
|
||||||
|
|
||||||
|
self._was_set = True
|
||||||
|
|
||||||
|
@valid_logger
|
||||||
|
def info(self, message):
|
||||||
|
self._logger.info(message)
|
||||||
|
|
||||||
|
@valid_logger
|
||||||
|
def debug(self, message):
|
||||||
|
self._logger.debug(message)
|
||||||
|
|
||||||
|
@valid_logger
|
||||||
|
def warning(self, message):
|
||||||
|
self._logger.warning(message)
|
||||||
|
|
||||||
|
@valid_logger
|
||||||
|
def error(self, message):
|
||||||
|
self._logger.error(message)
|
||||||
|
|
||||||
def _create_handlers(self):
|
def _create_handlers(self):
|
||||||
handlers = []
|
handlers = []
|
||||||
if self.outfile is not None:
|
if self.outfile is not None:
|
||||||
|
|||||||
@@ -1,34 +1,96 @@
|
|||||||
from diceplayer.shared.utils.logger import Logger
|
from diceplayer.shared.utils.logger import Logger, valid_logger
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class TestValidateLogger(unittest.TestCase):
|
||||||
|
def test_validate_logger(self):
|
||||||
|
class MockLogger:
|
||||||
|
_was_set = True
|
||||||
|
|
||||||
|
@valid_logger
|
||||||
|
def test_func(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
MockLogger().test_func()
|
||||||
|
|
||||||
|
def test_validate_logger_exception(self):
|
||||||
|
class MockLogger:
|
||||||
|
_was_set = False
|
||||||
|
|
||||||
|
@valid_logger
|
||||||
|
def test_func(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
MockLogger().test_func()
|
||||||
|
|
||||||
|
|
||||||
class TestLogger(unittest.TestCase):
|
class TestLogger(unittest.TestCase):
|
||||||
def test_class_instantiation(self):
|
def test_class_instantiation(self):
|
||||||
logger = Logger()
|
logger = Logger('test')
|
||||||
|
|
||||||
self.assertIsInstance(logger, Logger)
|
self.assertIsInstance(logger, Logger)
|
||||||
|
|
||||||
def test_singleton(self):
|
@mock.patch('builtins.open', mock.mock_open())
|
||||||
logger1 = Logger()
|
|
||||||
logger2 = Logger()
|
|
||||||
|
|
||||||
self.assertIs(logger1, logger2)
|
|
||||||
|
|
||||||
def test_set_logger(self):
|
def test_set_logger(self):
|
||||||
logger = Logger()
|
logger = Logger('test')
|
||||||
logger.set_logger('test_logger')
|
logger.set_logger()
|
||||||
|
|
||||||
self.assertIsNotNone(logger._logger)
|
self.assertIsNotNone(logger._logger)
|
||||||
self.assertEqual(logger._logger.name, 'test_logger')
|
self.assertEqual(logger._logger.name, 'test')
|
||||||
|
|
||||||
|
@mock.patch('builtins.open', mock.mock_open())
|
||||||
def test_close(self):
|
def test_close(self):
|
||||||
logger = Logger()
|
logger = Logger('test')
|
||||||
logger.set_logger('test_logger')
|
logger.set_logger()
|
||||||
logger.close()
|
logger.close()
|
||||||
|
|
||||||
self.assertEqual(len(logger._logger.handlers), 0)
|
self.assertEqual(len(logger._logger.handlers), 0)
|
||||||
|
|
||||||
|
@mock.patch('builtins.open', mock.mock_open())
|
||||||
|
def test_info(self):
|
||||||
|
logger = Logger('test')
|
||||||
|
logger.set_logger()
|
||||||
|
|
||||||
|
with self.assertLogs(level='INFO') as cm:
|
||||||
|
logger.info('test')
|
||||||
|
|
||||||
|
self.assertEqual(cm.output, ['INFO:test:test'])
|
||||||
|
|
||||||
|
@mock.patch('builtins.open', mock.mock_open())
|
||||||
|
def test_debug(self):
|
||||||
|
logger = Logger('test')
|
||||||
|
logger.set_logger(level=logging.DEBUG)
|
||||||
|
|
||||||
|
with self.assertLogs(level='DEBUG') as cm:
|
||||||
|
logger.debug('test')
|
||||||
|
|
||||||
|
self.assertEqual(cm.output, ['DEBUG:test:test'])
|
||||||
|
|
||||||
|
@mock.patch('builtins.open', mock.mock_open())
|
||||||
|
def test_warning(self):
|
||||||
|
logger = Logger('test')
|
||||||
|
logger.set_logger()
|
||||||
|
|
||||||
|
with self.assertLogs(level='WARNING') as cm:
|
||||||
|
logger.warning('test')
|
||||||
|
|
||||||
|
self.assertEqual(cm.output, ['WARNING:test:test'])
|
||||||
|
|
||||||
|
@mock.patch('builtins.open', mock.mock_open())
|
||||||
|
def test_error(self):
|
||||||
|
logger = Logger('test')
|
||||||
|
logger.set_logger()
|
||||||
|
|
||||||
|
with self.assertLogs(level='ERROR') as cm:
|
||||||
|
logger.error('test')
|
||||||
|
|
||||||
|
self.assertEqual(cm.output, ['ERROR:test:test'])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user