Created
September 28, 2019 11:08
-
-
Save frederik-elwert/c99ceee72293035aeef05ccbb53dea83 to your computer and use it in GitHub Desktop.
Script for converting Python 2 to Python 3 in Markdown files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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