from fontTools.misc.loggingTools import ( LevelFormatter, Timer, configLogger, ChannelsFilter, LogMixin, ) from io import StringIO import logging import textwrap import time import re import pytest def logger_name_generator(): basename = "fontTools.test#" num = 1 while True: yield basename+str(num) num += 1 unique_logger_name = logger_name_generator() @pytest.fixture def logger(): log = logging.getLogger(next(unique_logger_name)) configLogger(logger=log, level="DEBUG", stream=StringIO()) return log def test_LevelFormatter(): stream = StringIO() handler = logging.StreamHandler(stream) formatter = LevelFormatter( fmt={ '*': '[%(levelname)s] %(message)s', 'DEBUG': '%(name)s [%(levelname)s] %(message)s', 'INFO': '%(message)s', }) handler.setFormatter(formatter) name = next(unique_logger_name) log = logging.getLogger(name) log.setLevel(logging.DEBUG) log.addHandler(handler) log.debug("this uses a custom format string") log.info("this also uses a custom format string") log.warning("this one uses the default format string") assert stream.getvalue() == textwrap.dedent("""\ %s [DEBUG] this uses a custom format string this also uses a custom format string [WARNING] this one uses the default format string """ % name) class TimerTest(object): def test_split(self): timer = Timer() time.sleep(0.01) fist_lap = timer.split() assert timer.elapsed == fist_lap time.sleep(0.1) second_lap = timer.split() assert second_lap > fist_lap assert timer.elapsed == second_lap def test_time(self): timer = Timer() time.sleep(0.01) overall_time = timer.time() assert overall_time > 0 def test_context_manager(self): with Timer() as t: time.sleep(0.01) assert t.elapsed > 0 def test_using_logger(self, logger): with Timer(logger, 'do something'): time.sleep(0.01) assert re.match( r"Took [0-9]\.[0-9]{3}s to do something", logger.handlers[0].stream.getvalue()) def test_using_logger_calling_instance(self, logger): timer = Timer(logger) with timer(): time.sleep(0.01) assert re.match( r"elapsed time: [0-9]\.[0-9]{3}s", logger.handlers[0].stream.getvalue()) # do it again but with custom level with timer('redo it', level=logging.WARNING): time.sleep(0.02) assert re.search( r"WARNING: Took [0-9]\.[0-9]{3}s to redo it", logger.handlers[0].stream.getvalue()) def test_function_decorator(self, logger): timer = Timer(logger) @timer() def test1(): time.sleep(0.01) @timer('run test 2', level=logging.INFO) def test2(): time.sleep(0.02) test1() assert re.match( r"Took [0-9]\.[0-9]{3}s to run 'test1'", logger.handlers[0].stream.getvalue()) test2() assert re.search( r"Took [0-9]\.[0-9]{3}s to run test 2", logger.handlers[0].stream.getvalue()) def test_ChannelsFilter(logger): n = logger.name filtr = ChannelsFilter(n+".A.B", n+".C.D") handler = logger.handlers[0] handler.addFilter(filtr) stream = handler.stream logging.getLogger(n+".A.B").debug('this record passes through') assert 'this record passes through' in stream.getvalue() logging.getLogger(n+'.A.B.C').debug('records from children also pass') assert 'records from children also pass' in stream.getvalue() logging.getLogger(n+'.C.D').debug('this one as well') assert 'this one as well' in stream.getvalue() logging.getLogger(n+'.A.B.').debug('also this one') assert 'also this one' in stream.getvalue() before = stream.getvalue() logging.getLogger(n+'.A.F').debug('but this one does not!') assert before == stream.getvalue() logging.getLogger(n+'.C.DE').debug('neither this one!') assert before == stream.getvalue() def test_LogMixin(): class Base(object): pass class A(LogMixin, Base): pass class B(A): pass a = A() b = B() assert hasattr(a, 'log') assert hasattr(b, 'log') assert isinstance(a.log, logging.Logger) assert isinstance(b.log, logging.Logger) assert a.log.name == "loggingTools_test.A" assert b.log.name == "loggingTools_test.B"