PKzJ,iologger/__init__.py""" Decorator which logs the wrapped function/method. The following are logged: 1. name of the function called 2. arg(s) passed for the function called (if any) 3. kwarg(s) passed for the function called (if any) 4. execution time of the function called (in seconds) * also catches and logs any exceptions raised gracefully. """ import time from functools import partial, wraps from logbook import Logger __version__ = "1.1.1" def iologger(function=None, catch_exceptions=True): """ Decorator which logs the wrapped function/method. The following are logged: 1. name of the function called 2. arg(s) passed for the function called (if any) 3. kwarg(s) passed for the function called (if any) 4. execution time of the function called (in seconds) * also catches and logs any exceptions raised gracefully. :param catch_exceptions: will catch exceptions gracefully if true. :param function: func to run and all its args/kwargs. :return: returns func(*args, **kwargs) """ if function is None: return partial(iologger, catch_exceptions=catch_exceptions) logger = Logger("IOL - {}".format(function.__name__)) @wraps(function) def wrapper(*args, **kwargs) -> None: def run_function(func): start = time.time() result = func(*args, **kwargs) end = time.time() logger.debug("returned: '{}'".format(result)) elapsed = end - start logger.info("...Finished ({:f} seconds)".format(elapsed)) return result logger.debug("Starting...") arg_dict = dict() arg_dict['args'] = args arg_dict['kwargs'] = kwargs logger.debug("passed args/kwargs = {}".format(arg_dict)) if catch_exceptions: with logger.catch_exceptions(): return run_function(function) else: return run_function(function) return wrapper PKlJMMiologger/module_test.pyfrom io import StringIO import pytest from hypothesis import given from hypothesis.strategies import integers, permutations, text from logbook import StreamHandler from iologger import * @iologger def logged_function(a_string: str, an_int: int) -> str: """ Returns a str made from static text, a passed str, and a passed int. :param a_string: a str to be used in the returned string :param an_int: an int to be used in the returned string :return: a str which includes both a_string and an_int values """ return "Your str was '{}' and your int was '{}'.".format(a_string, an_int) @iologger def logged_exception_graceful() -> None: """ This function just raises an exception. :return: None """ raise PermissionError @iologger(catch_exceptions=False) def logged_exception_ungraceful() -> None: """ This function just raises an exception. :return: None """ raise PermissionError @pytest.fixture() def setup_logging(): logger = Logger('test_logger') return logger @given(t_str=text(alphabet='azbef'), t_int=integers()) def test_iologger_runs(t_str, t_int): assert logged_function(a_string=t_str, an_int=t_int) @given(t_str=permutations('azbef'), t_int=integers()) @pytest.mark.usefixtures('setup_logging') def test_args_logging(t_str, t_int): with StringIO() as logfile: stdout_handler = StreamHandler(logfile) stdout_handler.push_application() t_str = ''.join(t_str) logged_function(a_string=t_str, an_int=t_int) assert t_str in logfile.getvalue() assert str(t_int) in logfile.getvalue() stdout_handler.pop_application() @given(t_str=text(alphabet='azbef'), t_int=integers()) @pytest.mark.usefixtures('setup_logging') def test_iologger_debug_level(t_str, t_int): with StringIO() as logfile: stdout_handler = StreamHandler(logfile) stdout_handler.push_application() t_str = ''.join(t_str) logged_function(a_string=t_str, an_int=t_int) assert "Starting" in logfile.getvalue() assert "args/kwargs" in logfile.getvalue() assert "Finished" in logfile.getvalue() assert logfile.getvalue() assert len(logfile.getvalue().splitlines()) == 4 stdout_handler.pop_application() @given(t_str=text(alphabet='azbef'), t_int=integers()) @pytest.mark.usefixtures('setup_logging') def test_iologger_info_level(t_str, t_int): with StringIO() as logfile: stdout_handler = StreamHandler(logfile, level="INFO") stdout_handler.push_application() t_str = ''.join(t_str) logged_function(a_string=t_str, an_int=t_int) assert "Starting" not in logfile.getvalue() assert "args/kwargs" not in logfile.getvalue() assert "Finished" in logfile.getvalue() assert logfile.getvalue() assert len(logfile.getvalue().splitlines()) == 1 stdout_handler.pop_application() @given(t_str=text(alphabet='azbef'), t_int=integers()) @pytest.mark.usefixtures('setup_logging') def test_iologger_notice_level(t_str, t_int): with StringIO() as logfile: stdout_handler = StreamHandler(logfile, level="NOTICE") stdout_handler.push_application() t_str = ''.join(t_str) logged_function(a_string=t_str, an_int=t_int) assert "Starting" not in logfile.getvalue() assert "args/kwargs" not in logfile.getvalue() assert "Finished" not in logfile.getvalue() assert logfile.getvalue() == "" stdout_handler.pop_application() @given(t_str=text(alphabet='azbef'), t_int=integers()) @pytest.mark.usefixtures('setup_logging') def test_iologger_notice_level(t_str, t_int): with StringIO() as logfile: stdout_handler = StreamHandler(logfile, level="NOTICE") stdout_handler.push_application() t_str = ''.join(t_str) logged_function(a_string=t_str, an_int=t_int) assert "Starting" not in logfile.getvalue() assert "args/kwargs" not in logfile.getvalue() assert "Finished" not in logfile.getvalue() assert logfile.getvalue() == "" stdout_handler.pop_application() @pytest.mark.usefixtures('setup_logging') def test_iologger_exception_catching_graceful(): logged_exception_graceful() @pytest.mark.usefixtures('setup_logging') def test_iologger_exception_catching_ungraceful(): with pytest.raises(PermissionError): logged_exception_ungraceful() @pytest.mark.usefixtures('setup_logging') def test_iologger_exception_catching_logging(): with StringIO() as logfile: stdout_handler = StreamHandler(logfile) stdout_handler.push_application() logged_exception_graceful() assert "Starting" in logfile.getvalue() assert "args/kwargs" in logfile.getvalue() assert "PermissionError" in logfile.getvalue() stdout_handler.pop_application() @given(t_str=text(alphabet='azbef'), t_int=integers()) @pytest.mark.usefixtures('setup_logging') def test_iologger_exception_catching_graceful_logging(t_str, t_int): with StringIO() as logfile: stdout_handler = StreamHandler(logfile) stdout_handler.push_application() logged_exception_graceful() t_str = ''.join(t_str) logged_function(a_string=t_str, an_int=t_int) assert "Starting" in logfile.getvalue() assert "args/kwargs" in logfile.getvalue() assert "PermissionError" in logfile.getvalue() assert "Finished" in logfile.getvalue() stdout_handler.pop_application() if __name__ == "__main__": pytest.main(['-v']) PK!H|&Ubiologger-1.1.1.dist-info/WHEEL HM K-*ϳR03rOK-J,/RH,Q034 /, (-JLR()*M ILR(4KM̫#DPK!H(!iologger-1.1.1.dist-info/METADATAMo@9Hm9RF͡V[j<^z٥K1NZCyw>4Oc:it1[[,E(oruYmxXBSH^|!XU"ܓrV _M) sr/\2+3no"ԩmvCGɅv~ml)83uL ҞL!I`'KOs:,~ =HRiLl?Qa+Z,ClnFDVVdodkZޘȵ2uH}V#B~\GvLY+ ,;qU s<~ .'[o.z/DdF)tv 4=;GDzMiu+ PӋrv@{˿IJ vS7}-T9Y8rQu&. : s\dRmH;PK!H}Oniologger-1.1.1.dist-info/RECORDuι0g ʡ wD!AA|-tqyL儌i_'eh% uP3{\dֱd0و+KeFxG7i~= Vfk>wH*'*koOlZyM"#Sa~d<=D8+0?p:ւ,Qv:w˽UQ~Xqo緓5d71pޢa[ʟ-0PKzJ,iologger/__init__.pyPKlJMMiologger/module_test.pyPK!H|&UbIiologger-1.1.1.dist-info/WHEELPK!H(!iologger-1.1.1.dist-info/METADATAPK!H}On iologger-1.1.1.dist-info/RECORDPKo:"