Skip to content

bpo-20104: Change the file_actions parameter of os.posix_spawn(). #6725

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Doc/library/os.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3394,15 +3394,16 @@ written in Python, such as a mail server's external command delivery program.
subprocesses.


.. function:: posix_spawn(path, argv, env, file_actions=None, /, *, \
.. function:: posix_spawn(path, argv, env, *, file_actions=None, \
setpgroup=None, resetids=False, setsigmask=(), \
setsigdef=(), scheduler=None)

Wraps the :c:func:`posix_spawn` C library API for use from Python.

Most users should use :func:`subprocess.run` instead of :func:`posix_spawn`.

The *path*, *args*, and *env* arguments are similar to :func:`execve`.
The positional-only arguments *path*, *args*, and *env* are similar to
:func:`execve`.

The *file_actions* argument may be a sequence of tuples describing actions
to take on specific file descriptors in the child process between the C
Expand Down
57 changes: 28 additions & 29 deletions Lib/test/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -1499,8 +1499,7 @@ def test_returns_pid(self):
pidfile.write(str(os.getpid()))
"""
args = self.python_args('-c', script)
pid = posix.posix_spawn(args[0], args,
os.environ)
pid = posix.posix_spawn(args[0], args, os.environ)
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
with open(pidfile) as f:
self.assertEqual(f.read(), str(pid))
Expand Down Expand Up @@ -1538,7 +1537,7 @@ def test_empty_file_actions(self):
self.NOOP_PROGRAM[0],
self.NOOP_PROGRAM,
os.environ,
[]
file_actions=[]
)
self.assertEqual(os.waitpid(pid, 0), (pid, 0))

Expand Down Expand Up @@ -1691,37 +1690,38 @@ def test_multiple_file_actions(self):
]
pid = posix.posix_spawn(self.NOOP_PROGRAM[0],
self.NOOP_PROGRAM,
os.environ, file_actions)
os.environ,
file_actions=file_actions)
self.assertEqual(os.waitpid(pid, 0), (pid, 0))

def test_bad_file_actions(self):
args = self.NOOP_PROGRAM
with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args,
os.environ, [None])
posix.posix_spawn(args[0], args, os.environ,
file_actions=[None])
with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args,
os.environ, [()])
posix.posix_spawn(args[0], args, os.environ,
file_actions=[()])
with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args,
os.environ, [(None,)])
posix.posix_spawn(args[0], args, os.environ,
file_actions=[(None,)])
with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args,
os.environ, [(12345,)])
posix.posix_spawn(args[0], args, os.environ,
file_actions=[(12345,)])
with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args,
os.environ, [(os.POSIX_SPAWN_CLOSE,)])
posix.posix_spawn(args[0], args, os.environ,
file_actions=[(os.POSIX_SPAWN_CLOSE,)])
with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args,
os.environ, [(os.POSIX_SPAWN_CLOSE, 1, 2)])
posix.posix_spawn(args[0], args, os.environ,
file_actions=[(os.POSIX_SPAWN_CLOSE, 1, 2)])
with self.assertRaises(TypeError):
posix.posix_spawn(args[0], args,
os.environ, [(os.POSIX_SPAWN_CLOSE, None)])
posix.posix_spawn(args[0], args, os.environ,
file_actions=[(os.POSIX_SPAWN_CLOSE, None)])
with self.assertRaises(ValueError):
posix.posix_spawn(args[0], args,
os.environ,
[(os.POSIX_SPAWN_OPEN, 3, __file__ + '\0',
os.O_RDONLY, 0)])
posix.posix_spawn(args[0], args, os.environ,
file_actions=[(os.POSIX_SPAWN_OPEN,
3, __file__ + '\0',
os.O_RDONLY, 0)])

def test_open_file(self):
outfile = support.TESTFN
Expand All @@ -1736,8 +1736,8 @@ def test_open_file(self):
stat.S_IRUSR | stat.S_IWUSR),
]
args = self.python_args('-c', script)
pid = posix.posix_spawn(args[0], args,
os.environ, file_actions)
pid = posix.posix_spawn(args[0], args, os.environ,
file_actions=file_actions)
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
with open(outfile) as f:
self.assertEqual(f.read(), 'hello')
Expand All @@ -1754,9 +1754,8 @@ def test_close_file(self):
closefile.write('is closed %d' % e.errno)
"""
args = self.python_args('-c', script)
pid = posix.posix_spawn(args[0], args,
os.environ,
[(os.POSIX_SPAWN_CLOSE, 0),])
pid = posix.posix_spawn(args[0], args, os.environ,
file_actions=[(os.POSIX_SPAWN_CLOSE, 0),])
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
with open(closefile) as f:
self.assertEqual(f.read(), 'is closed %d' % errno.EBADF)
Expand All @@ -1773,8 +1772,8 @@ def test_dup2(self):
(os.POSIX_SPAWN_DUP2, childfile.fileno(), 1),
]
args = self.python_args('-c', script)
pid = posix.posix_spawn(args[0], args,
os.environ, file_actions)
pid = posix.posix_spawn(args[0], args, os.environ,
file_actions=file_actions)
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
with open(dupfile) as f:
self.assertEqual(f.read(), 'hello')
Expand Down
10 changes: 5 additions & 5 deletions Modules/clinic/posixmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -5405,10 +5405,10 @@ os.posix_spawn
Tuple or list of strings.
env: object
Dictionary of strings mapping to strings.
file_actions: object = None
A sequence of file action tuples.
/
*
file_actions: object(c_default='NULL') = ()
A sequence of file action tuples.
setpgroup: object = NULL
The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
resetids: bool(accept={int}) = False
Expand All @@ -5419,6 +5419,7 @@ os.posix_spawn
The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
scheduler: object = NULL
A tuple with the scheduler policy (optional) and parameters.

Execute the program specified by path in a new process.
[clinic start generated code]*/

Expand All @@ -5427,7 +5428,7 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
PyObject *env, PyObject *file_actions,
PyObject *setpgroup, int resetids, PyObject *setsigmask,
PyObject *setsigdef, PyObject *scheduler)
/*[clinic end generated code: output=45dfa4c515d09f2c input=2d7a7578430a90f0]*/
/*[clinic end generated code: output=45dfa4c515d09f2c input=2891c2f1d457e39b]*/
{
EXECV_CHAR **argvlist = NULL;
EXECV_CHAR **envlist = NULL;
Expand Down Expand Up @@ -5477,7 +5478,7 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
goto exit;
}

if (file_actions != Py_None) {
if (file_actions != NULL) {
/* There is a bug in old versions of glibc that makes some of the
* helper functions for manipulating file actions not copy the provided
* buffers. The problem is that posix_spawn_file_actions_addopen does not
Expand Down