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

Logging integration #55

Merged
merged 5 commits into from
Sep 14, 2020
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
6 changes: 6 additions & 0 deletions docs/releasehistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Releases follow the ``major.minor.micro`` scheme recommended by `PEP440 <https:/

This is a micro release that includes general bug fixes and stability improvements. It is still a preliminary version of the Open Force Field to PELE package which is under development.

New features
""""""""""""
- `PR #55 <https://github.com/martimunicoy/offpele/pull/55>`_: Standard output prints follow the logging hierarchy and can be modified by the user.

Bugfixes
""""""""
- `PR #48 <https://github.com/martimunicoy/offpele/pull/48>`_: Fixes CLI's default output paths.
Expand All @@ -22,6 +26,8 @@ Tests added
"""""""""""
- `PR #48 <https://github.com/martimunicoy/offpele/pull/48>`_: Adds tests to validate the assignment of the default output paths.
- `PR #52 <https://github.com/martimunicoy/offpele/pull/52>`_: Adds tests to validate the initialization using a connectivity template.
- `PR #55 <https://github.com/martimunicoy/offpele/pull/55>`_: Adds tests for the new Logger class.


0.3.0 - Rotamers, OPLS2005, SMILES and stability improvements
-------------------------------------------------------------
Expand Down
64 changes: 42 additions & 22 deletions offpele/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import argparse as ap

import offpele
from offpele.utils import check_if_path_exists, create_path
from offpele.utils import check_if_path_exists, create_path, Logger


DEFAULT_OFF_FORCEFIELD = 'openff_unconstrained-1.2.0.offxml'
Expand Down Expand Up @@ -73,12 +73,22 @@ def parse_args():
action='store_true',
help="Use OPLS to set the parameters for bonds "
+ "and angles")
parser.add_argument('-s', '--silent',
dest="silent",
action='store_true',
help="Activate silent mode")
parser.add_argument('-d', '--debug',
dest="silent",
action='store_true',
help="Activate debug mode")

parser.set_defaults(as_datalocal=False)
parser.set_defaults(with_solvent=False)
parser.set_defaults(include_terminal_rotamers=False)
parser.set_defaults(use_OPLS_nb_params=False)
parser.set_defaults(use_OPLS_bonds_and_angles=False)
parser.set_defaults(silent=False)
parser.set_defaults(debug=False)

args = parser.parse_args()

Expand Down Expand Up @@ -177,27 +187,24 @@ def run_offpele(pdb_file, forcefield=DEFAULT_OFF_FORCEFIELD,
Whether to save output files following PELE's DataLocal hierarchy or
not
"""
print('-' * 60)
print('Open Force Field parameterizer for PELE', offpele.__version__)
print('-' * 60)
print(' - General:')
print(' - Input PDB:', pdb_file)
print(' - Output path:', output)
print(' - Write solvent parameters:', with_solvent)
print(' - DataLocal-like output:', as_datalocal)
print(' - Parameterization:')
print(' - Force field:', forcefield)
print(' - Charges method:', charges_method)
print(' - Use OPLS nonbonding parameters:', use_OPLS_nb_params)
print(' - Use OPLS bonds and angles:', use_OPLS_bonds_and_angles)
print(' - Rotamer library:')
print(' - Resolution:', resolution)
print(' - Exclude terminal rotamers:', exclude_terminal_rotamers)
print('-' * 60)

# Supress OpenForceField toolkit warnings
import logging
logging.getLogger().setLevel(logging.ERROR)
log = Logger()
log.info('-' * 60)
log.info('Open Force Field parameterizer for PELE', offpele.__version__)
log.info('-' * 60)
log.info(' - General:')
log.info(' - Input PDB:', pdb_file)
log.info(' - Output path:', output)
log.info(' - Write solvent parameters:', with_solvent)
log.info(' - DataLocal-like output:', as_datalocal)
log.info(' - Parameterization:')
log.info(' - Force field:', forcefield)
log.info(' - Charges method:', charges_method)
log.info(' - Use OPLS nonbonding parameters:', use_OPLS_nb_params)
log.info(' - Use OPLS bonds and angles:', use_OPLS_bonds_and_angles)
log.info(' - Rotamer library:')
log.info(' - Resolution:', resolution)
log.info(' - Exclude terminal rotamers:', exclude_terminal_rotamers)
log.info('-' * 60)

from offpele.topology import Molecule
from offpele.template import Impact
Expand Down Expand Up @@ -247,6 +254,19 @@ def main():

exclude_terminal_rotamers = not args.include_terminal_rotamers

# Supress OpenForceField toolkit warnings
import logging
logging.getLogger().setLevel(logging.ERROR)

# Set offpele logger to the corresponding level
logger = Logger()
if args.silent:
logger.set_level('CRITICAL')
elif args.debug:
logger.set_level('DEBUG')
else:
logger.set_level('INFO')

run_offpele(args.pdb_file, args.forcefield, args.resolution,
args.charges_method, args.use_OPLS_nb_params,
args.use_OPLS_bonds_and_angles, exclude_terminal_rotamers,
Expand Down
4 changes: 3 additions & 1 deletion offpele/solvent/solvent.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from offpele.utils import get_data_file_path, warning_on_one_line
from offpele.utils.toolkits import OpenForceFieldToolkitWrapper
from offpele.utils import Logger


class _SolventWrapper(object):
Expand Down Expand Up @@ -42,7 +43,8 @@ def _initialize_from_molecule(self):
"""
Initializes a SolventWrapper object using an offpele's Molecule.
"""
print(' - Loading solvent parameters')
logger = Logger()
logger.info(' - Loading solvent parameters')

off_toolkit = OpenForceFieldToolkitWrapper()

Expand Down
151 changes: 151 additions & 0 deletions offpele/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
"""
This module contains the tests to check some handy classes and functions
of offpele.
"""


import pytest

import io
from contextlib import redirect_stdout
from offpele.utils import Logger


class TestLogger(object):
def test_logger_levels(self):
"""
It checks the correct behaviour of the different log levels.
"""
def push_messages(log):
"""Pull some messages at different levels."""
log.debug('Debug message')
log.info('Info message')
log.warning('Warn message')
log.error('Error message')
log.critical('Critical message')

import logging

# Initiate logger
log = Logger()

# Try the default level (INFO)
# Catch logger messages to string buffer
with io.StringIO() as buf:
# Add custom handler to logger
log_handler = logging.StreamHandler(buf)
log._logger.handlers = list()
log._logger.addHandler(log_handler)

# Push messages
push_messages(log)

# Get string from buffer
output = buf.getvalue()

assert output == 'Info message\nWarn message\n' \
+ 'Error message\nCritical message\n', \
'Unexpected logger message at standard output'

# Try DEBUG level
# Catch logger messages to string buffer
with io.StringIO() as buf:
# Add custom handler to logger
log_handler = logging.StreamHandler(buf)
log._logger.handlers = list()
log._logger.addHandler(log_handler)

# Try DEBUG level
log.set_level('DEBUG')

# Push messages
push_messages(log)

# Get string from buffer
output = buf.getvalue()

assert output == 'Debug message\nInfo message\n'\
+ 'Warn message\nError message\nCritical message\n', \
'Unexpected logger message at standard output'

# Try INFO level
# Catch logger messages to string buffer
with io.StringIO() as buf:
# Add custom handler to logger
log_handler = logging.StreamHandler(buf)
log._logger.handlers = list()
log._logger.addHandler(log_handler)

# Try INFO level
log.set_level('INFO')

# Push messages
push_messages(log)

# Get string from buffer
output = buf.getvalue()

assert output == 'Info message\nWarn message\n' \
+ 'Error message\nCritical message\n', \
'Unexpected logger message at standard output'

# Try WARNING level
# Catch logger messages to string buffer
with io.StringIO() as buf:
# Add custom handler to logger
log_handler = logging.StreamHandler(buf)
log._logger.handlers = list()
log._logger.addHandler(log_handler)

# Try WARNING level
log.set_level('WARNING')

# Push messages
push_messages(log)

# Get string from buffer
output = buf.getvalue()

assert output == 'Warn message\nError message\n' \
+ 'Critical message\n', \
'Unexpected logger message at standard output'

# Try ERROR level
# Catch logger messages to string buffer
with io.StringIO() as buf:
# Add custom handler to logger
log_handler = logging.StreamHandler(buf)
log._logger.handlers = list()
log._logger.addHandler(log_handler)

# Try ERROR level
log.set_level('ERROR')

# Push messages
push_messages(log)

# Get string from buffer
output = buf.getvalue()

assert output == 'Error message\nCritical message\n', \
'Unexpected logger message at standard output'

# Try CRITICAL level
# Catch logger messages to string buffer
with io.StringIO() as buf:
# Add custom handler to logger
log_handler = logging.StreamHandler(buf)
log._logger.handlers = list()
log._logger.addHandler(log_handler)

# Try CRITICAL level
log.set_level('CRITICAL')

# Push messages
push_messages(log)

# Get string from buffer
output = buf.getvalue()

assert output == 'Critical message\n', \
'Unexpected logger message at standard output'
Loading