Pre-commit hook to automatically detect and convert f-strings in Python code to printf-style logging calls, following W1203 Pylint rule:
To use it with pre-commit, add the following lines to your .pre-commit-config.yaml:
- repo: https://github.com/dmar1n/lazy-log-formatter
rev: 0.8.0
hooks:
- id: lazy-log-formatter
args: ['--fix']--fix: Automatically fix f-strings used in log calls to lazy log calls.DIR [DIR ...]: One or more directories to search for Python files. If not specified, defaults to the current directory.
Check all Python files in the current directory and subdirectories:
python -m src.cliCheck all Python files in two directories:
python -m src.cli src/ tests/Fix issues in all Python files in a directory:
python -m src.cli mydir --fixIf the --fix option is used, the hook will convert f-strings in log calls to lazy log calls, as follows:
# Before
logger.info(f'Hello {name}')
# After
logger.info('Hello %s', name)# Before
logger.info(f'Hello {name} {surname}')
# After
logger.info('Hello %s %s', name, surname)import logging
from datetime import datetime
def log_and_return_datetime():
now = datetime.now()
logging.info(f"Current datetime: {now}")
return now
class DateTimeLogger:
def __init__(self):
self._logger = logging.getLogger(self.__class__.__name__)
def log_datetime(self):
now = datetime.now()
self._logger.info(f"Current datetime: {now}")
return nowpython src\cli.py tests\dataThe output will be:
F-string in logging call at ...\tests\data\test.py:8: f'Current datetime: {now}'
F-string in logging call at ...\tests\data\test.py:18: f'Current datetime: {now}'
F-strings found and fixed in '...\tests\data\test.py'.
After running the formatter, the code will be transformed to:
import logging
from datetime import datetime
def log_and_return_datetime():
now = datetime.now()
logging.info("Current datetime: %s", now)
return now
class DateTimeLogger:
def __init__(self):
self._logger = logging.getLogger(self.__class__.__name__)
def log_datetime(self):
now = datetime.now()
self._logger.info("Current datetime: %s", now)
return nowOnly works with the native Python logging module. Other libraries, such as loguru, do not support lazy calls.
For loguru, see Lazy evaluation of expensive functions:
logger.opt(lazy=True).debug("If sink level <= DEBUG: {x}", x=lambda: expensive_function(2**64))