2 # Copyright (c) 2002-2003 ActiveState 
   3 # See LICENSE.txt for license details. 
   4 """ Contents of LICENSE.txt: 
   5 Permission is hereby granted, free of charge, to any person obtaining a 
   6 copy of this software and associated documentation files (the 
   7 "Software"), to deal in the Software without restriction, including 
   8 without limitation the rights to use, copy, modify, merge, publish, 
   9 distribute, sublicense, and/or sell copies of the Software, and to 
  10 permit persons to whom the Software is furnished to do so, subject to 
  11 the following conditions: 
  13 The above copyright notice and this permission notice shall be included 
  14 in all copies or substantial portions of the Software. 
  16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
  17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
  18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
  19 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 
  20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
  21 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
  22 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
  26     Python interface for process control. 
  28     This module defines three Process classes for spawning, 
  29     communicating and control processes. They are: Process, ProcessOpen, 
  30     ProcessProxy. All of the classes allow one to specify the command (cmd), 
  31     starting working directory (cwd), and environment to create for the 
  32     new process (env) and to "wait" for termination of the child and 
  36         Use this class to simply launch a process (either a GUI app or a 
  37         console app in a new console) with which you do not intend to 
  38         communicate via it std handles. 
  41         Think of this as a super version of Python's os.popen3() method. 
  42         This spawns the given command and sets up pipes for 
  43         stdin/stdout/stderr which can then be used to communicate with 
  47         This is a heavy-weight class that, similar to ProcessOpen, 
  48         spawns the given commands and sets up pipes to the child's 
  49         stdin/stdout/stderr. However, it also starts three threads to 
  50         proxy communication between each of the child's and parent's std 
  51         handles. At the parent end of this communication are, by 
  52         default, IOBuffer objects. You may specify your own objects here 
  53         (usually sub-classing from IOBuffer, which handles some 
  54         synchronization issues for you). The result is that it is 
  55         possible to have your own IOBuffer instance that gets, say, a 
  56         .write() "event" for every write that the child does on its 
  59         Understanding ProcessProxy is pretty complex. Some examples 
  60         below attempt to help show some uses. Here is a diagram of the 
  64                ,---->->->------'   ^   `------>->->----, 
  66            IOBuffer             IOBuffer            IOBuffer         
  67            (p.stdout)           (p.stderr)          (p.stdin) 
  69            _OutFileProxy        _OutFileProxy       _InFileProxy 
  72                `----<-<-<------,   |   ,------<-<-<----' 
  77         p = process.<Process class>(cmd='echo hi', ...) 
  78         #... use the various methods and attributes 
  81       A simple 'hello world': 
  83         >>> p = process.ProcessOpen(['echo', 'hello']) 
  86         >>> p.wait()   # .wait() returns the child's exit status 
  89       Redirecting the stdout handler: 
  91         >>> p = process.ProcessProxy(['echo', 'hello'], stdout=sys.stdout) 
  94       Using stdin (need to use ProcessProxy here because it defaults to 
  95       text-mode translation on Windows, ProcessOpen does not support 
  97         >>> p = process.ProcessProxy(['sort']) 
  98         >>> p.stdin.write('5\n') 
  99         >>> p.stdin.write('2\n') 
 100         >>> p.stdin.write('7\n') 
 105       Specifying environment variables: 
 106         >>> p = process.ProcessOpen(['perl', '-e', 'print $ENV{FOO}']) 
 109         >>> p = process.ProcessOpen(['perl', '-e', 'print $ENV{FOO}'], 
 110         ...                         env={'FOO':'bar'}) 
 114       Killing a long running process (On Linux, to poll you must use 
 116         >>> p = ProcessOpen(['perl', '-e', 'while (1) {}']) 
 118         ...     p.wait(os.WNOHANG)  # poll to see if is process still running 
 119         ... except ProcessError, ex: 
 120         ...     if ex.errno == ProcessProxy.WAIT_TIMEOUT: 
 121         ...             print "process is still running" 
 123         process is still running 
 128       Providing objects for stdin/stdout/stderr: 
 129         XXX write this, mention IOBuffer subclassing. 
 132 #   - Discuss the decision to NOT have the stdout/stderr _OutFileProxy's 
 133 #     wait for process termination before closing stdin. It will just 
 134 #     close stdin when stdout is seen to have been closed. That is 
 135 #     considered Good Enough (tm). Theoretically it would be nice to 
 136 #     only abort the stdin proxying when the process terminates, but 
 137 #     watching for process termination in any of the parent's thread 
 138 #     adds the undesired condition that the parent cannot exit with the 
 139 #     child still running. That sucks. 
 140 #     XXX Note that I don't even know if the current stdout proxy even 
 141 #         closes the stdin proxy at all. 
 142 #   - DavidA: if I specify "unbuffered" for my stdin handler (in the 
 143 #     ProcessProxy constructor) then the stdin IOBuffer should do a 
 144 #     fparent.read() rather than a fparent.readline(). TrentM: can I do 
 145 #     that? What happens? 
 153 if sys
.platform
.startswith("win"): 
 161     # constants pulled from win32con to save memory 
 162     VER_PLATFORM_WIN32_WINDOWS 
= 1 
 166     DUPLICATE_SAME_ACCESS 
= 2 
 174 class ProcessError(Exception): 
 175     def __init__(self
, msg
, errno
=-1): 
 176         Exception.__init
__(self
, msg
) 
 180 #---- internal logging facility 
 183     DEBUG
, INFO
, WARN
, ERROR
, FATAL 
= range(5) 
 184     def __init__(self
, name
, level
=None, streamOrFileName
=sys
.stderr
): 
 187             self
.level 
= self
.WARN
 
 190         if type(streamOrFileName
) == types
.StringType
: 
 191             self
.stream 
= open(streamOrFileName
, 'w') 
 192             self
._opennedStream 
= 1 
 194             self
.stream 
= streamOrFileName
 
 195             self
._opennedStream 
= 0 
 197         if self
._opennedStream
: 
 199     def _getLevelName(self
, level
): 
 207         return levelNameMap
[level
] 
 208     def log(self
, level
, msg
, *args
): 
 209         if level 
< self
.level
: 
 211         message 
= "%s: %s:" % (self
.name
, self
._getLevelName
(level
).lower()) 
 212         message 
= message 
+ (msg 
% args
) + "\n" 
 213         self
.stream
.write(message
) 
 215     def debug(self
, msg
, *args
): 
 216         self
.log(self
.DEBUG
, msg
, *args
) 
 217     def info(self
, msg
, *args
): 
 218         self
.log(self
.INFO
, msg
, *args
) 
 219     def warn(self
, msg
, *args
): 
 220         self
.log(self
.WARN
, msg
, *args
) 
 221     def error(self
, msg
, *args
): 
 222         self
.log(self
.ERROR
, msg
, *args
) 
 223     def fatal(self
, msg
, *args
): 
 224         self
.log(self
.FATAL
, msg
, *args
) 
 227 #   - 'log' to log normal process handling 
 228 #   - 'logres' to track system resource life 
 229 #   - 'logfix' to track wait/kill proxying in _ThreadFixer 
 230 if 1:   # normal/production usage 
 231     log 
= Logger("process", Logger
.WARN
) 
 232 else:   # development/debugging usage 
 233     log 
= Logger("process", Logger
.DEBUG
, sys
.stdout
) 
 234 if 1:   # normal/production usage 
 235     logres 
= Logger("process.res", Logger
.WARN
) 
 236 else:   # development/debugging usage 
 237     logres 
= Logger("process.res", Logger
.DEBUG
, sys
.stdout
) 
 238 if 1:   # normal/production usage 
 239     logfix 
= Logger("process.waitfix", Logger
.WARN
) 
 240 else:   # development/debugging usage 
 241     logfix 
= Logger("process.waitfix", Logger
.DEBUG
, sys
.stdout
) 
 247 _version_ 
= (0, 5, 0) 
 249 # List of registered processes (see _(un)registerProcess). 
 254 #---- internal support routines 
 257     """Escape the given command line argument for the shell.""" 
 258     #XXX There is a probably more that we should escape here. 
 259     return arg
.replace('"', r
'\"') 
 263     r
"""Join an arglist to a string appropriate for running. 
 266         >>> _joinArgv(['foo', 'bar "baz']) 
 271         if ' ' in arg 
or ';' in arg
: 
 272             cmdstr 
+= '"%s"' % _escapeArg(arg
) 
 274             cmdstr 
+= _escapeArg(arg
) 
 276     if cmdstr
.endswith(' '): cmdstr 
= cmdstr
[:-1]  # strip trailing space 
 280 def _getPathFromEnv(env
): 
 281     """Return the PATH environment variable or None. 
 283     Do the right thing for case sensitivity per platform. 
 284     XXX Icky. This guarantee of proper case sensitivity of environment 
 285         variables should be done more fundamentally in this module. 
 287     if sys
.platform
.startswith("win"): 
 288         for key 
in env
.keys(): 
 289             if key
.upper() == "PATH": 
 294         if env
.has_key("PATH"): 
 300 def _whichFirstArg(cmd
, env
=None): 
 301     """Return the given command ensuring that the first arg (the command to 
 302     launch) is a full path to an existing file. 
 304     Raise a ProcessError if no such executable could be found. 
 306     # Parse out the first arg. 
 307     if cmd
.startswith('"'): 
 308         # The .replace() is to ensure it does not mistakenly find the 
 309         # second '"' in, say (escaped quote): 
 310         #           "C:\foo\"bar" arg1 arg2 
 311         idx 
= cmd
.replace('\\"', 'XX').find('"', 1) 
 313             raise ProcessError("Malformed command: %r" % cmd
) 
 314         first
, rest 
= cmd
[1:idx
], cmd
[idx
+1:] 
 318             first
, rest 
= cmd
.split(' ', 1) 
 320             first
, rest 
= cmd
, "" 
 322     # Ensure the first arg is a valid path to the appropriate file. 
 325         altpath 
= [os
.path
.dirname(first
)] 
 326         firstbase 
= os
.path
.basename(first
) 
 327         candidates 
= list(which
.which(firstbase
, path
=altpath
)) 
 329         altpath 
= _getPathFromEnv(env
) 
 331             candidates 
= list(which
.which(first
, altpath
.split(os
.pathsep
))) 
 333             candidates 
= list(which
.which(first
)) 
 335         candidates 
= list(which
.which(first
)) 
 337         return _joinArgv( [candidates
[0]] ) + ' ' + rest
 
 339         raise ProcessError("Could not find an appropriate leading command "\
 
 343 if sys
.platform
.startswith("win"): 
 344     def _SaferCreateProcess(appName
,        # app name 
 346                             processSA
,      # process security attributes  
 347                             threadSA
,       # thread security attributes  
 348                             inheritHandles
, # are handles are inherited 
 349                             creationFlags
,  # creation flags  
 351                             cwd
,            # current working directory 
 352                             si
):            # STARTUPINFO pointer 
 353         """If CreateProcess fails from environment type inconsistency then 
 354         fix that and try again. 
 356         win32process.CreateProcess requires that all environment keys and 
 357         values either be all ASCII or all unicode. Try to remove this burden 
 358         from the user of process.py. 
 360         isWin9x 
= win32api
.GetVersionEx()[3] == VER_PLATFORM_WIN32_WINDOWS
 
 361         # On Win9x all keys and values of 'env' must be ASCII (XXX 
 362         # Actually this is probably only true if the Unicode support 
 363         # libraries, which are not installed by default, are not 
 364         # installed). On other Windows flavours all keys and values of 
 365         # 'env' must all be ASCII *or* all Unicode. We will try to 
 366         # automatically convert to the appropriate type, issuing a 
 367         # warning if such an automatic conversion is necessary. 
 369         #XXX Komodo 2.0 Beta 1 hack. This requirement should be 
 370         #    pushed out to Komodo code using process.py. Or should it? 
 373             for key
, value 
in env
.items(): 
 374                 aenv
[str(key
)] = str(value
) 
 378 _SaferCreateProcess(appName=%r, 
 383 """, appName
, cmd
, env
, cwd
, os
.getcwd()) 
 385             hProcess
, hThread
, processId
, threadId\
 
 386                 = win32process
.CreateProcess(appName
, cmd
, processSA
, 
 387                                              threadSA
, inheritHandles
, 
 388                                              creationFlags
, env
, cwd
, si
) 
 389         except TypeError, ex
: 
 390             if ex
.args 
== ('All dictionary items must be strings, or all must be unicode',): 
 391                 # Try again with an all unicode environment. 
 392                 #XXX Would be nice if didn't have to depend on the error 
 393                 #    string to catch this. 
 394                 #XXX Removing this warning for 2.3 release. See bug 
 395                 #    23215. The right fix is to correct the PHPAppInfo 
 396                 #    stuff to heed the warning. 
 398                 #warnings.warn('env: ' + str(ex), stacklevel=4) 
 402                         for key
, value 
in env
.items(): 
 403                             aenv
[str(key
)] = str(value
) 
 404                     except UnicodeError, ex
: 
 405                         raise ProcessError(str(ex
)) 
 409                     for key
, val 
in env
.items(): 
 411                             uenv
[unicode(key
)] = unicode(val
)   # default encoding 
 414                                 uenv
[unicode(key
, 'iso-8859-1')] = unicode(val
, 'iso-8859-1')   # backup encoding 
 416                                 log
.warn('Skipping environment variable "%s" in execution process: unable to convert to unicode using either the default encoding or ISO-8859-1' % (key
)) 
 418                 hProcess
, hThread
, processId
, threadId\
 
 419                     = win32process
