Repository: pre-commit/pre-commit

Issue:
C:\python3\python.exe does not exist while running pre-commit on Windows
Hi,

I'm trying to run the pre-commit commands of the [ESSS/barril](https://github.com/ESSS/barril) repository on my Windows machine, but I'm getting this error:

```
 λ tox -e linting
linting installed: aspy.yaml==1.1.1,cfgv==1.4.0,identify==1.1.8,importlib-metadata==0.8,importlib-resources==1.0.2,nodeenv==1.3.3,pre-commit==1.14.0,PyYAML==3.13,six==1.12.0,toml==0.10.0,virtualenv==16.2.0,zipp==0.3.3
linting run-test-pre: PYTHONHASHSEED='554'
linting runtests: commands[0] | pre-commit run --all-files --show-diff-on-failure
[INFO] Installing environment for https://github.com/ambv/black.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
An unexpected error has occurred: CalledProcessError: Command: ('w:\\projects\\barril\\.tox\\linting\\scripts\\python.exe', '-mvirtualenv', 'C:\\Users\\darci\\.cache\\pre-commit\\repoufam_s8_\\py_env-python3', '-p', 'C:\\python3\\python.exe')
Return code: 3
Expected return code: 0
Output:
    The path C:\python3\python.exe (from --python=C:\python3\python.exe) does not exist

Errors: (none)

Check the log at C:\Users\darci/.cache\pre-commit\pre-commit.log
```

The `C:\python3` path does not exist on my machine, I'm using `conda` and `virtualenv` to create a Python 3.6 virtual environment, from which I execute `tox -e linting`.

Here's the contents of the `pre-commit-config.yaml`:

```yaml
repos:
-   repo: https://github.com/ambv/black
    rev: 18.6b4
    hooks:
    -   id: black
        args: [--safe, --quiet]
        language_version: python3
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v1.3.0
    hooks:
    -   id: trailing-whitespace
    -   id: end-of-file-fixer
    -   id: check-yaml
    -   id: debug-statements
    -   id: flake8
-   repo: local
    hooks:
    -   id: rst
        name: rst
        entry: rst-lint --encoding utf-8
        files: ^(CHANGELOG.rst|HOWTORELEASE.rst|README.rst)$
        language: python
        additional_dependencies: [pygments, restructuredtext_lint]
```

Any hints of what the problem might be?

cc @nicoddemus 


Discussion:
I'm not sure how conda sets things up but standard python installations on windows are detected via three ways (quite similar to tox, but perhaps can be extended to do this [one thing](https://github.com/tox-dev/tox/blob/554548434d2b0a84f0e8c1d74d221a97cf5e03b8/src/tox/interpreters.py#L143-L144) tox does):

1. look up as if it is a posix executable, that is look for `python3.exe` somewhere
2. look up using the `py` launcher, the standard way to register executables on windows (`py -3` in this case)
3. all else fails, assume the "standard" installation location of `C:\PythonXX\python.exe` -- this is the final one that's shown in the error message

My guess is that conda does not participate in any of those three approaches and perhaps the approach from tox should be pursued.  

If you could provide the output of `py -l` and `which python3` I could probably confirm or deny my suspicions :)

Resolving patch:
diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py
--- a/pre_commit/languages/python.py
+++ b/pre_commit/languages/python.py
@@ -89,8 +89,26 @@ def get_default_version():
         return get_default_version()
 
 
+def _sys_executable_matches(version):
+    if version == 'python':
+        return True
+    elif not version.startswith('python'):
+        return False
+
+    try:
+        info = tuple(int(p) for p in version[len('python'):].split('.'))
+    except ValueError:
+        return False
+
+    return sys.version_info[:len(info)] == info
+
+
 def norm_version(version):
     if os.name == 'nt':  # pragma: no cover (windows)
+        # first see if our current executable is appropriate
+        if _sys_executable_matches(version):
+            return sys.executable
+
         # Try looking up by name
         version_exec = find_executable(version)
         if version_exec and version_exec != version:


Test patch:
diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py
--- a/tests/languages/python_test.py
+++ b/tests/languages/python_test.py
@@ -2,6 +2,10 @@
 from __future__ import unicode_literals
 
 import os.path
+import sys
+
+import mock
+import pytest
 
 from pre_commit.languages import python
 
@@ -16,3 +20,15 @@ def test_norm_version_expanduser():
         expected_path = home + '/.pyenv/versions/3.4.3/bin/python'
     result = python.norm_version(path)
     assert result == expected_path
+
+
+@pytest.mark.parametrize('v', ('python3.6', 'python3', 'python'))
+def test_sys_executable_matches(v):
+    with mock.patch.object(sys, 'version_info', (3, 6, 7)):
+        assert python._sys_executable_matches(v)
+
+
+@pytest.mark.parametrize('v', ('notpython', 'python3.x'))
+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)