@@ -177,22 +177,6 @@ def test_fexecve(self):
177177 os .close (fp )
178178
179179
180- @unittest .skipUnless (hasattr (os , 'posix_spawn' ), "test needs os.posix_spawn" )
181- def test_posix_spawn (self ):
182- pid = posix .posix_spawn (sys .executable , [sys .executable , "-c" , "pass" ], os .environ ,[])
183- self .assertEqual (os .waitpid (pid ,0 ),(pid ,0 ))
184-
185-
186- @unittest .skipUnless (hasattr (os , 'posix_spawn' ), "test needs os.posix_spawn" )
187- def test_posix_spawn_file_actions (self ):
188- file_actions = []
189- file_actions .append ((0 ,3 ,os .path .realpath (__file__ ),0 ,0 ))
190- file_actions .append ((os .POSIX_SPAWN_CLOSE ,2 ))
191- file_actions .append ((os .POSIX_SPAWN_DUP2 ,1 ,4 ))
192- pid = posix .posix_spawn (sys .executable , [sys .executable , "-c" , "pass" ], os .environ , file_actions )
193- self .assertEqual (os .waitpid (pid ,0 ),(pid ,0 ))
194-
195-
196180 @unittest .skipUnless (hasattr (posix , 'waitid' ), "test needs posix.waitid()" )
197181 @unittest .skipUnless (hasattr (os , 'fork' ), "test needs os.fork()" )
198182 def test_waitid (self ):
@@ -1437,9 +1421,168 @@ def test_setgroups(self):
14371421 posix .setgroups (groups )
14381422 self .assertListEqual (groups , posix .getgroups ())
14391423
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+ {'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+
14401583def test_main ():
14411584 try :
1442- support .run_unittest (PosixTester , PosixGroupsTester )
1585+ support .run_unittest (PosixTester , PosixGroupsTester , TestPosixSpawn )
14431586 finally :
14441587 support .reap_children ()
14451588
0 commit comments