Repository: pypa/virtualenv

Issue:
python2 should link to python (if using python2 on venv)
Following [PEP-0394](http://www.python.org/dev/peps/pep-0394/), I'm using `#!/usr/bin/env python2` in my scripts, but it does not work on virtualenvs by default! I need to manually link:

``` bash
cdvirtualenv
cd bin
ln -s python python2
```

I think `virtualenv` should handle this problem automatically, so we can use the PEP-0394 without any problems.



Discussion:

Resolving patch:
diff --git a/virtualenv.py b/virtualenv.py
--- a/virtualenv.py
+++ b/virtualenv.py
@@ -1409,22 +1409,26 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
                              "have Apple's development tools installed")
                 raise
 
-        # Some tools depend on pythonX.Y being present
-        py_executable_version = '%s.%s' % (
+    if not is_win:
+        # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist
+        py_exe_version_major = 'python%s' % sys.version_info[0]
+        py_exe_version_major_minor = 'python%s.%s' % (
             sys.version_info[0], sys.version_info[1])
-        if not py_executable.endswith(py_executable_version):
-            # symlinking pythonX.Y > python
-            pth = py_executable + '%s.%s' % (
-                    sys.version_info[0], sys.version_info[1])
-            if os.path.exists(pth):
-                os.unlink(pth)
-            os.symlink('python', pth)
-        else:
-            # reverse symlinking python -> pythonX.Y (with --python)
-            pth = join(bin_dir, 'python')
-            if os.path.exists(pth):
-                os.unlink(pth)
-            os.symlink(os.path.basename(py_executable), pth)
+        py_exe_no_version = 'python'
+        required_symlinks = [ py_exe_no_version, py_exe_version_major,
+                         py_exe_version_major_minor ]
+
+        py_executable_base = os.path.basename(py_executable)
+
+        if py_executable_base in required_symlinks:
+            # Don't try to symlink to yourself.
+            required_symlinks.remove(py_executable_base)
+
+        for pth in required_symlinks:
+            full_pth = join(bin_dir, pth)
+            if os.path.exists(full_pth):
+                os.unlink(full_pth)
+            os.symlink(py_executable_base, full_pth)
 
     if is_win and ' ' in py_executable:
         # There's a bug with subprocess on Windows when using a first


Test patch:
diff --git a/tests/test_virtualenv.py b/tests/test_virtualenv.py
--- a/tests/test_virtualenv.py
+++ b/tests/test_virtualenv.py
@@ -1,5 +1,9 @@
 import virtualenv
 import optparse
+import os
+import shutil
+import sys
+import tempfile
 from mock import patch, Mock
 
 
@@ -22,7 +26,7 @@ def test_resolve_interpreter_with_absolute_path(mock_exists):
 
 
 @patch('os.path.exists')
-def test_resolve_intepreter_with_nonexistant_interpreter(mock_exists):
+def test_resolve_interpreter_with_nonexistent_interpreter(mock_exists):
     """Should exit when with absolute path if not exists"""
     mock_exists.return_value = False
 
@@ -36,7 +40,7 @@ def test_resolve_intepreter_with_nonexistant_interpreter(mock_exists):
 
 
 @patch('os.path.exists')
-def test_resolve_intepreter_with_invalid_interpreter(mock_exists):
+def test_resolve_interpreter_with_invalid_interpreter(mock_exists):
     """Should exit when with absolute path if not exists"""
     mock_exists.return_value = True
     virtualenv.is_executable = Mock(return_value=False)
@@ -92,3 +96,25 @@ def get_environ_vars(self, prefix='VIRTUALENV_'):
     defaults = {}
     cop.update_defaults(defaults)
     assert defaults == {'system_site_packages': 0}
+
+def test_install_python_symlinks():
+    """Should create the right symlinks in bin_dir"""
+    tmp_virtualenv = tempfile.mkdtemp()
+    try:
+        home_dir, lib_dir, inc_dir, bin_dir = \
+                                virtualenv.path_locations(tmp_virtualenv)
+        virtualenv.install_python(home_dir, lib_dir, inc_dir, bin_dir, False,
+                                  False)
+
+        py_exe_no_version = 'python'
+        py_exe_version_major = 'python%s' % sys.version_info[0]
+        py_exe_version_major_minor = 'python%s.%s' % (
+            sys.version_info[0], sys.version_info[1])
+        required_executables = [ py_exe_no_version, py_exe_version_major,
+                         py_exe_version_major_minor ]
+
+        for pth in required_executables:
+            assert os.path.exists(os.path.join(bin_dir, pth)), ("%s should "
+                            "exist in bin_dir" % pth)
+    finally:
+        shutil.rmtree(tmp_virtualenv)