Skip to content

Commit d2a9f9d

Browse files
emmatypinggvanrossum
authored andcommitted
Allow setting python_executable from config file... (#5777)
* Remove check that python_[version/executable] agree * Allow setting python_version/executable from config file This fixes #5620
1 parent ed248c8 commit d2a9f9d

File tree

2 files changed

+40
-52
lines changed

2 files changed

+40
-52
lines changed

mypy/main.py

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -227,17 +227,6 @@ def python_executable_prefix(v: str) -> List[str]:
227227
return ['python{}'.format(v)]
228228

229229

230-
def _python_version_from_executable(python_executable: str) -> Tuple[int, int]:
231-
try:
232-
check = subprocess.check_output([python_executable, '-c',
233-
'import sys; print(repr(sys.version_info[:2]))'],
234-
stderr=subprocess.STDOUT).decode()
235-
return ast.literal_eval(check)
236-
except (subprocess.CalledProcessError, FileNotFoundError):
237-
raise PythonExecutableInferenceError(
238-
'invalid Python executable {}'.format(python_executable))
239-
240-
241230
def _python_executable_from_version(python_version: Tuple[int, int]) -> str:
242231
if sys.version_info[:2] == python_version:
243232
return sys.executable
@@ -253,37 +242,25 @@ def _python_executable_from_version(python_version: Tuple[int, int]) -> str:
253242
' perhaps try --python-executable, or --no-site-packages?'.format(python_version))
254243

255244

256-
def infer_python_version_and_executable(options: Options,
257-
special_opts: argparse.Namespace) -> None:
258-
"""Infer the Python version or executable from each other. Check they are consistent.
245+
def infer_python_executable(options: Options,
246+
special_opts: argparse.Namespace) -> None:
247+
"""Infer the Python executable from the given version.
259248
260-
This function mutates options based on special_opts to infer the correct Python version and
261-
executable to use.
249+
This function mutates options based on special_opts to infer the correct Python executable
250+
to use.
262251
"""
263-
# Infer Python version and/or executable if one is not given
264-
265252
# TODO: (ethanhs) Look at folding these checks and the site packages subprocess calls into
266253
# one subprocess call for speed.
267-
if special_opts.python_executable is not None and special_opts.python_version is not None:
268-
py_exe_ver = _python_version_from_executable(special_opts.python_executable)
269-
if py_exe_ver != special_opts.python_version:
270-
raise PythonExecutableInferenceError(
271-
'Python version {} did not match executable {}, got version {}.'.format(
272-
special_opts.python_version, special_opts.python_executable, py_exe_ver
273-
))
274-
else:
275-
options.python_version = special_opts.python_version
276-
options.python_executable = special_opts.python_executable
277-
elif special_opts.python_executable is None and special_opts.python_version is not None:
278-
options.python_version = special_opts.python_version
279-
py_exe = None
254+
255+
# Use the command line specified executable, or fall back to one set in the
256+
# config file. If an executable is not specified, infer it from the version
257+
# (unless no_executable is set)
258+
python_executable = special_opts.python_executable or options.python_executable
259+
260+
if python_executable is None:
280261
if not special_opts.no_executable:
281-
py_exe = _python_executable_from_version(special_opts.python_version)
282-
options.python_executable = py_exe
283-
elif special_opts.python_version is None and special_opts.python_executable is not None:
284-
options.python_version = _python_version_from_executable(
285-
special_opts.python_executable)
286-
options.python_executable = special_opts.python_executable
262+
python_executable = _python_executable_from_version(options.python_version)
263+
options.python_executable = python_executable
287264

288265

289266
HEADER = """%(prog)s [-h] [-v] [-V] [more options; see below]
@@ -747,8 +724,11 @@ def add_invertible_flag(flag: str,
747724
print("Warning: --quick-and-dirty is deprecated. It will disappear in the next release.",
748725
file=sys.stderr)
749726

727+
# The python_version is either the default, which can be overridden via a config file,
728+
# or stored in special_opts and is passed via the command line.
729+
options.python_version = special_opts.python_version or options.python_version
750730
try:
751-
infer_python_version_and_executable(options, special_opts)
731+
infer_python_executable(options, special_opts)
752732
except PythonExecutableInferenceError as e:
753733
parser.error(str(e))
754734

mypy/test/testargs.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from mypy.test.helpers import Suite, assert_equal
1313
from mypy.options import Options
1414
from mypy.main import (process_options, PythonExecutableInferenceError,
15-
infer_python_version_and_executable)
15+
infer_python_executable)
1616

1717

1818
class ArgSuite(Suite):
@@ -47,22 +47,30 @@ def test_executable_inference(self) -> None:
4747
assert options.python_version == sys.version_info[:2]
4848
assert options.python_executable == sys.executable
4949

50-
# test that we error if the version mismatch
51-
# argparse sys.exits on a parser.error, we need to check the raw inference function
52-
options = Options()
53-
54-
special_opts = argparse.Namespace()
55-
special_opts.python_executable = sys.executable
56-
special_opts.python_version = (2, 10) # obviously wrong
57-
special_opts.no_executable = None
58-
with pytest.raises(PythonExecutableInferenceError) as e:
59-
infer_python_version_and_executable(options, special_opts)
60-
assert str(e.value) == 'Python version (2, 10) did not match executable {}, got' \
61-
' version {}.'.format(sys.executable, sys.version_info[:2])
62-
6350
# test that --no-site-packages will disable executable inference
6451
matching_version = base + ['--python-version={}'.format(sys_ver_str),
6552
'--no-site-packages']
6653
_, options = process_options(matching_version)
6754
assert options.python_version == sys.version_info[:2]
6855
assert options.python_executable is None
56+
57+
# Test setting python_version/executable from config file
58+
special_opts = argparse.Namespace()
59+
special_opts.python_executable = None
60+
special_opts.python_version = None
61+
special_opts.no_executable = None
62+
63+
# first test inferring executable from version
64+
options = Options()
65+
options.python_executable = None
66+
options.python_version = sys.version_info[:2]
67+
infer_python_executable(options, special_opts)
68+
assert options.python_version == sys.version_info[:2]
69+
assert options.python_executable == sys.executable
70+
71+
# then test inferring version from executable
72+
options = Options()
73+
options.python_executable = sys.executable
74+
infer_python_executable(options, special_opts)
75+
assert options.python_version == sys.version_info[:2]
76+
assert options.python_executable == sys.executable

0 commit comments

Comments
 (0)