Skip to content

Commit 8e633a4

Browse files
pablogsalgpshead
authored andcommitted
bpo-20104: Remove posix_spawn from 3.7 (GH-6794)
Remove os.posix_spawn, the API isn't complete and we're still figuring out how it should look. wait for 3.8.
1 parent c6348cf commit 8e633a4

File tree

7 files changed

+5
-482
lines changed

7 files changed

+5
-482
lines changed

Doc/library/os.rst

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3365,47 +3365,6 @@ written in Python, such as a mail server's external command delivery program.
33653365
subprocesses.
33663366

33673367

3368-
.. function:: posix_spawn(path, argv, env, file_actions=None)
3369-
3370-
Wraps the :c:func:`posix_spawn` C library API for use from Python.
3371-
3372-
Most users should use :func:`subprocess.run` instead of :func:`posix_spawn`.
3373-
3374-
The *path*, *args*, and *env* arguments are similar to :func:`execve`.
3375-
3376-
The *file_actions* argument may be a sequence of tuples describing actions
3377-
to take on specific file descriptors in the child process between the C
3378-
library implementation's :c:func:`fork` and :c:func:`exec` steps.
3379-
The first item in each tuple must be one of the three type indicator
3380-
listed below describing the remaining tuple elements:
3381-
3382-
.. data:: POSIX_SPAWN_OPEN
3383-
3384-
(``os.POSIX_SPAWN_OPEN``, *fd*, *path*, *flags*, *mode*)
3385-
3386-
Performs ``os.dup2(os.open(path, flags, mode), fd)``.
3387-
3388-
.. data:: POSIX_SPAWN_CLOSE
3389-
3390-
(``os.POSIX_SPAWN_CLOSE``, *fd*)
3391-
3392-
Performs ``os.close(fd)``.
3393-
3394-
.. data:: POSIX_SPAWN_DUP2
3395-
3396-
(``os.POSIX_SPAWN_DUP2``, *fd*, *new_fd*)
3397-
3398-
Performs ``os.dup2(fd, new_fd)``.
3399-
3400-
These tuples correspond to the C library
3401-
:c:func:`posix_spawn_file_actions_addopen`,
3402-
:c:func:`posix_spawn_file_actions_addclose`, and
3403-
:c:func:`posix_spawn_file_actions_adddup2` API calls used to prepare
3404-
for the :c:func:`posix_spawn` call itself.
3405-
3406-
.. versionadded:: 3.7
3407-
3408-
34093368
.. function:: register_at_fork(*, before=None, after_in_parent=None, \
34103369
after_in_child=None)
34113370

Doc/whatsnew/3.7.rst

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -616,10 +616,6 @@ Exposed the system calls *preadv*, *preadv2*, *pwritev* and *pwritev2* through
616616
the new functions :func:`~os.preadv` and :func:`~os.pwritev`. (Contributed by
617617
Pablo Galindo in :issue:`31368`.)
618618

619-
Exposed the system call *posix_spawn* through the new function
620-
:func:`~os.posix_spawn`. (Contributed by Pablo Galindo, Serhiy Storchaka and
621-
Gregory P. Smith in :issue:`20104`.)
622-
623619
pdb
624620
---
625621

Lib/test/test_posix.py

Lines changed: 1 addition & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,168 +1421,9 @@ def test_setgroups(self):
14211421
posix.setgroups(groups)
14221422
self.assertListEqual(groups, posix.getgroups())
14231423