.CreateProcess(appName
, cmd
, processSA
, 
 420                                                  threadSA
, inheritHandles
, 
 421                                                  creationFlags
, env
, cwd
, 
 425         return hProcess
, hThread
, processId
, threadId
 
 428 # Maintain references to all spawned ProcessProxy objects to avoid hangs. 
 429 #   Otherwise, if the user lets the a ProcessProxy object go out of 
 430 #   scope before the process has terminated, it is possible to get a 
 431 #   hang (at least it *used* to be so when we had the 
 432 #   win32api.CloseHandle(<stdin handle>) call in the __del__() method). 
 433 #   XXX Is this hang possible on Linux as well? 
 434 # A reference is removed from this list when the process's .wait or 
 435 # .kill method is called. 
 436 # XXX Should an atexit() handler be registered to kill all curently 
 437 #     running processes? Else *could* get hangs, n'est ce pas? 
 438 def _registerProcess(process
): 
 440     log
.info("_registerprocess(process=%r)", process
) 
 442     # Clean up zombie processes. 
 443     #   If the user does not call .wait() or .kill() on processes then 
 444     #   the ProcessProxy object will not get cleaned up until Python 
 445     #   exits and _processes goes out of scope. Under heavy usage that 
 446     #   is a big memory waste. Cleaning up here alleviates that. 
 447     for p 
in _processes
[:]: # use copy of _process, because we may modifiy it 
 449             # poll to see if is process still running 
 450             if sys
.platform
.startswith("win"): 
 455             _unregisterProcess(p
) 
 456         except ProcessError
, ex
: 
 457             if ex
.errno 
== ProcessProxy
.WAIT_TIMEOUT
: 
 462     _processes
.append(process
) 
 464 def _unregisterProcess(process
): 
 466     log
.info("_unregisterProcess(process=%r)", process
) 
 468         _processes
.remove(process
) 
 474 def _fixupCommand(cmd
, env
=None): 
 475     """Fixup the command string so it is launchable via CreateProcess. 
 477     One cannot just launch, say "python", via CreateProcess. A full path 
 478     to an executable is required. In general there are two choices: 
 479         1. Launch the command string via the shell. The shell will find 
 480            the fullpath to the appropriate executable. This shell will 
 481            also be able to execute special shell commands, like "dir", 
 482            which don't map to an actual executable. 
 483         2. Find the fullpath to the appropriate executable manually and 
 486     Option (1) is preferred because you don't have to worry about not 
 487     exactly duplicating shell behaviour and you get the added bonus of 
 488     being able to launch "dir" and friends. 
 490     However, (1) is not always an option. Doing so when the shell is 
 491     command.com (as on all Win9x boxes) or when using WinNT's cmd.exe, 
 492     problems are created with .kill() because these shells seem to eat 
 493     up Ctrl-C's and Ctrl-Break's sent via 
 494     win32api.GenerateConsoleCtrlEvent().  Strangely this only happens 
 495     when spawn via this Python interface. For example, Ctrl-C get 
 496     through to hang.exe here: 
 497       C:\> ...\w9xpopen.exe "C:\WINDOWS\COMMAND.COM /c hang.exe" 
 500       >>> p = ProcessOpen('hang.exe') 
 501       # This results in the same command to CreateProcess as 
 505     Hence, for these platforms we fallback to option (2).  Cons: 
 506       - cannot spawn shell commands like 'dir' directly 
 507       - cannot spawn batch files 
 509     if sys
.platform
.startswith("win"): 
 510         # Fixup the command string to spawn.  (Lifted from 
 511         # posixmodule.c::_PyPopenCreateProcess() with some modifications) 
 512         comspec 
= os
.environ
.get("COMSPEC", None) 
 513         win32Version 
= win32api
.GetVersion() 
 515             raise ProcessError("Cannot locate a COMSPEC environment "\
 
 516                                "variable to use as the shell") 
 517         # Explicitly check if we are using COMMAND.COM.  If we 
 518         # are then use the w9xpopen hack. 
 519         elif (win32Version 
& 0x80000000L 
== 0) and\
 
 520              (win32Version 
&        0x5L 
>= 5) and\
 
 521              os
.path
.basename(comspec
).lower() != "command.com": 
 522             # 2000/XP and not using command.com. 
 523             if '"' in cmd 
or "'" in cmd
: 
 524                 cmd 
= comspec 
+ ' /c "%s"' % cmd
 
 526                 cmd 
= comspec 
+ ' /c ' + cmd
 
 527         elif (win32Version 
& 0x80000000L 
== 0) and\
 
 528              (win32Version 
&        0x5L  
< 5) and\
 
 529              os
.path
.basename(comspec
).lower() != "command.com": 
 530             # NT and not using command.com. 
 532                 cmd 
= _whichFirstArg(cmd
, env
) 
 534                 raise ProcessError("Could not find a suitable executable "\
 
 535                     "to launch for '%s'. On WinNT you must manually prefix "\
 
 536                     "shell commands and batch files with 'cmd.exe /c' to "\
 
 537                     "have the shell run them." % cmd
) 
 539             # Oh gag, we're on Win9x and/or using COMMAND.COM. Use the 
 540             # workaround listed in KB: Q150956 
 541             w9xpopen 
= os
.path
.join( 
 542                 os
.path
.dirname(win32api
.GetModuleFileName(0)), 
 544             if not os
.path
.exists(w9xpopen
): 
 545                 # Eeek - file-not-found - possibly an embedding 
 546                 # situation - see if we can locate it in sys.exec_prefix 
 547                 w9xpopen 
= os
.path
.join(os
.path
.dirname(sys
.exec_prefix
), 
 549                 if not os
.path
.exists(w9xpopen
): 
 551                         "Can not locate 'w9xpopen.exe' which is needed "\
 
 552                         "for ProcessOpen to work with your shell or "\
 
 554             ## This would be option (1): 
 555             #cmd = '%s "%s /c %s"'\ 
 556             #      % (w9xpopen, comspec, cmd.replace('"', '\\"')) 
 558                 cmd 
= _whichFirstArg(cmd
, env
) 
 560                 raise ProcessError("Could not find a suitable executable "\
 
 561                     "to launch for '%s'. On Win9x you must manually prefix "\
 
 562                     "shell commands and batch files with 'command.com /c' "\
 
 563                     "to have the shell run them." % cmd
) 
 564             cmd 
= '%s "%s"' % (w9xpopen
, cmd
.replace('"', '\\"')) 
 568     """Wrap a system file object, hiding some nitpicky details. 
 570     This class provides a Python file-like interface to either a Python 
 571     file object (pretty easy job), a file descriptor, or an OS-specific 
 572     file handle (e.g.  Win32 handles to file objects on Windows). Any or 
 573     all of these object types may be passed to this wrapper. If more 
 574     than one is specified this wrapper prefers to work with certain one 
 576         - file descriptor (because usually this allows for 
 577           return-immediately-on-read-if-anything-available semantics and 
 578           also provides text mode translation on Windows) 
 579         - OS-specific handle (allows for the above read semantics) 
 580         - file object (buffering can cause difficulty for interacting 
 581           with spawned programs) 
 583     It also provides a place where related such objects can be kept 
 584     alive together to prevent premature ref-counted collection. (E.g. on 
 585     Windows a Python file object may be associated with a Win32 file 
 586     handle. If the file handle is not kept alive the Python file object 
 587     will cease to function.) 
 589     def __init__(self
, file=None, descriptor
=None, handle
=None): 
 591         self
._descriptor 
= descriptor
 
 592         self
._handle 
= handle
 
 594         if self
._descriptor 
is not None or self
._handle 
is not None: 
 595             self
._lineBuf 
= "" # to support .readline() 
 600     def __getattr__(self
, name
): 
 601         """Forward to the underlying file object.""" 
 602         if self
._file 
is not None: 
 603             return getattr(self
._file
, name
) 
 605             raise ProcessError("no file object to pass '%s' attribute to" 
 608     def _win32Read(self
, nBytes
): 
 610             log
.info("[%s] _FileWrapper.read: waiting for read on pipe", 
 612             errCode
, text 
= win32file
.ReadFile(self
._handle
, nBytes
) 
 613         except pywintypes
.error
, ex
: 
 614             # Ignore errors for now, like "The pipe is being closed.", 
 615             # etc. XXX There *may* be errors we don't want to avoid. 
 616             log
.info("[%s] _FileWrapper.read: error reading from pipe: %s", 
 619         assert errCode 
== 0,\
 
 620                "Why is 'errCode' from ReadFile non-zero? %r" % errCode
 
 622             # Empty text signifies that the pipe has been closed on 
 624             log
.info("[%s] _FileWrapper.read: observed close of parent", 
 626             # Signal the child so it knows to stop listening. 
 630             log
.info("[%s] _FileWrapper.read: read %d bytes from pipe: %r", 
 631                      id(self
), len(text
), text
) 
 634     def read(self
, nBytes
=-1): 
 635         # nBytes <= 0 means "read everything" 
 636         #   Note that we are changing the "read everything" cue to 
 637         #   include 0, because actually doing 
 638         #   win32file.ReadFile(<handle>, 0) results in every subsequent 
 639         #   read returning 0, i.e. it shuts down the pipe. 
 640         if self
._descriptor 
is not None: 
 642                 text
, self
._lineBuf 
= self
._lineBuf
, "" 
 644                     t 
= os
.read(self
._descriptor
, 4092) 
 650                 if len(self
._lineBuf
) >= nBytes
: 
 651                     text
, self
._lineBuf 
=\
 
 652                         self
._lineBuf
[:nBytes
], self
._lineBuf
[nBytes
:] 
 654                     nBytesToGo 
= nBytes 
- len(self
._lineBuf
) 
 655                     text 
= self
._lineBuf 
+ os
.read(self
._descriptor
, 
 659         elif self
._handle 
is not None: 
 661                 text
, self
._lineBuf 
= self
._lineBuf
, "" 
 663                     t 
= self
._win
32Read
(4092) 
 669                 if len(self
._lineBuf
) >= nBytes
: 
 670                     text
, self
._lineBuf 
=\
 
 671                         self
._lineBuf
[:nBytes
], self
._lineBuf
[nBytes
:] 
 673                     nBytesToGo 
= nBytes 
- len(self
._lineBuf
) 
 674                     text
, self
._lineBuf 
=\
 
 675                         self
._lineBuf 
+ self
._win
32Read
(nBytesToGo
), "" 
 677         elif self
._file 
is not None: 
 678             return self
._file
.read(nBytes
) 
 680             raise "FileHandle.read: no handle to read with" 
 683         if self
._descriptor 
is not None or self
._handle 
is not None: 
 685                 #XXX This is not portable to the Mac. 
 686                 idx 
= self
._lineBuf
.find('\n') 
 688                     line
, self
._lineBuf 
=\
 
 689                         self
._lineBuf
[:idx
+1], self
._lineBuf
[idx
+1:] 
 692                     lengthBefore 
= len(self
._lineBuf
) 
 694                     if len(t
) <= lengthBefore
: # no new data was read 
 695                         line
, self
._lineBuf 
= self
._lineBuf
, "" 
 700         elif self
._file 
is not None: 
 701             return self
._file
.readline() 
 703             raise "FileHandle.readline: no handle to read with" 
 706         if self
._descriptor 
is not None or self
._handle 
is not None: 
 709                 line 
= self
.readline() 
 715         elif self
._file 
is not None: 
 716             return self
._file
.readlines() 
 718             raise "FileHandle.readline: no handle to read with" 
 720     def write(self
, text
): 
 721         if self
._descriptor 
is not None: 
 722             os
.write(self
._descriptor
, text
) 
 723         elif self
._handle 
is not None: 
 725                 errCode
, nBytesWritten 
= win32file
.WriteFile(self
._handle
, text
) 
 726             except pywintypes
.error
, ex
: 
 727                 # Ingore errors like "The pipe is being closed.", for 
 729                 log
.info("[%s] _FileWrapper.write: error writing to pipe, "\
 
 732             assert errCode 
== 0,\
 
 733                    "Why is 'errCode' from WriteFile non-zero? %r" % errCode
 
 734             if not nBytesWritten
: 
 735                 # No bytes written signifies that the pipe has been 
 736                 # closed on the child's end. 
 737                 log
.info("[%s] _FileWrapper.write: observed close of pipe", 
 741                 log
.info("[%s] _FileWrapper.write: wrote %d bytes to pipe: %r", 
 742                          id(self
), len(text
), text
) 
 743         elif self
._file 
is not None: 
 744             self
._file
.write(text
) 
 746             raise "FileHandle.write: nothing to write with" 
 749         """Close all associated file objects and handles.""" 
 750         log
.debug("[%s] _FileWrapper.close()", id(self
)) 
 753             if self
._file 
is not None: 
 754                 log
.debug("[%s] _FileWrapper.close: close file", id(self
)) 
 756                 log
.debug("[%s] _FileWrapper.close: done file close", id(self
)) 
 757             if self
._descriptor 
is not None: 
 759                     os
.close(self
._descriptor
) 
 762                         # Ignore: OSError: [Errno 9] Bad file descriptor 
 763                         # XXX *Should* we be ignoring this? It appears very 
 764                         #     *in*frequently in test_wait.py. 
 765                         log
.debug("[%s] _FileWrapper.close: closing "\
 
 766                                   "descriptor raised OSError", id(self
)) 
 769             if self
._handle 
is not None: 
 770                 log
.debug("[%s] _FileWrapper.close: close handle", id(self
)) 
 772                     win32api
.CloseHandle(self
._handle
) 
 773                 except win32api
.error
: 
 774                     log
.debug("[%s] _FileWrapper.close: closing handle raised", 
 777                 log
.debug("[%s] _FileWrapper.close: done closing handle", 
 781         return "<_FileWrapper: file:%r fd:%r os_handle:%r>"\
 
 782                % (self
._file
, self
._descriptor
, self
._handle
) 
 785 class _CountingCloser
: 
 786     """Call .close() on the given object after own .close() is called 
 787     the precribed number of times. 
 789     def __init__(self
, objectsToClose
, count
): 
 791         "objectsToClose" is a list of object on which to call .close(). 
 792         "count" is the number of times this object's .close() method 
 793             must be called before .close() is called on the given objects. 
 795         self
.objectsToClose 
= objectsToClose
 
 798             raise ProcessError("illegal 'count' value: %s" % self
.count
) 
 802         log
.debug("[%d] _CountingCloser.close(): count=%d", id(self
), 
 805             for objectToClose 
in self
.objectsToClose
: 
 806                 objectToClose
.close() 
 810 #---- public interface 
 815     One can optionally specify the starting working directory, the 
 816     process environment, and std handles to have the child process 
 817     inherit (all defaults are the parent's current settings). 'wait' and 
 818     'kill' method allow for control of the child's termination. 
 821     #   - Rename this or merge it with ProcessOpen somehow. 
 823     if sys
.platform
.startswith("win"): 
 824         # .wait() argument constants 
 825         INFINITE 
= win32event
.INFINITE
 
 826         # .wait() return error codes 
 827         WAIT_FAILED 
= win32event
.WAIT_FAILED
 
 828         WAIT_TIMEOUT 
= win32event
.WAIT_TIMEOUT
 
 829         # creation "flags" constants 
 830         # XXX Should drop these and just document usage of 
 831         #     win32process.CREATE_* constants on windows. 
 832         CREATE_NEW_CONSOLE 
= win32process
.CREATE_NEW_CONSOLE
 
 834         # .wait() argument constants 
 836         # .wait() return error codes 
 839         # creation "flags" constants 
 840         CREATE_NEW_CONSOLE 
= 0x10 # same as win32process.CREATE_NEW_CONSOLE 
 842     def __init__(self
, cmd
, cwd
=None, env
=None, flags
=0): 
 843         """Create a child process. 
 845         "cmd" is a command string or argument vector to spawn. 
 846         "cwd" is a working directory in which to start the child process. 
 847         "env" is an environment dictionary for the child. 
 848         "flags" are system-specific process creation flags. On Windows 
 849             this can be a bitwise-OR of any of the win32process.CREATE_* 
 850             constants (Note: win32process.CREATE_NEW_PROCESS_GROUP is always 
 851             OR'd in). On Unix, this is currently ignored. 
 853         log
.info("Process.__init__(cmd=%r, cwd=%r, env=%r, flags=%r)", 
 854                  cmd
, cwd
, env
, flags
) 
 857             raise ProcessError("You must specify a command.") 
 861         if sys
.platform
.startswith("win"): 
 862             self
._flags |
= win32process
.CREATE_NEW_PROCESS_GROUP
 
 864         if sys
.platform
.startswith("win"): 
 865             self
._startOnWindows
() 
 867             self
.__retvalCache 
= None 
 870     def _runChildOnUnix(self
): 
 871         #XXX Errors running the child do *not* get communicated back. 
 873         #XXX Perhaps we should *always* prefix with '/bin/sh -c'? There is a 
 874         #    disparity btwn how this works on Linux and Windows. 
 875         if isinstance(self
._cmd
, types
.StringTypes
): 
 876             # This is easier than trying to reproduce shell interpretation to 
 877             # separate the arguments. 
 878             cmd 
= ['/bin/sh', '-c', self
._cmd
] 
 882         # Close all file descriptors (except std*) inherited from the parent. 
 883         MAXFD 
= 256 # Max number of file descriptors (os.getdtablesize()???) 
 884         for i 
in range(3, MAXFD
): 
 892                 os
.execvpe(cmd
[0], cmd
, self
._env
) 
 894                 os
.execvp(cmd
[0], cmd
) 
 896             os
._exit
(1)  # Should never get here. 
 898     def _forkAndExecChildOnUnix(self
): 
 899         """Fork and start the child process. 
 901         Sets self._pid as a side effect. 
 905             self
._runChildOnUnix
() 
 909     def _startOnUnix(self
): 
 915                 raise ProcessError(msg
=str(ex
), errno
=ex
.errno
) 
 916         self
._forkAndExecChildOnUnix
() 
 922     def _startOnWindows(self
): 
 923         if type(self
._cmd
) in (types
.ListType
, types
.TupleType
): 
 924             # And arg vector was passed in. 
 925             cmd 
= _joinArgv(self
._cmd
) 
 929         si 
= win32process
.STARTUPINFO()  
 930         si
.dwFlags 
= win32process
.STARTF_USESHOWWINDOW
 
 931         si
.wShowWindow 
= SW_SHOWDEFAULT
 
 933         if not (self
._flags 
& self
.CREATE_NEW_CONSOLE
): 
 935             # We cannot then use _fixupCommand because this will cause a 
 936             # shell to be openned as the command is launched. Therefore need 
 937             # to ensure be have the full path to the executable to launch. 
 939                 cmd 
= _whichFirstArg(cmd
, self
._env
) 
 941                 # Could not find the command, perhaps it is an internal 
 942                 # shell command -- fallback to _fixupCommand 
 943                 cmd 
= _fixupCommand(cmd
, self
._env
) 
 945             cmd 
= _fixupCommand(cmd
, self
._env
) 
 946         log
.debug("cmd = %r", cmd
) 
 948         # Start the child process. 
 950             self
._hProcess
, self
._hThread
, self
._processId
, self
._threadId\
 
 951                 = _SaferCreateProcess( 
 954                     None,           # process security attributes  
 955                     None,           # primary thread security attributes  
 956                     0,              # handles are inherited  
 957                     self
._flags
,    # creation flags  
 958                     self
._env
,      # environment 
 959                     self
._cwd
,      # current working directory 
 960                     si
)             # STARTUPINFO pointer  
 961             win32api
.CloseHandle(self
._hThread
) 
 962         except win32api
.error
, ex
: 
 963             raise ProcessError(msg
="Error creating process for '%s': %s"\
 
 967     def wait(self
, timeout
=None):  
 968         """Wait for the started process to complete. 
 970         "timeout" (on Windows) is a floating point number of seconds after 
 971             which to timeout.  Default is win32event.INFINITE. 
 972         "timeout" (on Unix) is akin to the os.waitpid() "options" argument 
 973             (os.WNOHANG may be used to return immediately if the process has 
 974             not exited). Default is 0, i.e. wait forever. 
 976         If the wait time's out it will raise a ProcessError. Otherwise it 
 977         will return the child's exit value (on Windows) or the child's exit 
 978         status excoded as per os.waitpid() (on Linux): 
 979             "a 16-bit number, whose low byte is the signal number that killed 
 980             the process, and whose high byte is the exit status (if the 
 981             signal number is zero); the high bit of the low byte is set if a 
 982             core file was produced." 
 983         In the latter case, use the os.W*() methods to interpret the return 
 986         # XXX Or should returning the exit value be move out to another 
 987         #     function as on Win32 process control? If so, then should 
 988         #     perhaps not make WaitForSingleObject semantic transformation. 
 989         if sys
.platform
.startswith("win"): 
 991                 timeout 
= win32event
.INFINITE
 
 993                 timeout 
= timeout 
* 1000.0 # Win32 API's timeout is in millisecs 
 995             rc 
= win32event
.WaitForSingleObject(self
._hProcess
, timeout
) 
 996             if rc 
== win32event
.WAIT_FAILED
: 
 997                 raise ProcessError("'WAIT_FAILED' when waiting for process to "\
 
 998                                    "terminate: %r" % self
._cmd
, rc
) 
 999             elif rc 
== win32event
.WAIT_TIMEOUT
: 
1000                 raise ProcessError("'WAIT_TIMEOUT' when waiting for process to "\
 
1001                                    "terminate: %r" % self
._cmd
, rc
) 
1003             retval 
= win32process
.GetExitCodeProcess(self
._hProcess
) 
1005             # os.waitpid() will raise: 
1006             #       OSError: [Errno 10] No child processes 
1007             # on subsequent .wait() calls. Change these semantics to have 
1008             # subsequent .wait() calls return the exit status and return 
1009             # immediately without raising an exception. 
1010             # (XXX It would require synchronization code to handle the case 
1011             # of multiple simultaneous .wait() requests, however we can punt 
1012             # on that because it is moot while Linux still has the problem 
1013             # for which _ThreadFixer() exists.) 
1014             if self
.__retvalCache 
is not None: 
1015                 retval 
= self
.__retvalCache
 
1019                 pid
, sts 
= os
.waitpid(self
._pid
, timeout
) 
1020                 if pid 
== self
._pid
: 
1021                     self
.__retvalCache 
= retval 
= sts
 
1023                     raise ProcessError("Wait for process timed out.", 
1027     def kill(self
, exitCode
=0, gracePeriod
=1.0, sig
=None): 
1030         "exitCode" [deprecated, not supported] (Windows only) is the 
1031             code the terminated process should exit with. 
1032         "gracePeriod" (Windows only) is a number of seconds the process is 
1033             allowed to shutdown with a WM_CLOSE signal before a hard 
1034             terminate is called. 
1035         "sig" (Unix only) is the signal to use to kill the process. Defaults 
1036             to signal.SIGKILL. See os.kill() for more information. 
1039             Try for an orderly shutdown via WM_CLOSE.  If still running 
1040             after gracePeriod (1 sec. default), terminate. 
1042         if sys
.platform
.startswith("win"): 
1044             # Send WM_CLOSE to windows in this process group. 
1045             win32gui
.EnumWindows(self
._close
_, 0) 
1047             # Send Ctrl-Break signal to all processes attached to this 
1048             # console. This is supposed to trigger shutdown handlers in 
1049             # each of the processes. 
1051                 win32api
.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT
, 
1053             except AttributeError: 
1054                 log
.warn("The win32api module does not have "\
 
1055                          "GenerateConsoleCtrlEvent(). This may mean that "\
 
1056                          "parts of this process group have NOT been killed.") 
1057             except win32api
.error
, ex
: 
1058                 if ex
.args
[0] not in (6, 87): 
1059                     # Ignore the following: 
1060                     #   api_error: (87, 'GenerateConsoleCtrlEvent', 'The parameter is incorrect.') 
1061                     #   api_error: (6, 'GenerateConsoleCtrlEvent', 'The handle is invalid.') 
1062                     # Get error 6 if there is no console. 
1065             # Last resort: call TerminateProcess if it has not yet. 
1068                 self
.wait(gracePeriod
) 
1069             except ProcessError
, ex
: 
1070                 log
.info("[%s] Process.kill: calling TerminateProcess", id(self
)) 
1071                 win32process
.TerminateProcess(self
._hProcess
, -1) 
1072                 win32api
.Sleep(100) # wait for resources to be released 
1076                 sig 
= signal
.SIGKILL
 
1078                 os
.kill(self
._pid
, sig
) 
1081                     # Ignore:   OSError: [Errno 3] No such process 
1084     def _close_(self
, hwnd
, dummy
): 
1085         """Callback used by .kill() on Windows. 
1087         EnumWindows callback - sends WM_CLOSE to any window owned by this 
1090         threadId
, processId 
= win32process
.GetWindowThreadProcessId(hwnd
) 
1091         if processId 
== self
._processId
: 
1093             win32gui
.PostMessage(hwnd
, WM_CLOSE
, 0, 0) 
1096 class ProcessOpen(Process
): 
1097     """Create a process and setup pipes to it standard handles. 
1099     This is a super popen3. 
1102     #   - Share some implementation with Process and ProcessProxy. 
1105     def __init__(self
, cmd
, mode
='t', cwd
=None, env
=None): 
1106         """Create a Process with proxy threads for each std handle. 
1108         "cmd" is the command string or argument vector to run. 
1109         "mode" (Windows only) specifies whether the pipes used to communicate 
1110             with the child are openned in text, 't', or binary, 'b', mode. 
1111             This is ignored on platforms other than Windows. Default is 't'. 
1112         "cwd" optionally specifies the directory in which the child process 
1113             should be started. Default is None, a.k.a. inherits the cwd from 
1115         "env" is optionally a mapping specifying the environment in which to 
1116             start the child. Default is None, a.k.a. inherits the environment 
1119         # Keep a reference to ensure it is around for this object's destruction. 
1121         log
.info("ProcessOpen.__init__(cmd=%r, mode=%r, cwd=%r, env=%r)", 
1122                  cmd
, mode
, cwd
, env
) 
1125             raise ProcessError("You must specify a command.") 
1129         if self
._mode 
not in ('t', 'b'): 
1130             raise ProcessError("'mode' must be 't' or 'b'.") 
1133         if sys
.platform
.startswith("win"): 
1134             self
._startOnWindows
() 
1136             self
.__retvalCache 
= None 
1139         _registerProcess(self
) 
1142         #XXX Should probably not rely upon this. 
1143         logres
.info("[%s] ProcessOpen.__del__()", id(self
)) 
1145         del self
.__log 
# drop reference 
1148         if not self
._closed
: 
1149             self
.__log
.info("[%s] ProcessOpen.close()" % id(self
)) 
1151             # Ensure that all IOBuffer's are closed. If they are not, these 
1154                 self
.__log
.info("[%s] ProcessOpen: closing stdin (%r)."\
 
1155                                 % (id(self
), self
.stdin
)) 
1157             except AttributeError: 
1158                 # May not have gotten far enough in the __init__ to set 
1162                 self
.__log
.info("[%s] ProcessOpen: closing stdout (%r)."\
 
1163                                 % (id(self
), self
.stdout
)) 
1165             except AttributeError: 
1166                 # May not have gotten far enough in the __init__ to set 
1170                 self
.__log
.info("[%s] ProcessOpen: closing stderr (%r)."\
 
1171                                 % (id(self
), self
.stderr
)) 
1173             except AttributeError: 
1174                 # May not have gotten far enough in the __init__ to set 
1180     def _forkAndExecChildOnUnix(self
, fdChildStdinRd
, fdChildStdoutWr
, 
1182         """Fork and start the child process. 
1184         Sets self._pid as a side effect. 
1187         if pid 
== 0: # child 
1188             os
.dup2(fdChildStdinRd
, 0) 
1189             os
.dup2(fdChildStdoutWr
, 1) 
1190             os
.dup2(fdChildStderrWr
, 2) 
1191             self
._runChildOnUnix
() 
1195     def _startOnUnix(self
): 
1196         # Create pipes for std handles. 
1197         fdChildStdinRd
, fdChildStdinWr 
= os
.pipe() 
1198         fdChildStdoutRd
, fdChildStdoutWr 
= os
.pipe() 
1199         fdChildStderrRd
, fdChildStderrWr 
= os
.pipe() 
1202             oldDir 
= os
.getcwd() 
1206                 raise ProcessError(msg
=str(ex
), errno
=ex
.errno
) 
1207         self
._forkAndExecChildOnUnix
(fdChildStdinRd
, fdChildStdoutWr
, 
1212         os
.close(fdChildStdinRd
) 
1213         os
.close(fdChildStdoutWr
) 
1214         os
.close(fdChildStderrWr
) 
1216         self
.stdin 
= _FileWrapper(descriptor
=fdChildStdinWr
) 
1217         logres
.info("[%s] ProcessOpen._start(): create child stdin: %r", 
1218                     id(self
), self
.stdin
) 
1219         self
.stdout 
= _FileWrapper(descriptor
=fdChildStdoutRd
) 
1220         logres
.info("[%s] ProcessOpen._start(): create child stdout: %r", 
1221                     id(self
), self
.stdout
) 
1222         self
.stderr 
= _FileWrapper(descriptor
=fdChildStderrRd
) 
1223         logres
.info("[%s] ProcessOpen._start(): create child stderr: %r", 
1224                     id(self
), self
.stderr
) 
1226     def _startOnWindows(self
): 
1227         if type(self
._cmd
) in (types
.ListType
, types
.TupleType
): 
1228             # An arg vector was passed in. 
1229             cmd 
= _joinArgv(self
._cmd
) 
1233         # Create pipes for std handles. 
1234         # (Set the bInheritHandle flag so pipe handles are inherited.) 
1235         saAttr 
= pywintypes
.SECURITY_ATTRIBUTES() 
1236         saAttr
.bInheritHandle 
= 1 
1237         #XXX Should maybe try with os.pipe. Dunno what that does for 
1238         #    inheritability though. 
1239         hChildStdinRd
, hChildStdinWr 
= win32pipe
.CreatePipe(saAttr
, 0)  
1240         hChildStdoutRd
, hChildStdoutWr 
= win32pipe
.CreatePipe(saAttr
, 0)  
1241         hChildStderrRd
, hChildStderrWr 
= win32pipe
.CreatePipe(saAttr
, 0)  
1244             # Duplicate the parent ends of the pipes so they are not 
1246             hChildStdinWrDup 
= win32api
.DuplicateHandle( 
1247                 win32api
.GetCurrentProcess(), 
1249                 win32api
.GetCurrentProcess(), 
1252                 DUPLICATE_SAME_ACCESS
) 
1253             win32api
.CloseHandle(hChildStdinWr
) 
1254             self
._hChildStdinWr 
= hChildStdinWrDup
 
1255             hChildStdoutRdDup 
= win32api
.DuplicateHandle( 
1256                 win32api
.GetCurrentProcess(), 
1258                 win32api
.GetCurrentProcess(), 
1261                 DUPLICATE_SAME_ACCESS
) 
1262             win32api
.CloseHandle(hChildStdoutRd
) 
1263             self
._hChildStdoutRd 
= hChildStdoutRdDup
 
1264             hChildStderrRdDup 
= win32api
.DuplicateHandle( 
1265                 win32api
.GetCurrentProcess(), 
1267                 win32api
.GetCurrentProcess(), 
1270                 DUPLICATE_SAME_ACCESS
) 
1271             win32api
.CloseHandle(hChildStderrRd
) 
1272             self
._hChildStderrRd 
= hChildStderrRdDup
 
1274             # Set the translation mode and buffering. 
1275             if self
._mode 
== 't': 
1279             fdChildStdinWr 
= msvcrt
.open_osfhandle(self
._hChildStdinWr
, flags
) 
1280             fdChildStdoutRd 
= msvcrt
.open_osfhandle(self
._hChildStdoutRd
, flags
) 
1281             fdChildStderrRd 
= msvcrt
.open_osfhandle(self
._hChildStderrRd
, flags
) 
1283             self
.stdin 
= _FileWrapper(descriptor
=fdChildStdinWr
, 
1284                                       handle
=self
._hChildStdinWr
) 
1285             logres
.info("[%s] ProcessOpen._start(): create child stdin: %r", 
1286                         id(self
), self
.stdin
) 
1287             self
.stdout 
= _FileWrapper(descriptor
=fdChildStdoutRd
, 
1288                                        handle
=self
._hChildStdoutRd
) 
1289             logres
.info("[%s] ProcessOpen._start(): create child stdout: %r", 
1290                         id(self
), self
.stdout
) 
1291             self
.stderr 
= _FileWrapper(descriptor
=fdChildStderrRd
, 
1292                                        handle
=self
._hChildStderrRd
) 
1293             logres
.info("[%s] ProcessOpen._start(): create child stderr: %r", 
1294                         id(self
), self
.stderr
) 
1296             # Start the child process. 
1297             si 
= win32process
.STARTUPINFO()  
1298             si
.dwFlags 
= win32process
.STARTF_USESHOWWINDOW
 
1299             si
.wShowWindow 
= 0 # SW_HIDE 
1300             si
.hStdInput 
= hChildStdinRd
 
1301             si
.hStdOutput 
= hChildStdoutWr
 
1302             si
.hStdError 
= hChildStderrWr
 
1303             si
.dwFlags |
= win32process
.STARTF_USESTDHANDLES
 
1305             cmd 
= _fixupCommand(cmd
, self
._env
) 
1307             creationFlags 
= win32process
.CREATE_NEW_PROCESS_GROUP
 
1309                 self
._hProcess
, hThread
, self
._processId
, threadId\
 
1310                     = _SaferCreateProcess( 
1313                         None,           # process security attributes  
1314                         None,           # primary thread security attributes  
1315                         1,              # handles are inherited  
1316                         creationFlags
,  # creation flags  
1317                         self
._env
,      # environment 
1318                         self
._cwd
,      # current working directory 
1319                         si
)             # STARTUPINFO pointer  
1320             except win32api
.error
, ex
: 
1321                 raise ProcessError(msg
=ex
.args
[2], errno
=ex
.args
[0]) 
1322             win32api
.CloseHandle(hThread
) 
1325             # Close child ends of pipes on the parent's side (the 
1326             # parent's ends of the pipe are closed in the _FileWrappers.) 
1327             win32file
.CloseHandle(hChildStdinRd
) 
1328             win32file
.CloseHandle(hChildStdoutWr
) 
1329             win32file
.CloseHandle(hChildStderrWr
) 
1331     def wait(self
, timeout
=None):  
1332         """Wait for the started process to complete. 
1334         "timeout" (on Windows) is a floating point number of seconds after 
1335             which to timeout.  Default is win32event.INFINITE. 
1336         "timeout" (on Unix) is akin to the os.waitpid() "options" argument 
1337             (os.WNOHANG may be used to return immediately if the process has 
1338             not exited). Default is 0, i.e. wait forever. 
1340         If the wait time's out it will raise a ProcessError. Otherwise it 
1341         will return the child's exit value (on Windows) or the child's exit 
1342         status excoded as per os.waitpid() (on Linux): 
1343             "a 16-bit number, whose low byte is the signal number that killed 
1344             the process, and whose high byte is the exit status (if the 
1345             signal number is zero); the high bit of the low byte is set if a 
1346             core file was produced." 
1347         In the latter case, use the os.W*() methods to interpret the return 
1350         # XXX Or should returning the exit value be move out to another 
1351         #    function as on Win32 process control? If so, then should 
1352         #    perhaps not make WaitForSingleObject semantic 
1355         #   - Need to rationalize the .wait() API for Windows vs. Unix. 
1356         #     It is a real pain in the current situation. 
1357         if sys
.platform
.startswith("win"): 
1359                 timeout 
= win32event
.INFINITE
 
1361                 timeout 
= timeout 
* 1000.0 # Win32 API's timeout is in millisecs 
1363             #rc = win32event.WaitForSingleObject(self._hProcess, timeout) 
1364             rc 
= win32event
.WaitForSingleObject(self
._hProcess
, int(timeout
)) # MATT -- Making timeout an integer 
1365             if rc 
== win32event
.WAIT_FAILED
: 
1366                 raise ProcessError("'WAIT_FAILED' when waiting for process to "\
 
1367                                    "terminate: %r" % self
._cmd
, rc
) 
1368             elif rc 
== win32event
.WAIT_TIMEOUT
: 
1369                 raise ProcessError("'WAIT_TIMEOUT' when waiting for process to "\
 
1370                                    "terminate: %r" % self
._cmd
, rc
) 
1372             retval 
= win32process
.GetExitCodeProcess(self
._hProcess
) 
1374             # os.waitpid() will raise: 
1375             #       OSError: [Errno 10] No child processes 
1376             # on subsequent .wait() calls. Change these semantics to have 
1377             # subsequent .wait() calls return the exit status and return 
1378             # immediately without raising an exception. 
1379             # (XXX It would require synchronization code to handle the case 
1380             # of multiple simultaneous .wait() requests, however we can punt 
1381             # on that because it is moot while Linux still has the problem 
1382             # for which _ThreadFixer() exists.) 
1383             if self
.__retvalCache 
is not None: 
1384                 retval 
= self
.__retvalCache
 
1388                 pid
, sts 
= os
.waitpid(self
._pid
, timeout
) 
1389                 if pid 
== self
._pid
: 
1390                     self
.__retvalCache 
= retval 
= sts
 
1392                     raise ProcessError("Wait for process timed out.", 
1394         _unregisterProcess(self
) 
1397     def kill(self
, exitCode
=0, gracePeriod
=1.0, sig
=None): 
1400         "exitCode" [deprecated, not supported] (Windows only) is the 
1401             code the terminated process should exit with. 
1402         "gracePeriod" (Windows only) is a number of seconds the process is 
1403             allowed to shutdown with a WM_CLOSE signal before a hard 
1404             terminate is called. 
1405         "sig" (Unix only) is the signal to use to kill the process. Defaults 
1406             to signal.SIGKILL. See os.kill() for more information. 
1409             Try for an orderly shutdown via WM_CLOSE.  If still running 
1410             after gracePeriod (1 sec. default), terminate. 
1412         if sys
.platform
.startswith("win"): 
1414             # Send WM_CLOSE to windows in this process group. 
1415             win32gui
.EnumWindows(self
._close
_, 0) 
1417             # Send Ctrl-Break signal to all processes attached to this 
1418             # console. This is supposed to trigger shutdown handlers in 
1419             # each of the processes. 
1421                 win32api
.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT
, 
1423             except AttributeError: 
1424                 log
.warn("The win32api module does not have "\
 
1425                          "GenerateConsoleCtrlEvent(). This may mean that "\
 
1426                          "parts of this process group have NOT been killed.") 
1427             except win32api
.error
, ex
: 
1428                 if ex
.args
[0] not in (6, 87): 
1429                     # Ignore the following: 
1430                     #   api_error: (87, 'GenerateConsoleCtrlEvent', 'The parameter is incorrect.') 
1431                     #   api_error: (6, 'GenerateConsoleCtrlEvent', 'The handle is invalid.') 
1432                     # Get error 6 if there is no console. 
1435             # Last resort: call TerminateProcess if it has not yet. 
1438                 self
.wait(gracePeriod
) 
1439             except ProcessError
, ex
: 
1440                 log
.info("[%s] Process.kill: calling TerminateProcess", id(self
)) 
1441                 win32process
.TerminateProcess(self
._hProcess
, -1) 
1442                 win32api
.Sleep(100) # wait for resources to be released 
1446                 sig 
= signal
.SIGKILL
 
1448                 os
.kill(self
._pid
, sig
) 
1451                     # Ignore:   OSError: [Errno 3] No such process 
1454         _unregisterProcess(self
) 
1456     def _close_(self
, hwnd
, dummy
): 
1457         """Callback used by .kill() on Windows. 
1459         EnumWindows callback - sends WM_CLOSE to any window owned by this 
1462         threadId
, processId 
= win32process
.GetWindowThreadProcessId(hwnd
) 
1463         if processId 
== self
._processId
: 
1465             win32gui
.PostMessage(hwnd
, WM_CLOSE
, 0, 0) 
1468 class ProcessProxy(Process
): 
1469     """Create a process and proxy communication via the standard handles. 
1471     #XXX To add to docstring: 
1472     #   - stdout/stderr proxy handling 
1473     #   - stdin proxy handling 
1475     #   - how to .start(), i.e. basic usage rules 
1476     #   - mention that pased in stdin/stdout/stderr objects have to 
1477     #     implement at least .write (is .write correct for stdin)? 
1478     #   - if you pass in stdin, stdout, and/or stderr streams it is the 
1479     #     user's responsibility to close them afterwards. 
1480     #   - 'cmd' arg can be a command string or an arg vector 
1483     #   - .suspend() and .resume()? See Win32::Process Perl module. 
1485     def __init__(self
, cmd
, mode
='t', cwd
=None, env
=None, 
1486                  stdin
=None, stdout
=None, stderr
=None): 
1487         """Create a Process with proxy threads for each std handle. 
1489         "cmd" is the command string or argument vector to run. 
1490         "mode" (Windows only) specifies whether the pipes used to communicate 
1491             with the child are openned in text, 't', or binary, 'b', mode. 
1492             This is ignored on platforms other than Windows. Default is 't'. 
1493         "cwd" optionally specifies the directory in which the child process 
1494             should be started. Default is None, a.k.a. inherits the cwd from 
1496         "env" is optionally a mapping specifying the environment in which to 
1497             start the child. Default is None, a.k.a. inherits the environment 
1499         "stdin", "stdout", "stderr" can be used to specify objects with 
1500             file-like interfaces to handle read (stdout/stderr) and write 
1501             (stdin) events from the child. By default a process.IOBuffer 
1502             instance is assigned to each handler. IOBuffer may be 
1503             sub-classed. See the IOBuffer doc string for more information. 
1505         # Keep a reference to ensure it is around for this object's destruction. 
1507         log
.info("ProcessProxy.__init__(cmd=%r, mode=%r, cwd=%r, env=%r, "\
 
1508                  "stdin=%r, stdout=%r, stderr=%r)", 
1509                  cmd
, mode
, cwd
, env
, stdin
, stdout
, stderr
) 
1512             raise ProcessError("You must specify a command.") 
1514         if self
._mode 
not in ('t', 'b'): 
1515             raise ProcessError("'mode' must be 't' or 'b'.") 
1519             self
.stdin 
= IOBuffer(name
='<stdin>') 
1523             self
.stdout 
= IOBuffer(name
='<stdout>') 
1525             self
.stdout 
= stdout
 
1527             self
.stderr 
= IOBuffer(name
='<stderr>') 
1529             self
.stderr 
= stderr
 
1532         if sys
.platform
.startswith("win"): 
1533             self
._startOnWindows
() 
1535             self
.__retvalCache 
= None 
1538         _registerProcess(self
) 
1541         #XXX Should probably not rely upon this. 
1542         logres
.info("[%s] ProcessProxy.__del__()", id(self
)) 
1544         del self
.__log 
# drop reference 
1547         if not self
._closed
: 
1548             self
.__log
.info("[%s] ProcessProxy.close()" % id(self
)) 
1550             # Ensure that all IOBuffer's are closed. If they are not, these 
1552             self
.__log
.info("[%s] ProcessProxy: closing stdin (%r)."\
 
1553                             % (id(self
), self
.stdin
)) 
1556                 self
._stdinProxy
.join() 
1557             except AttributeError: 
1558                 # May not have gotten far enough in the __init__ to set 
1561             self
.__log
.info("[%s] ProcessProxy: closing stdout (%r)."\
 
1562                             % (id(self
), self
.stdout
)) 
1565                 if self
._stdoutProxy 
is not threading
.currentThread(): 
1566                     self
._stdoutProxy
.join() 
1567             except AttributeError: 
1568                 # May not have gotten far enough in the __init__ to set 
1571             self
.__log
.info("[%s] ProcessProxy: closing stderr (%r)."\
 
1572                             % (id(self
), self
.stderr
)) 
1575                 if self
._stderrProxy 
is not threading
.currentThread(): 
1576                     self
._stderrProxy
.join() 
1577             except AttributeError: 
1578                 # May not have gotten far enough in the __init__ to set 
1584     def _forkAndExecChildOnUnix(self
, fdChildStdinRd
, fdChildStdoutWr
, 
1586         """Fork and start the child process. 
1588         Sets self._pid as a side effect. 
1591         if pid 
== 0: # child 
1592             os
.dup2(fdChildStdinRd
, 0) 
1593             os
.dup2(fdChildStdoutWr
, 1) 
1594             os
.dup2(fdChildStderrWr
, 2) 
1595             self
._runChildOnUnix
() 
1599     def _startOnUnix(self
): 
1600         # Create pipes for std handles. 
1601         fdChildStdinRd
, fdChildStdinWr 
= os
.pipe() 
1602         fdChildStdoutRd
, fdChildStdoutWr 
= os
.pipe() 
1603         fdChildStderrRd
, fdChildStderrWr 
= os
.pipe() 
1606             oldDir 
= os
.getcwd() 
1610                 raise ProcessError(msg
=str(ex
), errno
=ex
.errno
) 
1611         self
._forkAndExecChildOnUnix
(fdChildStdinRd
, fdChildStdoutWr
, 
1616         os
.close(fdChildStdinRd
) 
1617         os
.close(fdChildStdoutWr
) 
1618         os
.close(fdChildStderrWr
) 
1620         childStdin 
= _FileWrapper(descriptor
=fdChildStdinWr
) 
1621         logres
.info("[%s] ProcessProxy._start(): create child stdin: %r", 
1622                     id(self
), childStdin
) 
1623         childStdout 
= _FileWrapper(descriptor
=fdChildStdoutRd
) 
1624         logres
.info("[%s] ProcessProxy._start(): create child stdout: %r", 
1625                     id(self
), childStdout
) 
1626         childStderr 
= _FileWrapper(descriptor
=fdChildStderrRd
) 
1627         logres
.info("[%s] ProcessProxy._start(): create child stderr: %r", 
1628                     id(self
), childStderr
) 
1630         # Create proxy threads for the out pipes. 
1631         self
._stdinProxy 
= _InFileProxy(self
.stdin
, childStdin
, name
='<stdin>') 
1632         self
._stdinProxy
.start() 
1633         # Clean up the parent's side of <stdin> when it is observed that 
1634         # the child has closed its side of <stdout> and <stderr>. (This 
1635         # is one way of determining when it is appropriate to clean up 
1636         # this pipe, with compromises. See the discussion at the top of 
1638         closer 
= _CountingCloser([self
.stdin
, childStdin
, self
], 2) 
1639         self
._stdoutProxy 
= _OutFileProxy(childStdout
, self
.stdout
,  
1642         self
._stdoutProxy
.start() 
1643         self
._stderrProxy 
= _OutFileProxy(childStderr
, self
.stderr
, 
1646         self
._stderrProxy
.start() 
1648     def _startOnWindows(self
): 
1649         if type(self
._cmd
) in (types
.ListType
, types
.TupleType
): 
1650             # An arg vector was passed in. 
1651             cmd 
= _joinArgv(self
._cmd
) 
1655         # Create pipes for std handles. 
1656         # (Set the bInheritHandle flag so pipe handles are inherited.) 
1657         saAttr 
= pywintypes
.SECURITY_ATTRIBUTES() 
1658         saAttr
.bInheritHandle 
= 1 
1659         #XXX Should maybe try with os.pipe. Dunno what that does for 
1660         #    inheritability though. 
1661         hChildStdinRd
, hChildStdinWr 
= win32pipe
.CreatePipe(saAttr
, 0)  
1662         hChildStdoutRd
, hChildStdoutWr 
= win32pipe
.CreatePipe(saAttr
, 0)  
1663         hChildStderrRd
, hChildStderrWr 
= win32pipe
.CreatePipe(saAttr
, 0)  
1666             # Duplicate the parent ends of the pipes so they are not 
1668             hChildStdinWrDup 
= win32api
.DuplicateHandle( 
1669                 win32api
.GetCurrentProcess(), 
1671                 win32api
.GetCurrentProcess(), 
1674                 DUPLICATE_SAME_ACCESS
) 
1675             win32api
.CloseHandle(hChildStdinWr
) 
1676             self
._hChildStdinWr 
= hChildStdinWrDup
 
1677             hChildStdoutRdDup 
= win32api
.DuplicateHandle( 
1678                 win32api
.GetCurrentProcess(), 
1680                 win32api
.GetCurrentProcess(), 
1683                 DUPLICATE_SAME_ACCESS
) 
1684             win32api
.CloseHandle(hChildStdoutRd
) 
1685             self
._hChildStdoutRd 
= hChildStdoutRdDup
 
1686             hChildStderrRdDup 
= win32api
.DuplicateHandle( 
1687                 win32api
.GetCurrentProcess(), 
1689                 win32api
.GetCurrentProcess(), 
1692                 DUPLICATE_SAME_ACCESS
) 
1693             win32api
.CloseHandle(hChildStderrRd
) 
1694             self
._hChildStderrRd 
= hChildStderrRdDup
 
1696             # Set the translation mode. 
1697             if self
._mode 
== 't': 
1703             fdChildStdinWr 
= msvcrt
.open_osfhandle(self
._hChildStdinWr
, flags
) 
1704             fdChildStdoutRd 
= msvcrt
.open_osfhandle(self
._hChildStdoutRd
, flags
) 
1705             fdChildStderrRd 
= msvcrt
.open_osfhandle(self
._hChildStderrRd
, flags
) 
1707             childStdin 
= _FileWrapper(descriptor
=fdChildStdinWr
, 
1708                                       handle
=self
._hChildStdinWr
) 
1709             logres
.info("[%s] ProcessProxy._start(): create child stdin: %r", 
1710                         id(self
), childStdin
) 
1711             childStdout 
= _FileWrapper(descriptor
=fdChildStdoutRd
, 
1712                                        handle
=self
._hChildStdoutRd
) 
1713             logres
.info("[%s] ProcessProxy._start(): create child stdout: %r", 
1714                         id(self
), childStdout
) 
1715             childStderr 
= _FileWrapper(descriptor
=fdChildStderrRd
, 
1716                                        handle
=self
._hChildStderrRd
) 
1717             logres
.info("[%s] ProcessProxy._start(): create child stderr: %r", 
1718                         id(self
), childStderr
) 
1720             # Start the child process. 
1721             si 
= win32process
.STARTUPINFO()  
1722             si
.dwFlags 
= win32process
.STARTF_USESHOWWINDOW
 
1723             si
.wShowWindow 
= 0 # SW_HIDE 
1724             si
.hStdInput 
= hChildStdinRd
 
1725             si
.hStdOutput 
= hChildStdoutWr
 
1726             si
.hStdError 
= hChildStderrWr
 
1727             si
.dwFlags |
= win32process
.STARTF_USESTDHANDLES
 
1729             cmd 
= _fixupCommand(cmd
, self
._env
) 
1730             log
.debug("cmd = %r", cmd
) 
1732             creationFlags 
= win32process
.CREATE_NEW_PROCESS_GROUP
 
1734                 self
._hProcess
, hThread
, self
._processId
, threadId\
 
1735                     = _SaferCreateProcess( 
1738                         None,           # process security attributes  
1739                         None,           # primary thread security attributes  
1740                         1,              # handles are inherited  
1741                         creationFlags
,  # creation flags  
1742                         self
._env
,      # environment 
1743                         self
._cwd
,      # current working directory 
1744                         si
)             # STARTUPINFO pointer  
1745             except win32api
.error
, ex
: 
1746                 raise ProcessError(msg
=ex
.args
[2], errno
=ex
.args
[0]) 
1747             win32api
.CloseHandle(hThread
) 
1750             # Close child ends of pipes on the parent's side (the 
1751             # parent's ends of the pipe are closed in the _FileWrappers.) 
1752             win32file
.CloseHandle(hChildStdinRd
) 
1753             win32file
.CloseHandle(hChildStdoutWr
) 
1754             win32file
.CloseHandle(hChildStderrWr
) 
1756         # Create proxy threads for the pipes. 
1757         self
._stdinProxy 
= _InFileProxy(self
.stdin
, childStdin
, name
='<stdin>') 
1758         self
._stdinProxy
.start() 
1759         # Clean up the parent's side of <stdin> when it is observed that 
1760         # the child has closed its side of <stdout>. (This is one way of 
1761         # determining when it is appropriate to clean up this pipe, with 
1762         # compromises. See the discussion at the top of this module.) 
1763         self
._stdoutProxy 
= _OutFileProxy(childStdout
, self
.stdout
,  
1764                                           [self
.stdin
, childStdin
, self
], 
1766         self
._stdoutProxy
.start() 
1767         self
._stderrProxy 
= _OutFileProxy(childStderr
, self
.stderr
, 
1769         self
._stderrProxy
.start() 
1771     def wait(self
, timeout
=None):  
1772         """Wait for the started process to complete. 
1774         "timeout" (on Windows) is a floating point number of seconds after 
1775             which to timeout.  Default is win32event.INFINITE. 
1776         "timeout" (on Unix) is akin to the os.waitpid() "options" argument 
1777             (os.WNOHANG may be used to return immediately if the process has 
1778             not exited). Default is 0, i.e. wait forever. 
1780         If the wait time's out it will raise a ProcessError. Otherwise it 
1781         will return the child's exit value (on Windows) or the child's exit 
1782         status excoded as per os.waitpid() (on Linux): 
1783             "a 16-bit number, whose low byte is the signal number that killed 
1784             the process, and whose high byte is the exit status (if the 
1785             signal number is zero); the high bit of the low byte is set if a 
1786             core file was produced." 
1787         In the latter case, use the os.W*() methods to interpret the return 
1790         # XXX Or should returning the exit value be move out to another 
1791         #     function as on Win32 process control? If so, then should 
1792         #     perhaps not make WaitForSingleObject semantic transformation. 
1793         if sys
.platform
.startswith("win"): 
1795                 timeout 
= win32event
.INFINITE
 
1797                 timeout 
= timeout 
* 1000.0 # Win32 API's timeout is in millisecs 
1799             rc 
= win32event
.WaitForSingleObject(self
._hProcess
, timeout
) 
1800             if rc 
== win32event
.WAIT_FAILED
: 
1801                 raise ProcessError("'WAIT_FAILED' when waiting for process to "\
 
1802                                    "terminate: %r" % self
._cmd
, rc
) 
1803             elif rc 
== win32event
.WAIT_TIMEOUT
: 
1804                 raise ProcessError("'WAIT_TIMEOUT' when waiting for process to "\
 
1805                                    "terminate: %r" % self
._cmd
, rc
) 
1807             retval 
= win32process
.GetExitCodeProcess(self
._hProcess
) 
1809             # os.waitpid() will raise: 
1810             #       OSError: [Errno 10] No child processes 
1811             # on subsequent .wait() calls. Change these semantics to have 
1812             # subsequent .wait() calls return the exit status and return 
1813             # immediately without raising an exception. 
1814             # (XXX It would require synchronization code to handle the case 
1815             # of multiple simultaneous .wait() requests, however we can punt 
1816             # on that because it is moot while Linux still has the problem 
1817             # for which _ThreadFixer() exists.) 
1818             if self
.__retvalCache 
is not None: 
1819                 retval 
= self
.__retvalCache
 
1823                 pid
, sts 
= os
.waitpid(self
._pid
, timeout
) 
1824                 if pid 
== self
._pid
: 
1825                     self
.__retvalCache 
= retval 
= sts
 
1827                     raise ProcessError("Wait for process timed out.", 
1829         _unregisterProcess(self
) 
1832     def kill(self
, exitCode
=0, gracePeriod
=1.0, sig
=None): 
1835         "exitCode" [deprecated, not supported] (Windows only) is the 
1836             code the terminated process should exit with. 
1837         "gracePeriod" (Windows only) is a number of seconds the process is 
1838             allowed to shutdown with a WM_CLOSE signal before a hard 
1839             terminate is called. 
1840         "sig" (Unix only) is the signal to use to kill the process. Defaults 
1841             to signal.SIGKILL. See os.kill() for more information. 
1844             Try for an orderly shutdown via WM_CLOSE.  If still running 
1845             after gracePeriod (1 sec. default), terminate. 
1847         if sys
.platform
.startswith("win"): 
1849             # Send WM_CLOSE to windows in this process group. 
1850             win32gui
.EnumWindows(self
._close
_, 0) 
1852             # Send Ctrl-Break signal to all processes attached to this 
1853             # console. This is supposed to trigger shutdown handlers in 
1854             # each of the processes. 
1856                 win32api
.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT
, 
1858             except AttributeError: 
1859                 log
.warn("The win32api module does not have "\
 
1860                          "GenerateConsoleCtrlEvent(). This may mean that "\
 
1861                          "parts of this process group have NOT been killed.") 
1862             except win32api
.error
, ex
: 
1863                 if ex
.args
[0] not in (6, 87): 
1864                     # Ignore the following: 
1865                     #   api_error: (87, 'GenerateConsoleCtrlEvent', 'The parameter is incorrect.') 
1866                     #   api_error: (6, 'GenerateConsoleCtrlEvent', 'The handle is invalid.') 
1867                     # Get error 6 if there is no console. 
1870             # Last resort: call TerminateProcess if it has not yet. 
1873                 self
.wait(gracePeriod
) 
1874             except ProcessError
, ex
: 
1875                 log
.info("[%s] Process.kill: calling TerminateProcess", id(self
)) 
1876                 win32process
.TerminateProcess(self
._hProcess
, -1) 
1877                 win32api
.Sleep(100) # wait for resources to be released 
1881                 sig 
= signal
.SIGKILL
 
1883                 os
.kill(self
._pid
, sig
) 
1886                     # Ignore:   OSError: [Errno 3] No such process 
1889         _unregisterProcess(self
) 
1891     def _close_(self
, hwnd
, dummy
): 
1892         """Callback used by .kill() on Windows. 
1894         EnumWindows callback - sends WM_CLOSE to any window owned by this 
1897         threadId
, processId 
= win32process
.GetWindowThreadProcessId(hwnd
) 
1898         if processId 
== self
._processId
: 
1900             win32gui
.PostMessage(hwnd
, WM_CLOSE
, 0, 0) 
1904     """Want to be able to both read and write to this buffer from 
1905     difference threads and have the same read/write semantics as for a 
1908     This class is subclass-able. _doRead(), _doWrite(), _doReadline(), 
1909     _doClose(), _haveLine(), and _haveNumBytes() can be overridden for 
1910     specific functionality. The synchronization issues (block on read 
1911     until write provides the needed data, termination) are handled for 
1915         .seek()     # Because we are managing *two* positions (one each 
1916         .tell()     #   for reading and writing), these do not make 
1920     #   - Is performance a problem? This will likely be slower that 
1921     #     StringIO.StringIO(). 
1923     def __init__(self
, mutex
=None, stateChange
=None, name
=None): 
1924         """'name' can be set for debugging, it will be used in log messages.""" 
1925         if name 
is not None: 
1928             self
._name 
= id(self
) 
1929         log
.info("[%s] IOBuffer.__init__()" % self
._name
) 
1932         # A state change is defined as the buffer being closed or a 
1934         if mutex 
is not None: 
1937             self
._mutex 
= threading
.Lock() 
1938         if stateChange 
is not None: 
1939             self
._stateChange 
= stateChange
 
1941             self
._stateChange 
= threading
.Condition() 
1944     def _doWrite(self
, s
): 
1945         self
.__buf 
+= s  
# Append to buffer. 
1948         log
.info("[%s] IOBuffer.write(s=%r)", self
._name
, s
) 
1949         # Silently drop writes after the buffer has been close()'d. 
1952         # If empty write, close buffer (mimicking behaviour from 
1958         self
._mutex
.acquire() 
1960         self
._stateChange
.acquire() 
1961         self
._stateChange
.notifyAll()   # Notify of the write(). 
1962         self
._stateChange
.release() 
1963         self
._mutex
.release() 
1965     def writelines(self
, list): 
1966         self
.write(''.join(list)) 
1968     def _doRead(self
, n
): 
1969         """Pop 'n' bytes from the internal buffer and return them.""" 
1971             idx 
= len(self
.__buf
) 
1973             idx 
= min(n
, len(self
.__buf
)) 
1974         retval
, self
.__buf 
= self
.__buf
[:idx
], self
.__buf
[idx
:] 
1977     def read(self
, n
=-1): 
1978         log
.info("[%s] IOBuffer.read(n=%r)" % (self
._name
, n
)) 
1979         log
.info("[%s] IOBuffer.read(): wait for data" % self
._name
) 
1981             # Wait until the buffer is closed, i.e. no more writes will 
1984                 if self
._closed
: break 
1985                 #log.debug("[%s]     <<< IOBuffer.read: state change .wait()"\ 
1987                 self
._stateChange
.acquire() 
1988                 self
._stateChange
.wait() 
1989                 self
._stateChange
.release() 
1990                 #log.debug("[%s]     >>> IOBuffer.read: done change .wait()"\ 
1993             # Wait until there are the requested number of bytes to read 
1994             # (or until the buffer is closed, i.e. no more writes will 
1996             # XXX WARNING: I *think* there is a race condition around 
1997             #     here whereby self.fparent.read() in _InFileProxy can 
1998             #     hang. *Sometime* test_stdin::test_stdin_buffer() will 
1999             #     hang. This was *before* I moved the 
2000             #     _stateChange.acquire() and .release() calls out side 
2001             #     of the 'while 1:' here. ...and now they are back 
2004                 if self
._closed
: break 
2005                 if self
._haveNumBytes
(n
): break 
2006                 #log.debug("[%s]     <<< IOBuffer.read: state change .wait()"\ 
2008                 self
._stateChange
.acquire() 
2009                 self
._stateChange
.wait() 
2010                 self
._stateChange
.release() 
2011                 #log.debug("[%s]     >>> IOBuffer.read: done change .wait()"\ 
2013         log
.info("[%s] IOBuffer.read(): done waiting for data" % self
._name
) 
2015         self
._mutex
.acquire() 
2016         retval 
= self
._doRead
(n
) 
2017         self
._mutex
.release() 
2020     def _doReadline(self
, n
): 
2021         """Pop the front line (or n bytes of it, whichever is less) from 
2022         the internal buffer and return it. 
2024         idx 
= self
.__buf
.find('\n') 
2026             idx 
= len(self
.__buf
) 
2028             idx 
+= 1 # include the '\n' 
2031         retval
, self
.__buf 
= self
.__buf
[:idx
], self
.__buf
[idx
:] 
2034     def _haveLine(self
): 
2035         return self
.__buf
.find('\n') != -1 
2037     def _haveNumBytes(self
, n
=None): 
2038         return len(self
.__buf
) >= n
 
2040     def readline(self
, n
=None): 
2041         # Wait until there is a full line (or at least 'n' bytes) 
2042         # in the buffer or until the buffer is closed, i.e. no more 
2044         log
.info("[%s] IOBuffer.readline(n=%r)" % (self
._name
, n
)) 
2046         log
.info("[%s] IOBuffer.readline(): wait for data" % self
._name
) 
2048             if self
._closed
: break 
2049             if self
._haveLine
(): break 
2050             if n 
is not None and self
._haveNumBytes
(n
): break 
2051             self
._stateChange
.acquire() 
2052             self
._stateChange
.wait() 
2053             self
._stateChange
.release() 
2054         log
.info("[%s] IOBuffer.readline(): done waiting for data"\
 
2057         self
._mutex
.acquire() 
2058         retval 
= self
._doReadline
(n
) 
2059         self
._mutex
.release() 
2062     def readlines(self
): 
2065             line 
= self
.readline() 
2076         if not self
._closed
: 
2077             log
.info("[%s] IOBuffer.close()" % self
._name
) 
2080             self
._stateChange
.acquire() 
2081             self
._stateChange
.notifyAll()   # Notify of the close(). 
2082             self
._stateChange
.release() 
2085         log
.info("[%s] IOBuffer.flush()" % self
._name
) 
2086         #XXX Perhaps flush() should unwedged possible waiting .read() 
2087         #    and .readline() calls that are waiting for more data??? 
2090 class _InFileProxy(threading
.Thread
): 
2091     """A thread to proxy stdin.write()'s from the parent to the child.""" 
2092     def __init__(self
, fParent
, fChild
, name
=None): 
2094         "fParent" is a Python file-like object setup for writing. 
2095         "fChild" is a Win32 handle to the a child process' output pipe. 
2096         "name" can be set for debugging, it will be used in log messages. 
2098         log
.info("[%s, %s] _InFileProxy.__init__(fChild=%r, fParent=%r)", 
2099                  name
, id(self
), fChild
, fParent
) 
2100         threading
.Thread
.__init
__(self
, name
=name
) 
2101         self
.fChild 
= fChild
 
2102         self
.fParent 
= fParent
 
2105         log
.info("[%s] _InFileProxy: start" % self
.getName()) 
2107             self
._proxyFromParentToChild
() 
2109             log
.info("[%s] _InFileProxy: closing parent (%r)"\
 
2110                      % (self
.getName(), self
.fParent
)) 
2112                 self
.fParent
.close() 
2114                 pass # Ignore: IOError: [Errno 4] Interrupted system call 
2115         log
.info("[%s] _InFileProxy: done" % self
.getName()) 
2117     def _proxyFromParentToChild(self
): 
2119         # Read output from the child process, and (for now) just write 
2122             log
.info("[%s] _InFileProxy: waiting for read on parent (%r)"\
 
2123                      % (self
.getName(), self
.fParent
)) 
2124             # XXX Get hangs here (!) even with 
2125             #     self.stdin.close() in ProcessProxy' __del__() under this 
2127             #           p = ProcessProxy([...], stdin=sys.stdin) 
2128             #     The user must manually send '\n' via <Enter> or EOF 
2129             #     via <Ctrl-Z> to unlock this. How to get around that? 
2130             #     See cleanOnTermination note in _OutFileProxy.run() 
2132             #log.debug("XXX          -> start read on %r" % self.fParent) 
2134                 text 
= self
.fParent
.read(CHUNKSIZE
) 
2135             except ValueError, ex
: 
2136                 # ValueError is raised with trying to write to a closed 
2139             #log.debug("XXX          <- done read on %r" % self.fParent) 
2141                 # Empty text signifies that the pipe has been closed on 
2143                 log
.info("[%s] _InFileProxy: observed close of parent (%r)"\
 
2144                          % (self
.getName(), self
.fParent
)) 
2145                 # Signal the child so it knows to stop listening. 
2147                     logres
.info("[%s] _InFileProxy: closing child after "\
 
2148                                 "observing parent's close: %r", self
.getName(), 
2153                         pass # Ignore: IOError: [Errno 4] Interrupted system call 
2155                     # Ignore: IOError: [Errno 9] Bad file descriptor 
2156                     # XXX Do we *know* we want to do that? 
2160                 log
.info("[%s] _InFileProxy: read %d bytes from parent: %r"\
 
2161                          % (self
.getName(), len(text
), text
)) 
2163             log
.info("[%s, %s] _InFileProxy: writing %r to child (%r)", 
2164                      self
.getName(), id(self
), text
, self
.fChild
) 
2166                 self
.fChild
.write(text
) 
2167             except (OSError, IOError), ex
: 
2168                 # Ignore errors for now. For example: 
2169                 # - Get this on Win9x when writing multiple lines to "dir": 
2170                 #   OSError: [Errno 32] Broken pipe 
2171                 #XXX There *may* be errors we don't want to avoid. 
2172                 #XXX Should maybe just ignore EnvironmentError (base class). 
2173                 log
.info("[%s] _InFileProxy: error writing to child (%r), "\
 
2174                          "closing: %s" % (self
.getName(), self
.fParent
, ex
)) 
2176             log
.info("[%s] _InFileProxy: wrote %d bytes to child: %r"\
 
2177                      % (self
.getName(), len(text
), text
)) 
2180 class _OutFileProxy(threading
.Thread
): 
2181     """A thread to watch an "out" file from the spawned child process 
2182     and pass on write's to the parent. 
2184     def __init__(self
, fChild
, fParent
, toClose
=[], name
=None): 
2186         "fChild" is a Win32 handle to the a child process' output pipe. 
2187         "fParent" is a Python file-like object setup for writing. 
2188         "toClose" is a list of objects on which to call .close when this 
2189             proxy is terminating. 
2190         "name" can be set for debugging, it will be used in log messages. 
2192         log
.info("[%s] _OutFileProxy.__init__(fChild=%r, fParent=%r, "\
 
2193                  "toClose=%r)", name
, fChild
, fParent
, toClose
) 
2194         threading
.Thread
.__init
__(self
, name
=name
) 
2195         self
.fChild 
= fChild
 
2196         self
.fParent 
= fParent
 
2197         self
.toClose 
= toClose
 
2200         log
.info("[%s] _OutFileProxy: start" % self
.getName()) 
2202             self
._proxyFromChildToParent
() 
2204             logres
.info("[%s] _OutFileProxy: terminating, close child (%r)", 
2205                         self
.getName(), self
.fChild
) 
2209                 pass # Ignore: IOError: [Errno 4] Interrupted system call 
2210             log
.info("[%s] _OutFileProxy: closing parent (%r)", 
2211                      self
.getName(), self
.fParent
) 
2213                 self
.fParent
.close() 
2215                 pass # Ignore: IOError: [Errno 4] Interrupted system call 
2217                 logres
.info("[%s] _OutFileProxy: closing %r after "\
 
2218                             "closing parent", self
.getName(), self
.toClose
[0]) 
2220                     self
.toClose
[0].close() 
2222                     pass # Ignore: IOError: [Errno 4] Interrupted system call 
2224         log
.info("[%s] _OutFileProxy: done" % self
.getName()) 
2226     def _proxyFromChildToParent(self
): 
2228         # Read output from the child process, and (for now) just write 
2233                 log
.info("[%s] _OutFileProxy: waiting for read on child (%r)"\
 
2234                          % (self
.getName(), self
.fChild
)) 
2235                 text 
= self
.fChild
.read(CHUNKSIZE
) 
2237                 # Ignore: IOError: [Errno 9] Bad file descriptor 
2238                 # XXX Do we *know* we want to do that? 
2239                 log
.info("[%s] _OutFileProxy: error reading from child (%r), "\
 
2240                          "shutting down: %s", self
.getName(), self
.fChild
, ex
) 
2243                 # Empty text signifies that the pipe has been closed on 
2245                 log
.info("[%s] _OutFileProxy: observed close of child (%r)"\
 
2246                          % (self
.getName(), self
.fChild
)) 
2249             log
.info("[%s] _OutFileProxy: text(len=%d): %r", 
2250                      self
.getName(), len(text
), text
) 
2251             self
.fParent
.write(text
) 
2255 if sys
.platform
.startswith("linux"): 
2257         """Mixin class for various classes in the Process hierarchy to 
2258         work around the known LinuxThreads bug where one cannot .wait() 
2259         on a created process from a subthread of the thread that created 
2263             class ProcessXXX(_ThreadFixer, BrokenProcessXXX): 
2264                 _pclass = BrokenProcessXXX 
2267             Because we must do all real os.wait() calls on the child 
2268             process from the thread that spawned it, we use a proxy 
2269             thread whose only responsibility is just that. The proxy 
2270             thread just starts the child and then immediately wait's for 
2271             the child to terminate. On termination is stores the exit 
2272             status (for use by the main thread) and notifies any thread 
2273             waiting for this termination (possibly the main thread). The 
2274             overriden .wait() uses this stored exit status and the 
2275             termination notification to simulate the .wait(). 
2277         def __init__(self
, *args
, **kwargs
): 
2278             # Keep a reference to 'log' ensure it is around for this object's 
2281             self
.__waiter 
= None 
2282             self
.__hasTerminated 
= threading
.Condition() 
2283             self
.__terminationResult 
= None 
2284             self
.__childStarted 
= threading
.Condition() 
2285             self
._pclass
.__init
__(self
, *args
, **kwargs
) 
2287         def _forkAndExecChildOnUnix(self
, *args
, **kwargs
): 
2288             """Fork and start the child process do it in a special subthread 
2289             that will negotiate subsequent .wait()'s. 
2291             Sets self._pid as a side effect. 
2293             self
.__waiter 
= threading
.Thread( 
2294                 target
=self
.__launchAndWait
, args
=args
, kwargs
=kwargs
) 
2296             # Start subthread that will launch child and wait until it 
2298             self
.__childStarted
.acquire() 
2299             self
.__waiter
.start() 
2300             self
.__childStarted
.wait() 
2301             self
.__childStarted
.release() 
2303         def __launchAndWait(self
, *args
, **kwargs
): 
2304             """Launch the given command and wait for it to terminate. 
2306             When the process has terminated then store its exit value 
2309             logfix
.info("start child in thread %s", 
2310                         threading
.currentThread().getName()) 
2312             # Spawn the child process and notify the main thread of 
2314             self
.__childStarted
.acquire() 
2315             self
._pclass
._forkAndExecChildOnUnix
(self
, *args
, **kwargs
) 
2316             self
.__childStarted
.notifyAll() 
2317             self
.__childStarted
.release() 
2319             # Wait on the thread and store appropriate results when 
2322                 waitResult 
= self
._pclass
.wait(self
) 
2323             except ProcessError
, ex
: 
2325             self
.__hasTerminated
.acquire() 
2326             self
.__terminationResult 
= waitResult
 
2327             self
.__hasTerminated
.notifyAll() 
2328             self
.__hasTerminated
.release() 
2330             self
.__waiter 
= None # drop ref that would keep instance alive 
2332         def wait(self
, timeout
=None):  
2333             # If the process __hasTerminated then return the exit 
2334             # status. Otherwise simulate the wait as appropriate. 
2336             #   - This class is only used on linux so 'timeout' has the 
2337             #     Unix 'timeout' semantics. 
2338             self
.__hasTerminated
.acquire() 
2339             if self
.__terminationResult 
is None: 
2340                 if timeout 
== os
.WNOHANG
:   # Poll. 
2341                     self
.__hasTerminated
.wait(0) 
2342                 else:                       # Block until process finishes. 
2343                     self
.__hasTerminated
.wait() 
2344             terminationResult 
= self
.__terminationResult
 
2345             self
.__hasTerminated
.release() 
2347             if terminationResult 
is None: 
2348                 # process has not finished yet 
2349                 raise ProcessError("Wait for process timed out.", 
2351             elif isinstance(terminationResult
, Exception): 
2352                 # some error waiting for process termination 
2353                 raise terminationResult
 
2355                 # the process terminated 
2356                 return terminationResult
 
2358     _ThreadBrokenProcess 
= Process
 
2359     class Process(_ThreadFixer
, _ThreadBrokenProcess
): 
2360         _pclass 
= _ThreadBrokenProcess
 
2362     _ThreadBrokenProcessOpen 
= ProcessOpen
 
2363     class ProcessOpen(_ThreadFixer
, _ThreadBrokenProcessOpen
): 
2364         _pclass 
= _ThreadBrokenProcessOpen
 
2366     _ThreadBrokenProcessProxy 
= ProcessProxy
 
2367     class ProcessProxy(_ThreadFixer
, _ThreadBrokenProcessProxy
): 
2368         _pclass 
= _ThreadBrokenProcessProxy