@@ -738,55 +738,81 @@ def main():
738
738
739
739
def should_reinvoke (options ):
740
740
"""Do we need to reinvoke ourself?"""
741
- # 1. Did the user specify the --python option?
741
+ # Did the user specify the --python option?
742
742
if options .python and not os .environ .get ("VIRTUALENV_INTERPRETER_RUNNING" ):
743
- return options .python
744
- # All of the remaining cases are only for Windows
743
+ interpreter = resolve_interpreter (options .python )
744
+ if interpreter != sys .executable :
745
+ # The user specified a different interpreter, so we have to reinvoke.
746
+ return interpreter
747
+
748
+ # At this point, we know the user wants to use sys.executable to create the
749
+ # virtual environment. But on Windows, sys.executable may be a venv redirector,
750
+ # in which case we still need to locate the underlying actual interpreter, and
751
+ # reinvoke using that.
745
752
if IS_WIN :
746
- # 2. Are we running from a venv-style virtual environment with a redirector?
753
+ # OK. Now things get really fun...
754
+ #
755
+ # If we are running from a venv, with a redirector, then what happens is as
756
+ # follows:
757
+ #
758
+ # 1. The redirector sets __PYVENV_LAUNCHER__ in the environment to point
759
+ # to the redirector executable.
760
+ # 2. The redirector launches the "base" Python (from the home value in
761
+ # pyvenv.cfg).
762
+ # 3. The base Python executable sees __PYVENV_LAUNCHER__ in the environment
763
+ # and sets sys.executable to that value.
764
+ # 4. If site.py gets run, it sees __PYVENV_LAUNCHER__, and sets
765
+ # sys._base_executable to _winapi.GetModuleFileName(0) and removes
766
+ # __PYVENV_LAUNCHER__.
767
+ #
768
+ # Unfortunately, that final step (site.py) may not happen. There are 2 key
769
+ # times when that is the case:
770
+ #
771
+ # 1. Python 3.7.2, which had the redirector but not the site.py code.
772
+ # 2. Running a venv from a virtualenv, which uses virtualenv's custom
773
+ # site.py.
774
+ #
775
+ # So, we check for sys._base_executable, but if it's not present and yet we
776
+ # hand __PYVENV_LAUNCHER__, we do what site.py would have done and get our
777
+ # interpreter from GetModuleFileName(0). We also remove __PYVENV_LAUNCHER__
778
+ # from the environment, to avoid loops (actually, mainly because site.py
779
+ # does so, and my head hurts enough buy now that I just want to be safe!)
780
+
781
+ # Phew.
782
+
747
783
if hasattr (sys , "_base_executable" ):
748
784
return sys ._base_executable
749
- # 3. Special case for Python 3.7.2, where we have a redirector,
750
- # but sys._base_executable does not exist.
751
- if sys .version_info [:3 ] == (3 , 7 , 2 ):
752
- # We are in a venv if the environment variable __PYVENV_LAUNCHER__ is set.
753
- if "__PYVENV_LAUNCHER__" in os .environ :
754
- # The base environment is either sys.real_prefix (if
755
- # we were invoked from a venv built from a virtualenv) or
756
- # sys.base_prefix if real_prefix doesn't exist (a simple venv).
757
- base_prefix = getattr (sys , "real_prefix" , sys .base_prefix )
758
- # We assume the Python executable is directly under the prefix
759
- # directory. The only known case where that won't be the case is
760
- # an in-place source build, which we don't support. We don't need
761
- # to consider virtuale environments (where python.exe is in "Scripts"
762
- # because we've just followed the links back to a non-virtual
763
- # environment - we hope!)
764
- base_exe = os .path .join (base_prefix , "python.exe" )
765
- if os .path .exists (base_exe ):
766
- return base_exe
785
+
786
+ if "__PYVENV_LAUNCHER__" in os .environ :
787
+ import _winapi
788
+
789
+ del os .environ ["__PYVENV_LAUNCHER__" ]
790
+ return _winapi .GetModuleFileName (0 )
791
+
767
792
# We don't need to reinvoke
768
793
return None
769
794
770
795
interpreter = should_reinvoke (options )
771
- if interpreter :
796
+ if interpreter is None :
797
+ # We don't need to reinvoke - if the user asked us to, tell them why we
798
+ # aren't.
799
+ if options .python :
800
+ logger .warn ("Already using interpreter {}" .format (sys .executable ))
801
+ else :
772
802
env = os .environ .copy ()
773
- interpreter = resolve_interpreter (interpreter )
774
- if interpreter == sys .executable :
775
- logger .warn ("Already using interpreter {}" .format (interpreter ))
776
- else :
777
- logger .notify ("Running virtualenv with interpreter {}" .format (interpreter ))
778
- env ["VIRTUALENV_INTERPRETER_RUNNING" ] = "true"
779
- # Remove the variable __PYVENV_LAUNCHER__ if it's present, as it causes the
780
- # interpreter to redirect back to the virtual environment.
781
- if "__PYVENV_LAUNCHER__" in env :
782
- del env ["__PYVENV_LAUNCHER__" ]
783
- file = __file__
784
- if file .endswith (".pyc" ):
785
- file = file [:- 1 ]
786
- elif IS_ZIPAPP :
787
- file = HERE
788
- sub_process_call = subprocess .Popen ([interpreter , file ] + sys .argv [1 :], env = env )
789
- raise SystemExit (sub_process_call .wait ())
803
+ logger .notify ("Running virtualenv with interpreter {}" .format (interpreter ))
804
+ env ["VIRTUALENV_INTERPRETER_RUNNING" ] = "true"
805
+ # Remove the variable __PYVENV_LAUNCHER__ if it's present, as it causes the
806
+ # interpreter to redirect back to the virtual environment.
807
+ if "__PYVENV_LAUNCHER__" in env :
808
+ del env ["__PYVENV_LAUNCHER__" ]
809
+ file = __file__
810
+ if file .endswith (".pyc" ):
811
+ file = file [:- 1 ]
812
+ elif IS_ZIPAPP :
813
+ file = HERE
814
+ sub_process_call = subprocess .Popen ([interpreter , file ] + sys .argv [1 :], env = env )
815
+ raise SystemExit (sub_process_call .wait ())
790
816
791
817
if not args :
792
818
print ("You must provide a DEST_DIR" )
0 commit comments