Skip to content

Instantly share code, notes, and snippets.

@gazpachoking
Last active December 12, 2019 21:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gazpachoking/4ec98e1362157aa17910e4b8e660225b to your computer and use it in GitHub Desktop.
Save gazpachoking/4ec98e1362157aa17910e4b8e660225b to your computer and use it in GitHub Desktop.
Converts files from stdlib to loguru logging
import ast
import pathlib
import re
import subprocess
import sys
import astor
import pyupgrade
def fix_log_call(node):
exception = False
if node.value.keywords:
if any(n.arg == 'exc_info' for n in node.value.keywords):
exception = True
node.value.keywords = [n for n in node.value.keywords if n.arg != 'exc_info']
text = astor.code_gen.to_source(node)
if isinstance(node.value.args[0], ast.BinOp) and isinstance(node.value.args[0].op, ast.Mod):
pct = node.value.args[0]
if not isinstance(pct.right, (ast.Tuple, ast.Dict)):
b = "({},)".format(astor.to_source(pct.right).strip())
pct.right = ast.parse(b).body[0].value
text = astor.to_source(node)
text = re.sub(r'\s+', ' ', text)
text = pyupgrade._fix_percent_format(text)
text = re.sub(r"\.format\((.*)\)", r", \1", text)
elif isinstance(node.value.args[0], ast.Constant):
node.value.args[0].n = pyupgrade._percent_to_format(node.value.args[0].n)
text = astor.to_source(node)
else:
print('possible fix needed on line {}: {}'.format(node.lineno, astor.to_source(node)))
if exception:
text = text.replace('log.', 'log.opt(exception=True).')
return text
a = ast.parse(text).body[0]
a.col_offset = node.col_offset
a.end_col_offset = node.end_col_offset
a.end_lineno = node.end_lineno
a.lineno = node.lineno
return a
def fix_file(source):
logcalls = []
parsed = ast.parse(source)
for node in ast.walk(parsed):
for child in ast.iter_child_nodes(node):
child.parent = node
for node in ast.walk(parsed):
if not (isinstance(node, ast.Expr) and isinstance(node.value, ast.Call)):
continue
if not (
isinstance(node.value.func, ast.Attribute)
and isinstance(node.value.func.value, ast.Name)
and node.value.func.value.id == 'log'
):
continue
if len(node.value.args) == 1 and not len(node.value.keywords):
if not isinstance(node.value.args[0], ast.BinOp):
continue
logcalls.append((ast.get_source_segment(source, node).strip(), fix_log_call(node).strip()))
text = source
for lc in logcalls:
text = text.replace(lc[0], lc[1])
text = text.replace('import logging\n', 'from loguru import logger\n')
text = re.sub(r'log = logging.getLogger\((.*)\)', r'log = logger.bind(name=\1)', text)
return text
if __name__ == "__main__":
filenames = [r"C:\Users\csterling\PycharmProjects\Flexget\testfile.py"]
filenames = pathlib.Path(sys.argv[1])
if filenames.is_file():
filenames = [filenames]
elif filenames.is_dir():
filenames = list(filenames.glob('*.py'))
print(filenames)
for filename in filenames:
with open(filename, "r") as f:
content = f.read()
print('Converting log calls {} ---->'.format(filename))
if 'import logging' not in content:
print('no standard logging')
continue
if 'logger' in content:
print('possible name conflict with logger')
newcontent = fix_file(content)
if 'logging' in newcontent:
print('logging module still possibly in use')
with open(filename, "w") as f:
f.write(fix_file(content))
print('Running isort ---->', flush=True)
subprocess.run(['isort', filename], stdout=sys.stdout, stderr=sys.stderr)
print('Running black ---->', flush=True)
subprocess.run(['black', filename], stdout=sys.stdout, stderr=sys.stderr)
#print(fix_file(content))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment