forked from python/mypy
/
mypy.py
138 lines (111 loc) · 3.72 KB
/
mypy.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/env python
"""Mypy type checker and Python translator
Type check and program, translate it to Python and run it. Note that you must
use a translated mypy translator to run this program.
"""
import os
import os.path
import shutil
import subprocess
import sys
import tempfile
from build import build
from errors import CompileError
from pythongen import PythonGenerator
# Fallback options
verbose = False
pyversion = 3
interpreter = 'python'
void main():
path, args = process_options()
try:
mainfile = open(path)
text = mainfile.read()
mainfile.close()
except IOError as ioerr:
fail("mypy: can't read file '{}': {}".format(path,
ioerr.strerror))
try:
outputdir = os.path.join(os.path.dirname(path), '__mycache__')
tempdir = False
if not os.path.isdir(outputdir):
try:
os.mkdir(outputdir)
except OSError:
# Could not create a directory under program directory; must
# fall back to a temp directory. It will be removed later.
outputdir = tempfile.mkdtemp()
tempdir = True
try:
# Parse and type check the program and dependencies.
trees, symtable, infos, types = build(text, path, False, None,
True)
# Translate each file in the program to Python.
# TODO support packages
for t in trees:
if not is_stub(t.path):
out_path = os.path.join(outputdir,
os.path.basename(t.path))
log('translate {} to {}'.format(t.path, out_path))
v = PythonGenerator(pyversion)
t.accept(v)
outfile = open(out_path, 'w')
outfile.write(v.output())
outfile.close()
# Run the translated program.
status = subprocess.call(
[interpreter,
'{}/{}'.format(outputdir,os.path.basename(path))] +
args)
sys.exit(status)
finally:
if tempdir:
shutil.rmtree(outputdir)
except CompileError as e:
for m in e.messages:
print(m)
sys.exit(1)
tuple<str, str[]> process_options():
if sys.executable:
global interpreter
interpreter = sys.executable
args = sys.argv[1:]
while args and args[0].startswith('-'):
if args[0] == '--verbose':
global verbose
verbose = True
args = args[1:]
elif args[0] == '--py2' and args[1:]:
# Generate Python 2 (but this is very buggy).
global pyversion
pyversion = 2
interpreter = args[1]
args = args[2:]
else:
usage('Invalid option {}'.format(args[0]))
if not args:
usage()
return args[0], args[1:]
void usage(str msg=None):
if msg:
sys.stderr.write('%s\n' % msg)
sys.stderr.write('Usage: mypy.py [--verbose] PROGRAM\n')
sys.exit(2)
void fail(str msg):
sys.stderr.write('%s\n' % msg)
sys.exit(1)
bool is_stub(str path):
"""Does path refer to a stubs file?
Currently check if there is a 'stubs' directory component somewhere
in the path."""
# TODO more precise check
if os.path.basename(path) == '':
return False
else:
return os.path.basename(path) == 'stubs' or is_stub(
os.path.dirname(path))
void log(str message):
if verbose:
print('LOG: {}'.format(message))
if __name__ == '__main__':
main()