diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 5d48fb89..df00a071 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -43,14 +43,13 @@ def _find_by_py_launcher(version): # pragma: no cover (windows only) pass -def _get_default_version(): # pragma: no cover (platform dependent) +def _find_by_sys_executable(): def _norm(path): _, exe = os.path.split(path.lower()) exe, _, _ = exe.partition('.exe') if find_executable(exe) and exe not in {'python', 'pythonw'}: return exe - # First attempt from `sys.executable` (or the realpath) # On linux, I see these common sys.executables: # # system `python`: /usr/bin/python -> python2.7 @@ -59,10 +58,17 @@ def _get_default_version(): # pragma: no cover (platform dependent) # virtualenv v -ppython2: v/bin/python -> python2 # virtualenv v -ppython2.7: v/bin/python -> python2.7 # virtualenv v -ppypy: v/bin/python -> v/bin/pypy - for path in {sys.executable, os.path.realpath(sys.executable)}: + for path in (sys.executable, os.path.realpath(sys.executable)): exe = _norm(path) if exe: return exe + return None + + +def _get_default_version(): # pragma: no cover (platform dependent) + + # First attempt from `sys.executable` (or the realpath) + exe = _find_by_sys_executable() # Next try the `pythonX.X` executable exe = 'python{}.{}'.format(*sys.version_info) diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py index 426d3ec6..52e0e85c 100644 --- a/tests/languages/python_test.py +++ b/tests/languages/python_test.py @@ -32,3 +32,18 @@ def test_sys_executable_matches(v): def test_sys_executable_matches_does_not_match(v): with mock.patch.object(sys, 'version_info', (3, 6, 7)): assert not python._sys_executable_matches(v) + + +@pytest.mark.parametrize( + 'exe,realpath,expected', ( + ('/usr/bin/python3', '/usr/bin/python3.7', 'python3'), + ('/usr/bin/python', '/usr/bin/python3.7', 'python3.7'), + ('/usr/bin/python', '/usr/bin/python', None), + ('/usr/bin/python3.6m', '/usr/bin/python3.6m', 'python3.6m'), + ('v/bin/python', 'v/bin/pypy', 'pypy'), + ), +) +def test_find_by_sys_executable(exe, realpath, expected): + with mock.patch.object(sys, 'executable', exe): + with mock.patch('os.path.realpath', return_value=realpath): + assert python._find_by_sys_executable() == expected