1424-
1425-
@unittest.skipUnless(hasattr(os, 'posix_spawn'), "test needs os.posix_spawn")
1426-
class TestPosixSpawn(unittest.TestCase):
1427-
def test_returns_pid(self):
1428-
pidfile = support.TESTFN
1429-
self.addCleanup(support.unlink, pidfile)
1430-
script = f"""if 1:
1431-
import os
1432-
with open({pidfile!r}, "w") as pidfile:
1433-
pidfile.write(str(os.getpid()))
1434-
"""
1435-
pid = posix.posix_spawn(sys.executable,
1436-
[sys.executable, '-c', script],
1437-
os.environ)
1438-
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
1439-
with open(pidfile) as f:
1440-
self.assertEqual(f.read(), str(pid))
1441-
1442-
def test_no_such_executable(self):
1443-
no_such_executable = 'no_such_executable'
1444-
try:
1445-
pid = posix.posix_spawn(no_such_executable,
1446-
[no_such_executable],
1447-
os.environ)
1448-
except FileNotFoundError as exc:
1449-
self.assertEqual(exc.filename, no_such_executable)
1450-
else:
1451-
pid2, status = os.waitpid(pid, 0)
1452-
self.assertEqual(pid2, pid)
1453-
self.assertNotEqual(status, 0)
1454-
1455-
def test_specify_environment(self):
1456-
envfile = support.TESTFN
1457-
self.addCleanup(support.unlink, envfile)
1458-
script = f"""if 1:
1459-
import os
1460-
with open({envfile!r}, "w") as envfile:
1461-
envfile.write(os.environ['foo'])
1462-
"""
1463-
pid = posix.posix_spawn(sys.executable,
1464-
[sys.executable, '-c', script],
1465-
{**os.environ, 'foo': 'bar'})
1466-
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
1467-
with open(envfile) as f:
1468-
self.assertEqual(f.read(), 'bar')
1469-
1470-
def test_empty_file_actions(self):
1471-
pid = posix.posix_spawn(
1472-
sys.executable,
1473-
[sys.executable, '-c', 'pass'],
1474-
os.environ,
1475-
[]
1476-
)
1477-
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
1478-
1479-
def test_multiple_file_actions(self):
1480-
file_actions = [
1481-
(os.POSIX_SPAWN_OPEN, 3, os.path.realpath(__file__), os.O_RDONLY, 0),
1482-
(os.POSIX_SPAWN_CLOSE, 0),
1483-
(os.POSIX_SPAWN_DUP2, 1, 4),
1484-
]
1485-
pid = posix.posix_spawn(sys.executable,
1486-
[sys.executable, "-c", "pass"],
1487-
os.environ, file_actions)
1488-
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
1489-
1490-
def test_bad_file_actions(self):
1491-
with self.assertRaises(TypeError):
1492-
posix.posix_spawn(sys.executable,
1493-
[sys.executable, "-c", "pass"],
1494-
os.environ, [None])
1495-
with self.assertRaises(TypeError):
1496-
posix.posix_spawn(sys.executable,
1497-
[sys.executable, "-c", "pass"],
1498-
os.environ, [()])
1499-
with self.assertRaises(TypeError):
1500-
posix.posix_spawn(sys.executable,
1501-
[sys.executable, "-c", "pass"],
1502-
os.environ, [(None,)])
1503-
with self.assertRaises(TypeError):
1504-
posix.posix_spawn(sys.executable,
1505-
[sys.executable, "-c", "pass"],
1506-
os.environ, [(12345,)])
1507-
with self.assertRaises(TypeError):
1508-
posix.posix_spawn(sys.executable,
1509-
[sys.executable, "-c", "pass"],
1510-
os.environ, [(os.POSIX_SPAWN_CLOSE,)])
1511-
with self.assertRaises(TypeError):
1512-
posix.posix_spawn(sys.executable,
1513-
[sys.executable, "-c", "pass"],
1514-
os.environ, [(os.POSIX_SPAWN_CLOSE, 1, 2)])
1515-
with self.assertRaises(TypeError):
1516-
posix.posix_spawn(sys.executable,
1517-
[sys.executable, "-c", "pass"],
1518-
os.environ, [(os.POSIX_SPAWN_CLOSE, None)])
1519-
with self.assertRaises(ValueError):
1520-
posix.posix_spawn(sys.executable,
1521-
[sys.executable, "-c", "pass"],
1522-
os.environ,
1523-
[(os.POSIX_SPAWN_OPEN, 3, __file__ + '\0',
1524-
os.O_RDONLY, 0)])
1525-
1526-
def test_open_file(self):
1527-
outfile = support.TESTFN
1528-
self.addCleanup(support.unlink, outfile)
1529-
script = """if 1:
1530-
import sys
1531-
sys.stdout.write("hello")
1532-
"""
1533-
file_actions = [
1534-
(os.POSIX_SPAWN_OPEN, 1, outfile,
1535-
os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
1536-
stat.S_IRUSR | stat.S_IWUSR),
1537-
]
1538-
pid = posix.posix_spawn(sys.executable,
1539-
[sys.executable, '-c', script],
1540-
os.environ, file_actions)
1541-
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
1542-
with open(outfile) as f:
1543-
self.assertEqual(f.read(), 'hello')
1544-
1545-
def test_close_file(self):
1546-
closefile = support.TESTFN
1547-
self.addCleanup(support.unlink, closefile)
1548-
script = f"""if 1:
1549-
import os
1550-
try:
1551-
os.fstat(0)
1552-
except OSError as e:
1553-
with open({closefile!r}, 'w') as closefile:
1554-
closefile.write('is closed %d' % e.errno)
1555-
"""
1556-
pid = posix.posix_spawn(sys.executable,
1557-
[sys.executable, '-c', script],
1558-
os.environ,
1559-
[(os.POSIX_SPAWN_CLOSE, 0),])
1560-
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
1561-
with open(closefile) as f:
1562-
self.assertEqual(f.read(), 'is closed %d' % errno.EBADF)
1563-
1564-
def test_dup2(self):
1565-
dupfile = support.TESTFN
1566-
self.addCleanup(support.unlink, dupfile)
1567-
script = """if 1:
1568-
import sys
1569-
sys.stdout.write("hello")
1570-
"""
1571-
with open(dupfile, "wb") as childfile:
1572-
file_actions = [
1573-
(os.POSIX_SPAWN_DUP2, childfile.fileno(), 1),
1574-
]
1575-
pid = posix.posix_spawn(sys.executable,
1576-
[sys.executable, '-c', script],
1577-
os.environ, file_actions)
1578-
self.assertEqual(os.waitpid(pid, 0), (pid, 0))
1579-
with open(dupfile) as f:
1580-
self.assertEqual(f.read(), 'hello')
1581-
1582-
15831424
def test_main():
15841425
try:
1585-
support.run_unittest(PosixTester, PosixGroupsTester, TestPosixSpawn)
1426+
support.run_unittest(PosixTester, PosixGroupsTester)
15861427
finally:
15871428
support.reap_children()
15881429

