[pypy-svn] r40862 - in pypy/dist/pypy/module/posix: . test
arigo at codespeak.net
arigo at codespeak.net
Tue Mar 20 20:24:09 CET 2007
Author: arigo
Date: Tue Mar 20 20:24:06 2007
New Revision: 40862
Modified:
pypy/dist/pypy/module/posix/__init__.py
pypy/dist/pypy/module/posix/app_posix.py
pypy/dist/pypy/module/posix/test/test_posix_libfile.py
Log:
An app-level version of posix.popen(). It returns a subclass of 'file'
with its close() method overridden to wait on the child process.
Modified: pypy/dist/pypy/module/posix/__init__.py
==============================================================================
--- pypy/dist/pypy/module/posix/__init__.py (original)
+++ pypy/dist/pypy/module/posix/__init__.py Tue Mar 20 20:24:06 2007
@@ -70,6 +70,7 @@
interpleveldefs['readlink'] = 'interp_posix.readlink'
if hasattr(os, 'fork'):
interpleveldefs['fork'] = 'interp_posix.fork'
+ appleveldefs['popen'] = 'app_posix.popen'
if hasattr(os, 'waitpid'):
interpleveldefs['waitpid'] = 'interp_posix.waitpid'
if hasattr(os, 'execv'):
Modified: pypy/dist/pypy/module/posix/app_posix.py
==============================================================================
--- pypy/dist/pypy/module/posix/app_posix.py (original)
+++ pypy/dist/pypy/module/posix/app_posix.py Tue Mar 20 20:24:06 2007
@@ -1,5 +1,6 @@
# NOT_RPYTHON
+import os
from _structseq import structseqtype, structseqfield
error = OSError
@@ -28,3 +29,65 @@
return file.fdopen(fd, mode, buffering)
+
+# __________ only if we have os.fork() __________
+
+class popenfile(file):
+ _childpid = None
+
+ def close(self):
+ file.close(self)
+ pid = self._childpid
+ if pid is not None:
+ self._childpid = None
+ os.waitpid(pid, 0)
+ __del__ = close # as in CPython, __del__ may call os.waitpid()
+
+def try_close(fd):
+ try:
+ os.close(fd)
+ except OSError:
+ pass
+
+def popen(command, mode='r', bufsize=-1):
+ """popen(command [, mode='r' [, bufsize]]) -> pipe
+
+ Open a pipe to/from a command returning a file object."""
+
+ from popen2 import MAXFD
+
+ if not mode.startswith('r') and not mode.startswith('w'):
+ raise ValueError("invalid mode %r" % (mode,))
+ read_end, write_end = os.pipe()
+ try:
+ childpid = os.fork()
+ if childpid == 0:
+ # in the child
+ try:
+ if mode.startswith('r'):
+ os.dup2(write_end, 1)
+ os.close(read_end)
+ else:
+ os.dup2(read_end, 0)
+ os.close(write_end)
+ for i in range(3, MAXFD):
+ try_close(i)
+ cmd = ['/bin/sh', '-c', command]
+ os.execvp(cmd[0], cmd)
+ finally:
+ os._exit(1)
+
+ if mode.startswith('r'):
+ os.close(write_end)
+ fd = read_end
+ else:
+ os.close(read_end)
+ fd = write_end
+ g = popenfile.fdopen(fd, mode, bufsize)
+ g._childpid = childpid
+ return g
+
+ except Exception, e:
+ try_close(write_end)
+ try_close(read_end)
+ raise Exception, e # bare 'raise' does not work here :-(
Modified: pypy/dist/pypy/module/posix/test/test_posix_libfile.py
==============================================================================
--- pypy/dist/pypy/module/posix/test/test_posix_libfile.py (original)
+++ pypy/dist/pypy/module/posix/test/test_posix_libfile.py Tue Mar 20 20:24:06 2007
@@ -23,3 +23,30 @@
f = posix.fdopen(fd, "r")
result = f.read()
assert result == "this is a test"
+
+ def test_popen(self):
+ import sys
+ if sys.platform.startswith('win'):
+ skip("unix specific")
+ path2 = self.path + '2'
+ posix = self.posix
+
+ f = posix.popen("echo hello")
+ data = f.read()
+ f.close()
+ assert data == 'hello\n'
+
+ f = posix.popen("cat > '%s'" % (path2,), 'w')
+ f.write('123\n')
+ f.close()
+ f = open(path2, 'r')
+ data = f.read()
+ f.close()
+ assert data == '123\n'
+
+ import time
+ start_time = time.time()
+ f = posix.popen("sleep 2")
+ f.close() # should wait here
+ end_time = time.time()
+ assert end_time - start_time >= 1.9
More information about the Pypy-commit
mailing list