Skip to content

Commit a967567

Browse files
committed
Cherry-pick dialect support from the syntax branch
1 parent 2a9df10 commit a967567

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

mypy/syntax/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# This page intentionally left blank

mypy/syntax/dialect.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
"""Python dialect control.
2+
3+
This may be incomplet or inkorrekt.
4+
5+
Versions < 2.7 is not a priority.
6+
Versions >= 3.0 and < 3.2 are not a priority.
7+
Versions < 2.4 have many fundamental differences.
8+
Versions < 2.2 have even more fundamental differences.
9+
Versions 1.6 and 2.0 are not distinguished.
10+
Versions < 1.6 are not even mentioned.
11+
"""
12+
13+
14+
from typing import (
15+
List,
16+
Sequence,
17+
Set,
18+
Tuple,
19+
)
20+
21+
import os
22+
import subprocess
23+
import sys
24+
25+
26+
# Maintain our own copy instead of using __future__ just in case we need
27+
# to parse a newer version of python than we're running.
28+
# Also we can use other ones.
29+
30+
available_futures = {
31+
# mypy-specific features
32+
'mypy-codec': '0.0',
33+
# platform.python_implementation()
34+
'variant-CPython': '0.0',
35+
'variant-PyPy': '0.0',
36+
'variant-Jython': '0.0',
37+
'variant-IronPython': '0.0',
38+
# real ones
39+
'nested_scopes': '2.1',
40+
'generators': '2.2',
41+
'division': '2.2',
42+
'absolute_import': '2.5',
43+
'with_statement': '2.5',
44+
'print_function': '2.6',
45+
'unicode_literals': '2.6',
46+
'barry_as_FLUFL': '3.1',
47+
}
48+
49+
50+
def check_futures(version: str, futures: Sequence[str]) -> Set[str]:
51+
for fut in futures:
52+
assert version >= available_futures[fut]
53+
return set(futures)
54+
55+
56+
class Dialect:
57+
58+
def __init__(self, version: str, future_list: Sequence[str] = []) -> None:
59+
"""Construct a dialect for the given Python version and future set.
60+
61+
`version` is like `'2.7.0'`, e.g. `platform.python_version()`.
62+
`future_list` is like `['X', 'Y', 'Z']` in `from __future__ import X, Y, Z`.
63+
"""
64+
self.major, self.minor, self.patchlevel = [int(x) for x in version.split('.')]
65+
future_set = check_futures(version, future_list)
66+
self.base_version = version
67+
self.base_future_list = future_list
68+
self.base_future_set = future_set
69+
70+
self.possible_futures = {k for (k, v) in available_futures.items() if v <= version}
71+
72+
def __repr__(self) -> str:
73+
return 'Dialect(%r, %r)' % (self.base_version, self.base_future_list)
74+
75+
def add_future(self, future: str) -> 'Dialect':
76+
if future in self.base_future_set:
77+
return self
78+
return Dialect(self.base_version, self.base_future_list + [future])
79+
80+
81+
class Implementation:
82+
83+
def __init__(self, executable: str) -> None:
84+
command = '''if True:
85+
import platform, sys
86+
print((platform.python_implementation(), platform.python_version(), sys.path))
87+
'''
88+
output = subprocess.check_output([executable, '-c', command])
89+
impl, version, path = eval(output) # type: Tuple[str, str, List[str]]
90+
91+
self.executable = executable
92+
self.base_dialect = Dialect(version, ['variant-' + impl])
93+
self.stub_dialect = self.base_dialect.add_future('mypy-codec')
94+
self.python_path = path
95+
# TODO self.stub_path = []
96+
97+
98+
def default_implementation(*, force_py2: bool = False) -> Implementation:
99+
"""Return the preferred python implementation for the inferior.
100+
101+
This looks at the MYPY_PYTHON environment variable, or else uses
102+
the current python version.
103+
104+
The `force_py2` argument should possibly be deprecated.
105+
"""
106+
if force_py2:
107+
try_pythons = [os.getenv('MYPY_PYTHON'), 'python2', 'python2.7', 'python']
108+
else:
109+
try_pythons = [os.getenv('MYPY_PYTHON'), sys.executable]
110+
for python in try_pythons:
111+
if python is None:
112+
continue
113+
try:
114+
impl = Implementation(python)
115+
except (OSError, subprocess.CalledProcessError):
116+
pass
117+
if force_py2 and impl.base_dialect.major != 2:
118+
continue
119+
return impl
120+
sys.exit('No suitable python executable found')

0 commit comments

Comments
 (0)