Skip to content

Calling 'python' via subprocess.call ignoring passed %PATH% #68981

Closed

Description

@phbarnacle
mannequin
BPO 24793
Nosy @pfmoore, @tjguk, @zware, @eryksun, @zooba

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = <Date 2015-08-05.10:52:00.959>
created_at = <Date 2015-08-05.09:07:24.811>
labels = ['type-bug', 'invalid', 'OS-windows']
title = "Calling 'python' via subprocess.call ignoring passed %PATH%"
updated_at = <Date 2015-08-05.11:55:12.228>
user = 'https://bugs.python.org/phbarnacle'

bugs.python.org fields:

activity = <Date 2015-08-05.11:55:12.228>
actor = 'eryksun'
assignee = 'none'
closed = True
closed_date = <Date 2015-08-05.10:52:00.959>
closer = 'paul.moore'
components = ['Windows']
creation = <Date 2015-08-05.09:07:24.811>
creator = 'phbarnacle'
dependencies = []
files = []
hgrepos = []
issue_num = 24793
keywords = []
message_count = 3.0
messages = ['248023', '248029', '248030']
nosy_count = 6.0
nosy_names = ['paul.moore', 'tim.golden', 'zach.ware', 'eryksun', 'steve.dower', 'phbarnacle']
pr_nums = []
priority = 'normal'
resolution = 'not a bug'
stage = None
status = 'closed'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue24793'
versions = ['Python 2.7']

Activity

  1. phbarnacle commented on Aug 5, 2015

    phbarnaclemannequin
    MannequinAuthor

    I just noticed that there is a litte inconvenience when I try to invoke 'python' via subprocess.call passing an environment (%PATH%) from a script. I pass an environment where %PATH% only contains one directory where a python2.7.3-exe is present (I checked with "subprocess.call(['where','python'],env=environment)" that python is found there). However when calling "subprocess.call(['python'],env=environment)" python 2.7.9 is opened, which is the python version I called the script with. Seems inconvenient to me.

    Greetings

  2. pfmoore commented on Aug 5, 2015

    @pfmoore
    Member

    This is standard Windows behaviour. Executables are always located first in the directory where your program (in this case the Python executable) is running from - even before searching PATH.

    If you want to use a different Python, you should specify the full path to the executable - "subprocess.call(["C:\\Python34\\python.exe"])".

  3. eryksun commented on Aug 5, 2015

    @eryksun
    Contributor

    Popen calls Windows CreateProcess. If the Popen "executable" argument isn't used or if the file from the command line doesn't include a directory path, then CreateProcess searches for it in the following directories:

    1. The directory from which the application loaded.
    2. The current directory for the parent process.
       * This step is skipped if the parent defines
         %NoDefaultCurrentDirectoryInExePath%.
    3. The 32-bit Windows system directory.
    4. The 16-bit Windows system directory. 
    5. The Windows directory. 
    6. The directories that are listed in the PATH 
       environment variable. 
    

    Also note that the PATH searched is that of the *parent* process; the "env" parameter doesn't affect this.

    Call the SearchPath function if you need a custom search for the fully qualified path.

        import ctypes
        from ctypes import wintypes
    
        kernel32 = ctypes.WinDLL('kernel32')
    
        kernel32.SearchPathW.argtypes = (
            wintypes.LPCWSTR,                   # _In_opt_  lpPath
            wintypes.LPCWSTR,                   # _In_      lpFileName
            wintypes.LPCWSTR,                   # _In_opt_  lpExtension
            wintypes.DWORD,                     # _In_      nBufferLength
            wintypes.LPWSTR,                    # _Out_     lpBuffer
            ctypes.POINTER(wintypes.LPWSTR))    # _Out_opt_ lpFilePart
                                                
        def search_path(filename, path=None, ext='.exe'):
            length, new_length = 0, 260
            while new_length > length:
                length = new_length
                filepath = (ctypes.c_wchar * length)()
                new_length = kernel32.SearchPathW(path, filename, ext,
                                                  length, filepath, None)
            return filepath.value

    For example:

        >>> search_path('python')
        u'C:\\Program Files\\Python27\\python.exe'
        >>> import os            
        >>> search_path('python', os.environ['PATH'])
        u''
    
        >>> search_path('more.com', os.environ['PATH'])
        u'C:\\Windows\\System32\\more.com'
        >>> search_path('more', ext='.com')            
        u'C:\\Windows\\system32\\more.com'
  4. transferred this issue fromon Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    OS-windowstype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions