Skip to content

Instantly share code, notes, and snippets.

@frederik-elwert
Created September 28, 2019 11:08
Show Gist options
  • Save frederik-elwert/c99ceee72293035aeef05ccbb53dea83 to your computer and use it in GitHub Desktop.
Save frederik-elwert/c99ceee72293035aeef05ccbb53dea83 to your computer and use it in GitHub Desktop.
Script for converting Python 2 to Python 3 in Markdown files
#!/usr/bin/env python3
import sys
import tempfile
import logging
import re
from pathlib import Path
from lib2to3 import refactor
from lib2to3.pgen2.parse import ParseError
def main(infile, outfile, force=False):
fixers = refactor.get_fixers_from_package('lib2to3.fixes')
rt = refactor.RefactoringTool(fixers)
made_changes = False
parse_error = False
with open(infile) as fin:
with tempfile.NamedTemporaryFile('w', delete=False) as fout:
ispystart = False
ispy = False
chunk_no = 0
for line in fin:
# Capture start of code block, but do not process this line
if re.match('```\s*python', line.strip()):
ispystart = True
chunk = []
chunk_no += 1
# Capture subsequent lines:
elif ispystart:
ispystart = False
ispy = True
# Stop capturing and process the chunk
if ispy and line.strip() == '```':
ispy = False
code_str = ''.join(chunk)
try:
out_tree = rt.refactor_string(code_str, f'chunk{chunk_no}')
except ParseError:
logging.debug(f'Error parsing chunk #{chunk_no}!')
fout.write('# ParseError: Could not check this chunk!\n')
parse_error = True
out_str = code_str
else:
out_str = str(out_tree)
if code_str != out_str:
logging.debug(f'Updated chunk #{chunk_no}.')
made_changes = True
code_str = out_str
else:
logging.debug(f'No changes in chunk #{chunk_no}.')
fout.write(code_str)
# Capture code lines
if ispy:
chunk.append(line)
# Write out all other lines unchanged
else:
fout.write(line)
if made_changes:
logging.info('Changes required.')
outpath = Path(outfile)
if outpath.exists() and not force:
logging.error(f'Not overwriting existing file {outfile}!')
else:
Path(fout.name).rename(outpath)
elif parse_error:
logging.info('Could not determine required changes.')
else:
logging.info('No changes necessary.')
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-o', '--outfile')
group.add_argument('-w', '--writeback', action='store_true')
parser.add_argument('-f', '--force', action='store_true')
parser.add_argument('-v', '--verbose', action='store_true')
parser.add_argument('infile')
args = parser.parse_args()
if args.writeback:
args.outfile = args.infile
args.force = True
if args.verbose:
level = logging.DEBUG
else:
level = logging.INFO
logging.basicConfig(level=level)
main(args.infile, outfile=args.infile, force=args.force)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment