Adds Functionality to Logger

This commit is contained in:
2023-04-27 05:14:07 -03:00
parent 2d488bd749
commit 9c822c6848
5 changed files with 177 additions and 87 deletions

View File

@@ -0,0 +1,4 @@
from diceplayer.shared.utils.logger import Logger
logger = Logger(__name__)

View File

@@ -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()

View File

@@ -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]
) # )
) # )

View File

@@ -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):
self.outfile = outfile
def __init__(self, logger_name):
if self._logger is None:
self._logger = logging.getLogger(logger_name) self._logger = logging.getLogger(logger_name)
def set_logger(self, outfile='run.log', level=logging.INFO):
self.outfile = outfile
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:

View File

@@ -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()