Misc/NEWS.d/3.7.0b1.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ Remove the STORE_ANNOTATION bytecode.
142142
.. section: Core and Builtins
143143
144144
Expose posix_spawn as a low level API in the os module.
145+
(removed before 3.7.0rc1)
145146

146147
..
147148
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The new `os.posix_spawn` added in 3.7.0b1 was removed as we are still
2+
working on what the API should look like. Expect this in 3.8 instead.

Modules/clinic/posixmodule.c.h

Lines changed: 1 addition & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,54 +1727,6 @@ os_execve(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *k
17271727

17281728
#endif /* defined(HAVE_EXECV) */
17291729

1730-
#if defined(HAVE_POSIX_SPAWN)
1731-
1732-
PyDoc_STRVAR(os_posix_spawn__doc__,
1733-
"posix_spawn($module, path, argv, env, file_actions=None, /)\n"
1734-
"--\n"
1735-
"\n"
1736-
"Execute the program specified by path in a new process.\n"
1737-
"\n"
1738-
" path\n"
1739-
" Path of executable file.\n"
1740-
" argv\n"
1741-
" Tuple or list of strings.\n"
1742-
" env\n"
1743-
" Dictionary of strings mapping to strings.\n"
1744-
" file_actions\n"
1745-
" A sequence of file action tuples.");
1746-
1747-
#define OS_POSIX_SPAWN_METHODDEF \
1748-
{"posix_spawn", (PyCFunction)os_posix_spawn, METH_FASTCALL, os_posix_spawn__doc__},
1749-
1750-
static PyObject *
1751-
os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
1752-
PyObject *env, PyObject *file_actions);
1753-
1754-
static PyObject *
1755-
os_posix_spawn(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
1756-
{
1757-
PyObject *return_value = NULL;
1758-
path_t path = PATH_T_INITIALIZE("posix_spawn", "path", 0, 0);
1759-
PyObject *argv;
1760-
PyObject *env;
1761-
PyObject *file_actions = Py_None;
1762-
1763-
if (!_PyArg_ParseStack(args, nargs, "O&OO|O:posix_spawn",
1764-
path_converter, &path, &argv, &env, &file_actions)) {
1765-
goto exit;
1766-
}
1767-
return_value = os_posix_spawn_impl(module, &path, argv, env, file_actions);
1768-
1769-
exit:
1770-
/* Cleanup for path */
1771-
path_cleanup(&path);
1772-
1773-
return return_value;
1774-
}
1775-
1776-
#endif /* defined(HAVE_POSIX_SPAWN) */
1777-
17781730
#if (defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV))
17791731

17801732
PyDoc_STRVAR(os_spawnv__doc__,
@@ -6194,10 +6146,6 @@ os_getrandom(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
61946146
#define OS_EXECVE_METHODDEF
61956147
#endif /* !defined(OS_EXECVE_METHODDEF) */
61966148

6197-
#ifndef OS_POSIX_SPAWN_METHODDEF
6198-
#define OS_POSIX_SPAWN_METHODDEF
6199-
#endif /* !defined(OS_POSIX_SPAWN_METHODDEF) */
6200-
62016149
#ifndef OS_SPAWNV_METHODDEF
62026150
#define OS_SPAWNV_METHODDEF
62036151
#endif /* !defined(OS_SPAWNV_METHODDEF) */
@@ -6589,4 +6537,4 @@ os_getrandom(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
65896537
#ifndef OS_GETRANDOM_METHODDEF
65906538
#define OS_GETRANDOM_METHODDEF
65916539
#endif /* !defined(OS_GETRANDOM_METHODDEF) */
6592-
/*[clinic end generated code: output=8d3d9dddf254c3c2 input=a9049054013a1b77]*/
6540+
/*[clinic end generated code: output=c966c821d557b7c0 input=a9049054013a1b77]*/

0 commit comments

Comments
 (0)