@@ -1489,10 +1489,10 @@ def test_setgroups(self):
1489
1489
self .assertListEqual (groups , posix .getgroups ())
1490
1490
1491
1491
1492
- @unittest .skipUnless (hasattr (os , 'posix_spawn' ), "test needs os.posix_spawn" )
1493
- class TestPosixSpawn (unittest .TestCase ):
1494
- # Program which does nothing and exit with status 0 (success)
1492
+ class _PosixSpawnMixin :
1493
+ # Program which does nothing and exits with status 0 (success)
1495
1494
NOOP_PROGRAM = (sys .executable , '-I' , '-S' , '-c' , 'pass' )
1495
+ spawn_func = None
1496
1496
1497
1497
def python_args (self , * args ):
1498
1498
# Disable site module to avoid side effects. For example,
@@ -1511,17 +1511,17 @@ def test_returns_pid(self):
1511
1511
pidfile.write(str(os.getpid()))
1512
1512
"""
1513
1513
args = self .python_args ('-c' , script )
1514
- pid = posix . posix_spawn (args [0 ], args , os .environ )
1514
+ pid = self . spawn_func (args [0 ], args , os .environ )
1515
1515
self .assertEqual (os .waitpid (pid , 0 ), (pid , 0 ))
1516
1516
with open (pidfile ) as f :
1517
1517
self .assertEqual (f .read (), str (pid ))
1518
1518
1519
1519
def test_no_such_executable (self ):
1520
1520
no_such_executable = 'no_such_executable'
1521
1521
try :
1522
- pid = posix . posix_spawn (no_such_executable ,
1523
- [no_such_executable ],
1524
- os .environ )
1522
+ pid = self . spawn_func (no_such_executable ,
1523
+ [no_such_executable ],
1524
+ os .environ )
1525
1525
except FileNotFoundError as exc :
1526
1526
self .assertEqual (exc .filename , no_such_executable )
1527
1527
else :
@@ -1538,14 +1538,14 @@ def test_specify_environment(self):
1538
1538
envfile.write(os.environ['foo'])
1539
1539
"""
1540
1540
args = self .python_args ('-c' , script )
1541
- pid = posix . posix_spawn (args [0 ], args ,
1542
- {** os .environ , 'foo' : 'bar' })
1541
+ pid = self . spawn_func (args [0 ], args ,
1542
+ {** os .environ , 'foo' : 'bar' })
1543
1543
self .assertEqual (os .waitpid (pid , 0 ), (pid , 0 ))
1544
1544
with open (envfile ) as f :
1545
1545
self .assertEqual (f .read (), 'bar' )
1546
1546
1547
1547
def test_empty_file_actions (self ):
1548
- pid = posix . posix_spawn (
1548
+ pid = self . spawn_func (
1549
1549
self .NOOP_PROGRAM [0 ],
1550
1550
self .NOOP_PROGRAM ,
1551
1551
os .environ ,
@@ -1554,7 +1554,7 @@ def test_empty_file_actions(self):
1554
1554
self .assertEqual (os .waitpid (pid , 0 ), (pid , 0 ))
1555
1555
1556
1556
def test_resetids_explicit_default (self ):
1557
- pid = posix . posix_spawn (
1557
+ pid = self . spawn_func (
1558
1558
sys .executable ,
1559
1559
[sys .executable , '-c' , 'pass' ],
1560
1560
os .environ ,
@@ -1563,7 +1563,7 @@ def test_resetids_explicit_default(self):
1563
1563
self .assertEqual (os .waitpid (pid , 0 ), (pid , 0 ))
1564
1564
1565
1565
def test_resetids (self ):
1566
- pid = posix . posix_spawn (
1566
+ pid = self . spawn_func (
1567
1567
sys .executable ,
1568
1568
[sys .executable , '-c' , 'pass' ],
1569
1569
os .environ ,
@@ -1573,12 +1573,12 @@ def test_resetids(self):
1573
1573
1574
1574
def test_resetids_wrong_type (self ):
1575
1575
with self .assertRaises (TypeError ):
1576
- posix . posix_spawn (sys .executable ,
1577
- [sys .executable , "-c" , "pass" ],
1578
- os .environ , resetids = None )
1576
+ self . spawn_func (sys .executable ,
1577
+ [sys .executable , "-c" , "pass" ],
1578
+ os .environ , resetids = None )
1579
1579
1580
1580
def test_setpgroup (self ):
1581
- pid = posix . posix_spawn (
1581
+ pid = self . spawn_func (
1582
1582
sys .executable ,
1583
1583
[sys .executable , '-c' , 'pass' ],
1584
1584
os .environ ,
@@ -1588,9 +1588,9 @@ def test_setpgroup(self):
1588
1588
1589
1589
def test_setpgroup_wrong_type (self ):
1590
1590
with self .assertRaises (TypeError ):
1591
- posix . posix_spawn (sys .executable ,
1592
- [sys .executable , "-c" , "pass" ],
1593
- os .environ , setpgroup = "023" )
1591
+ self . spawn_func (sys .executable ,
1592
+ [sys .executable , "-c" , "pass" ],
1593
+ os .environ , setpgroup = "023" )
1594
1594
1595
1595
@unittest .skipUnless (hasattr (signal , 'pthread_sigmask' ),
1596
1596
'need signal.pthread_sigmask()' )
@@ -1599,7 +1599,7 @@ def test_setsigmask(self):
1599
1599
import signal
1600
1600
signal.raise_signal(signal.SIGUSR1)""" )
1601
1601
1602
- pid = posix . posix_spawn (
1602
+ pid = self . spawn_func (
1603
1603
sys .executable ,
1604
1604
[sys .executable , '-c' , code ],
1605
1605
os .environ ,
@@ -1609,18 +1609,18 @@ def test_setsigmask(self):
1609
1609
1610
1610
def test_setsigmask_wrong_type (self ):
1611
1611
with self .assertRaises (TypeError ):
1612
- posix . posix_spawn (sys .executable ,
1613
- [sys .executable , "-c" , "pass" ],
1614
- os .environ , setsigmask = 34 )
1612
+ self . spawn_func (sys .executable ,
1613
+ [sys .executable , "-c" , "pass" ],
1614
+ os .environ , setsigmask = 34 )
1615
1615
with self .assertRaises (TypeError ):
1616
- posix . posix_spawn (sys .executable ,
1617
- [sys .executable , "-c" , "pass" ],
1618
- os .environ , setsigmask = ["j" ])
1616
+ self . spawn_func (sys .executable ,
1617
+ [sys .executable , "-c" , "pass" ],
1618
+ os .environ , setsigmask = ["j" ])
1619
1619
with self .assertRaises (ValueError ):
1620
- posix . posix_spawn (sys .executable ,
1621
- [sys .executable , "-c" , "pass" ],
1622
- os .environ , setsigmask = [signal .NSIG ,
1623
- signal .NSIG + 1 ])
1620
+ self . spawn_func (sys .executable ,
1621
+ [sys .executable , "-c" , "pass" ],
1622
+ os .environ , setsigmask = [signal .NSIG ,
1623
+ signal .NSIG + 1 ])
1624
1624
1625
1625
@unittest .skipUnless (hasattr (signal , 'pthread_sigmask' ),
1626
1626
'need signal.pthread_sigmask()' )
@@ -1630,7 +1630,7 @@ def test_setsigdef(self):
1630
1630
import signal
1631
1631
signal.raise_signal(signal.SIGUSR1)""" )
1632
1632
try :
1633
- pid = posix . posix_spawn (
1633
+ pid = self . spawn_func (
1634
1634
sys .executable ,
1635
1635
[sys .executable , '-c' , code ],
1636
1636
os .environ ,
@@ -1646,17 +1646,17 @@ def test_setsigdef(self):
1646
1646
1647
1647
def test_setsigdef_wrong_type (self ):
1648
1648
with self .assertRaises (TypeError ):
1649
- posix . posix_spawn (sys .executable ,
1650
- [sys .executable , "-c" , "pass" ],
1651
- os .environ , setsigdef = 34 )
1649
+ self . spawn_func (sys .executable ,
1650
+ [sys .executable , "-c" , "pass" ],
1651
+ os .environ , setsigdef = 34 )
1652
1652
with self .assertRaises (TypeError ):
1653
- posix . posix_spawn (sys .executable ,
1654
- [sys .executable , "-c" , "pass" ],
1655
- os .environ , setsigdef = ["j" ])
1653
+ self . spawn_func (sys .executable ,
1654
+ [sys .executable , "-c" , "pass" ],
1655
+ os .environ , setsigdef = ["j" ])
1656
1656
with self .assertRaises (ValueError ):
1657
- posix . posix_spawn (sys .executable ,
1658
- [sys .executable , "-c" , "pass" ],
1659
- os .environ , setsigdef = [signal .NSIG , signal .NSIG + 1 ])
1657
+ self . spawn_func (sys .executable ,
1658
+ [sys .executable , "-c" , "pass" ],
1659
+ os .environ , setsigdef = [signal .NSIG , signal .NSIG + 1 ])
1660
1660
1661
1661
@requires_sched
1662
1662
@unittest .skipIf (sys .platform .startswith (('freebsd' , 'netbsd' )),
@@ -1670,7 +1670,7 @@ def test_setscheduler_only_param(self):
1670
1670
sys.exit(101)
1671
1671
if os.sched_getparam(0).sched_priority != { priority } :
1672
1672
sys.exit(102)""" )
1673
- pid = posix . posix_spawn (
1673
+ pid = self . spawn_func (
1674
1674
sys .executable ,
1675
1675
[sys .executable , '-c' , code ],
1676
1676
os .environ ,
@@ -1690,7 +1690,7 @@ def test_setscheduler_with_policy(self):
1690
1690
sys.exit(101)
1691
1691
if os.sched_getparam(0).sched_priority != { priority } :
1692
1692
sys.exit(102)""" )
1693
- pid = posix . posix_spawn (
1693
+ pid = self . spawn_func (
1694
1694
sys .executable ,
1695
1695
[sys .executable , '-c' , code ],
1696
1696
os .environ ,
@@ -1704,40 +1704,40 @@ def test_multiple_file_actions(self):
1704
1704
(os .POSIX_SPAWN_CLOSE , 0 ),
1705
1705
(os .POSIX_SPAWN_DUP2 , 1 , 4 ),
1706
1706
]
1707
- pid = posix . posix_spawn (self .NOOP_PROGRAM [0 ],
1708
- self .NOOP_PROGRAM ,
1709
- os .environ ,
1710
- file_actions = file_actions )
1707
+ pid = self . spawn_func (self .NOOP_PROGRAM [0 ],
1708
+ self .NOOP_PROGRAM ,
1709
+ os .environ ,
1710
+ file_actions = file_actions )
1711
1711
self .assertEqual (os .waitpid (pid , 0 ), (pid , 0 ))
1712
1712
1713
1713
def test_bad_file_actions (self ):
1714
1714
args = self .NOOP_PROGRAM
1715
1715
with self .assertRaises (TypeError ):
1716
- posix . posix_spawn (args [0 ], args , os .environ ,
1717
- file_actions = [None ])
1716
+ self . spawn_func (args [0 ], args , os .environ ,
1717
+ file_actions = [None ])
1718
1718
with self .assertRaises (TypeError ):
1719
- posix . posix_spawn (args [0 ], args , os .environ ,
1720
- file_actions = [()])
1719
+ self . spawn_func (args [0 ], args , os .environ ,
1720
+ file_actions = [()])
1721
1721
with self .assertRaises (TypeError ):
1722
- posix . posix_spawn (args [0 ], args , os .environ ,
1723
- file_actions = [(None ,)])
1722
+ self . spawn_func (args [0 ], args , os .environ ,
1723
+ file_actions = [(None ,)])
1724
1724
with self .assertRaises (TypeError ):
1725
- posix . posix_spawn (args [0 ], args , os .environ ,
1726
- file_actions = [(12345 ,)])
1725
+ self . spawn_func (args [0 ], args , os .environ ,
1726
+ file_actions = [(12345 ,)])
1727
1727
with self .assertRaises (TypeError ):
1728
- posix . posix_spawn (args [0 ], args , os .environ ,
1729
- file_actions = [(os .POSIX_SPAWN_CLOSE ,)])
1728
+ self . spawn_func (args [0 ], args , os .environ ,
1729
+ file_actions = [(os .POSIX_SPAWN_CLOSE ,)])
1730
1730
with self .assertRaises (TypeError ):
1731
- posix . posix_spawn (args [0 ], args , os .environ ,
1732
- file_actions = [(os .POSIX_SPAWN_CLOSE , 1 , 2 )])
1731
+ self . spawn_func (args [0 ], args , os .environ ,
1732
+ file_actions = [(os .POSIX_SPAWN_CLOSE , 1 , 2 )])
1733
1733
with self .assertRaises (TypeError ):
1734
- posix . posix_spawn (args [0 ], args , os .environ ,
1735
- file_actions = [(os .POSIX_SPAWN_CLOSE , None )])
1734
+ self . spawn_func (args [0 ], args , os .environ ,
1735
+ file_actions = [(os .POSIX_SPAWN_CLOSE , None )])
1736
1736
with self .assertRaises (ValueError ):
1737
- posix . posix_spawn (args [0 ], args , os .environ ,
1738
- file_actions = [(os .POSIX_SPAWN_OPEN ,
1739
- 3 , __file__ + '\0 ' ,
1740
- os .O_RDONLY , 0 )])
1737
+ self . spawn_func (args [0 ], args , os .environ ,
1738
+ file_actions = [(os .POSIX_SPAWN_OPEN ,
1739
+ 3 , __file__ + '\0 ' ,
1740
+ os .O_RDONLY , 0 )])
1741
1741
1742
1742
def test_open_file (self ):
1743
1743
outfile = support .TESTFN
@@ -1752,8 +1752,8 @@ def test_open_file(self):
1752
1752
stat .S_IRUSR | stat .S_IWUSR ),
1753
1753
]
1754
1754
args = self .python_args ('-c' , script )
1755
- pid = posix . posix_spawn (args [0 ], args , os .environ ,
1756
- file_actions = file_actions )
1755
+ pid = self . spawn_func (args [0 ], args , os .environ ,
1756
+ file_actions = file_actions )
1757
1757
self .assertEqual (os .waitpid (pid , 0 ), (pid , 0 ))
1758
1758
with open (outfile ) as f :
1759
1759
self .assertEqual (f .read (), 'hello' )
@@ -1770,8 +1770,8 @@ def test_close_file(self):
1770
1770
closefile.write('is closed %d' % e.errno)
1771
1771
"""
1772
1772
args = self .python_args ('-c' , script )
1773
- pid = posix . posix_spawn (args [0 ], args , os .environ ,
1774
- file_actions = [(os .POSIX_SPAWN_CLOSE , 0 ), ])
1773
+ pid = self . spawn_func (args [0 ], args , os .environ ,
1774
+ file_actions = [(os .POSIX_SPAWN_CLOSE , 0 )])
1775
1775
self .assertEqual (os .waitpid (pid , 0 ), (pid , 0 ))
1776
1776
with open (closefile ) as f :
1777
1777
self .assertEqual (f .read (), 'is closed %d' % errno .EBADF )
@@ -1788,16 +1788,64 @@ def test_dup2(self):
1788
1788
(os .POSIX_SPAWN_DUP2 , childfile .fileno (), 1 ),
1789
1789
]
1790
1790
args = self .python_args ('-c' , script )
1791
- pid = posix . posix_spawn (args [0 ], args , os .environ ,
1792
- file_actions = file_actions )
1791
+ pid = self . spawn_func (args [0 ], args , os .environ ,
1792
+ file_actions = file_actions )
1793
1793
self .assertEqual (os .waitpid (pid , 0 ), (pid , 0 ))
1794
1794
with open (dupfile ) as f :
1795
1795
self .assertEqual (f .read (), 'hello' )
1796
1796
1797
1797
1798
+ @unittest .skipUnless (hasattr (os , 'posix_spawn' ), "test needs os.posix_spawn" )
1799
+ class TestPosixSpawn (unittest .TestCase , _PosixSpawnMixin ):
1800
+ spawn_func = getattr (posix , 'posix_spawn' , None )
1801
+
1802
+
1803
+ @unittest .skipUnless (hasattr (os , 'posix_spawnp' ), "test needs os.posix_spawnp" )
1804
+ class TestPosixSpawnP (unittest .TestCase , _PosixSpawnMixin ):
1805
+ spawn_func = getattr (posix , 'posix_spawnp' , None )
1806
+
1807
+ @support .skip_unless_symlink
1808
+ def test_posix_spawnp (self ):
1809
+ # Use a symlink to create a program in its own temporary directory
1810
+ temp_dir = tempfile .mkdtemp ()
1811
+ self .addCleanup (support .rmtree , temp_dir )
1812
+
1813
+ program = 'posix_spawnp_test_program.exe'
1814
+ program_fullpath = os .path .join (temp_dir , program )
1815
+ os .symlink (sys .executable , program_fullpath )
1816
+
1817
+ try :
1818
+ path = os .pathsep .join ((temp_dir , os .environ ['PATH' ]))
1819
+ except KeyError :
1820
+ path = temp_dir # PATH is not set
1821
+
1822
+ spawn_args = (program , '-I' , '-S' , '-c' , 'pass' )
1823
+ code = textwrap .dedent ("""
1824
+ import os
1825
+ args = %a
1826
+ pid = os.posix_spawnp(args[0], args, os.environ)
1827
+ pid2, status = os.waitpid(pid, 0)
1828
+ if pid2 != pid:
1829
+ raise Exception(f"pid {pid2} != {pid}")
1830
+ if status != 0:
1831
+ raise Exception(f"status {status} != 0")
1832
+ """ % (spawn_args ,))
1833
+
1834
+ # Use a subprocess to test os.posix_spawnp() with a modified PATH
1835
+ # environment variable: posix_spawnp() uses the current environment
1836
+ # to locate the program, not its environment argument.
1837
+ args = ('-c' , code )
1838
+ assert_python_ok (* args , PATH = path )
1839
+
1840
+
1798
1841
def test_main ():
1799
1842
try :
1800
- support .run_unittest (PosixTester , PosixGroupsTester , TestPosixSpawn )
1843
+ support .run_unittest (
1844
+ PosixTester ,
1845
+ PosixGroupsTester ,
1846
+ TestPosixSpawn ,
1847
+ TestPosixSpawnP ,
1848
+ )
1801
1849
finally :
1802
1850
support .reap_children ()
1803
1851
0 commit comments