/
auto2to3.py
executable file
·122 lines (106 loc) · 3.8 KB
/
auto2to3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/usr/bin/env python3.2
"""Wrapper to run 2to3 automatically at import time.
Usage:
auto2to3 -m mypackage.main_module
auto2to3 mypackage/script.py
By default, all modules imported from a subdirectory of the current
directory will be run through `2to3`. To change this behavior, use the
`--package` or `--dir` flags to `auto2to3` to specify which packages or
directories contain Python 2 code that should be converted.
2to3 output is cached on disk between runs for speed.
Based on auto2to3.py by Georg Brandl:
http://dev.pocoo.org/hg/sandbox/file/tip/auto2to3.py
"""
import argparse
import os
import sys
import imp
import runpy
from io import StringIO
from pkgutil import ImpImporter, ImpLoader
import runpy
import sys
import tempfile
import lib2to3
from lib2to3.refactor import RefactoringTool, get_fixers_from_package
fixes = get_fixers_from_package('lib2to3.fixes')
rt = RefactoringTool(fixes)
PACKAGES = []
DIRS = []
def maybe_2to3(filename, modname=None):
"""Returns a python3 version of filename."""
need_2to3 = False
filename = os.path.abspath(filename)
if any(filename.startswith(d) for d in DIRS):
need_2to3 = True
elif modname is not None and any(modname.startswith(p) for p in PACKAGES):
need_2to3 = True
if not need_2to3:
return filename
outfilename = '/_auto2to3_'.join(os.path.split(filename))
if (not os.path.exists(outfilename) or
os.stat(filename).st_mtime > os.stat(outfilename).st_mtime):
try:
with open(filename) as file:
contents = file.read()
contents = rt.refactor_docstring(contents, filename)
tree = rt.refactor_string(contents, filename)
except Exception as err:
raise ImportError("2to3 couldn't convert %r" % filename)
outfile = open(outfilename, 'wb')
outfile.write(str(tree).encode('utf8'))
outfile.close()
return outfilename
class ToThreeImporter(ImpImporter):
def find_module(self, fullname, path=None):
# this duplicates most of ImpImporter.find_module
subname = fullname.split(".")[-1]
if subname != fullname and self.path is None:
return None
if self.path is None:
path = None
else:
path = [os.path.realpath(self.path)]
try:
file, filename, etc = imp.find_module(subname, path)
except ImportError:
return None
if file and etc[2] == imp.PY_SOURCE:
outfilename = maybe_2to3(filename, modname=fullname)
if outfilename != filename:
file.close()
filename = outfilename
file = open(filename, 'rb')
return ImpLoader(fullname, file, filename, etc)
# setup the hook
sys.path_hooks.append(ToThreeImporter)
for key in sys.path_importer_cache:
if sys.path_importer_cache[key] is None:
sys.path_importer_cache[key] = ToThreeImporter(key)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--package', action='append')
parser.add_argument('--dir', action='append')
parser.add_argument('-m', action='store', metavar='MODULE')
args, rest = parser.parse_known_args()
if args.package:
PACKAGES.extend(args.package)
if args.dir:
DIRS.extend(os.path.abspath(d) for d in args.dir)
if not PACKAGES and not DIRS:
DIRS.append(os.getcwd())
if args.m:
sys.argv[1:] = rest
runpy.run_module(args.m, run_name='__main__', alter_sys=True)
elif rest:
sys.argv = rest
converted = maybe_2to3(rest[0])
with open(converted) as f:
new_globals = dict(__name__='__main__',
__file__=rest[0])
exec(f.read(), new_globals)
else:
import code
code.interact()
if __name__ == '__main__':
main()