Skip to content

Commit 058f8c5

Browse files
authored
Add fork support functions (RustPython#4972)
1 parent 0e24cf4 commit 058f8c5

File tree

12 files changed

+106
-65
lines changed

12 files changed

+106
-65
lines changed

Lib/_dummy_thread.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ def release(self):
145145
def locked(self):
146146
return self.locked_status
147147

148+
def _at_fork_reinit(self):
149+
self.locked_status = False
150+
148151
def __repr__(self):
149152
return "<%s %s.%s object at %s>" % (
150153
"locked" if self.locked_status else "unlocked",

Lib/test/test_builtin.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@
3737
except ImportError:
3838
pty = signal = None
3939

40-
import threading # XXX: RUSTPYTHON; to skip _at_fork_reinit
41-
4240

4341
class Squares:
4442

@@ -2261,17 +2259,18 @@ def skip_if_readline(self):
22612259
if 'readline' in sys.modules:
22622260
self.skipTest("the readline module is loaded")
22632261

2262+
@unittest.skipUnless(hasattr(sys.stdin, 'detach'), 'TODO: RustPython: requires detach function in TextIOWrapper')
22642263
def test_input_tty_non_ascii(self):
22652264
self.skip_if_readline()
22662265
# Check stdin/stdout encoding is used when invoking PyOS_Readline()
22672266
self.check_input_tty("prompté", b"quux\xe9", "utf-8")
22682267

2268+
@unittest.skipUnless(hasattr(sys.stdin, 'detach'), 'TODO: RustPython: requires detach function in TextIOWrapper')
22692269
def test_input_tty_non_ascii_unicode_errors(self):
22702270
self.skip_if_readline()
22712271
# Check stdin/stdout error handler is used when invoking PyOS_Readline()
22722272
self.check_input_tty("prompté", b"quux\xe9", "ascii")
22732273

2274-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
22752274
def test_input_no_stdout_fileno(self):
22762275
# Issue #24402: If stdin is the original terminal but stdout.fileno()
22772276
# fails, do not use the original stdout file descriptor

Lib/test/test_fcntl.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import os
55
import struct
66
import sys
7-
import threading # XXX: RUSTPYTHON
87
import unittest
98
from multiprocessing import Process
109
from test.support import verbose, cpython_only
@@ -156,9 +155,8 @@ def test_flock(self):
156155
self.assertRaises(ValueError, fcntl.flock, -1, fcntl.LOCK_SH)
157156
self.assertRaises(TypeError, fcntl.flock, 'spam', fcntl.LOCK_SH)
158157

159-
# TODO: RUSTPYTHON
160-
@unittest.expectedFailure
161-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
158+
# TODO RustPython
159+
@unittest.skipUnless(sys.platform == 'linux', 'test requires Linux')
162160
@unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
163161
def test_lockf_exclusive(self):
164162
self.f = open(TESTFN, 'wb+')
@@ -169,9 +167,9 @@ def test_lockf_exclusive(self):
169167
p.join()
170168
fcntl.lockf(self.f, fcntl.LOCK_UN)
171169
self.assertEqual(p.exitcode, 0)
172-
# TODO: RUSTPYTHON
173-
@unittest.expectedFailure
174-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
170+
171+
# TODO RustPython
172+
@unittest.skipUnless(sys.platform == 'linux', 'test requires Linux')
175173
@unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
176174
def test_lockf_share(self):
177175
self.f = open(TESTFN, 'wb+')

Lib/test/test_httpservers.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,8 @@ def test_url_collapse_path(self):
766766
msg='path = %r\nGot: %r\nWanted: %r' %
767767
(path, actual, expected))
768768

769-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
769+
# TODO: RUSTPYTHON
770+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
770771
def test_headers_and_content(self):
771772
res = self.request('/cgi-bin/file1.py')
772773
self.assertEqual(
@@ -777,7 +778,8 @@ def test_issue19435(self):
777778
res = self.request('///////////nocgi.py/../cgi-bin/nothere.sh')
778779
self.assertEqual(res.status, HTTPStatus.NOT_FOUND)
779780

780-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
781+
# TODO: RUSTPYTHON
782+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
781783
def test_post(self):
782784
params = urllib.parse.urlencode(
783785
{'spam' : 1, 'eggs' : 'python', 'bacon' : 123456})
@@ -791,7 +793,8 @@ def test_invaliduri(self):
791793
res.read()
792794
self.assertEqual(res.status, HTTPStatus.NOT_FOUND)
793795

794-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
796+
# TODO: RUSTPYTHON
797+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
795798
def test_authorization(self):
796799
headers = {b'Authorization' : b'Basic ' +
797800
base64.b64encode(b'username:pass')}
@@ -800,15 +803,17 @@ def test_authorization(self):
800803
(b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
801804
(res.read(), res.getheader('Content-type'), res.status))
802805

803-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
806+
# TODO: RUSTPYTHON
807+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
804808
def test_no_leading_slash(self):
805809
# http://bugs.python.org/issue2254
806810
res = self.request('cgi-bin/file1.py')
807811
self.assertEqual(
808812
(b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
809813
(res.read(), res.getheader('Content-type'), res.status))
810814

811-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
815+
# TODO: RUSTPYTHON
816+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
812817
def test_os_environ_is_not_altered(self):
813818
signature = "Test CGI Server"
814819
os.environ['SERVER_SOFTWARE'] = signature
@@ -818,36 +823,41 @@ def test_os_environ_is_not_altered(self):
818823
(res.read(), res.getheader('Content-type'), res.status))
819824
self.assertEqual(os.environ['SERVER_SOFTWARE'], signature)
820825

821-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
826+
# TODO: RUSTPYTHON
827+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
822828
def test_urlquote_decoding_in_cgi_check(self):
823829
res = self.request('/cgi-bin%2ffile1.py')
824830
self.assertEqual(
825831
(b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
826832
(res.read(), res.getheader('Content-type'), res.status))
827833

828-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
834+
# TODO: RUSTPYTHON
835+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
829836
def test_nested_cgi_path_issue21323(self):
830837
res = self.request('/cgi-bin/child-dir/file3.py')
831838
self.assertEqual(
832839
(b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
833840
(res.read(), res.getheader('Content-type'), res.status))
834841

835-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
842+
# TODO: RUSTPYTHON
843+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
836844
def test_query_with_multiple_question_mark(self):
837845
res = self.request('/cgi-bin/file4.py?a=b?c=d')
838846
self.assertEqual(
839847
(b'a=b?c=d' + self.linesep, 'text/html', HTTPStatus.OK),
840848
(res.read(), res.getheader('Content-type'), res.status))
841849

842-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
850+
# TODO: RUSTPYTHON
851+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
843852
def test_query_with_continuous_slashes(self):
844853
res = self.request('/cgi-bin/file4.py?k=aa%2F%2Fbb&//q//p//=//a//b//')
845854
self.assertEqual(
846855
(b'k=aa%2F%2Fbb&//q//p//=//a//b//' + self.linesep,
847856
'text/html', HTTPStatus.OK),
848857
(res.read(), res.getheader('Content-type'), res.status))
849858

850-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
859+
# TODO: RUSTPYTHON
860+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
851861
def test_cgi_path_in_sub_directories(self):
852862
try:
853863
CGIHTTPRequestHandler.cgi_directories.append('/sub/dir/cgi-bin')
@@ -858,7 +868,8 @@ def test_cgi_path_in_sub_directories(self):
858868
finally:
859869
CGIHTTPRequestHandler.cgi_directories.remove('/sub/dir/cgi-bin')
860870

861-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
871+
# TODO: RUSTPYTHON
872+
@unittest.skipIf(sys.platform != 'win32', "TODO: RUSTPYTHON; works only on windows")
862873
def test_accept(self):
863874
browser_accept = \
864875
'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'

Lib/test/test_os.py

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3070,15 +3070,9 @@ def check_waitpid(self, code, exitcode, callback=None):
30703070
self.assertEqual(os.waitstatus_to_exitcode(status), exitcode)
30713071
self.assertEqual(pid2, pid)
30723072

3073-
# TODO: RUSTPYTHON (AttributeError: module 'os' has no attribute 'spawnv')
3074-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
3075-
@unittest.expectedFailure
30763073
def test_waitpid(self):
30773074
self.check_waitpid(code='pass', exitcode=0)
30783075

3079-
# TODO: RUSTPYTHON (AttributeError: module 'os' has no attribute 'spawnv')
3080-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
3081-
@unittest.expectedFailure
30823076
def test_waitstatus_to_exitcode(self):
30833077
exitcode = 23
30843078
code = f'import sys; sys.exit({exitcode})'
@@ -3110,9 +3104,6 @@ def test_waitstatus_to_exitcode_windows(self):
31103104
with self.assertRaises(OverflowError):
31113105
os.waitstatus_to_exitcode(-1)
31123106

3113-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
3114-
# TODO: RUSTPYTHON (AttributeError: module 'os' has no attribute 'spawnv')
3115-
@unittest.expectedFailure
31163107
# Skip the test on Windows
31173108
@unittest.skipUnless(hasattr(signal, 'SIGKILL'), 'need signal.SIGKILL')
31183109
def test_waitstatus_to_exitcode_kill(self):
@@ -3154,35 +3145,30 @@ def create_args(self, *, with_env=False, use_bytes=False):
31543145

31553146
return args
31563147

3157-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
31583148
@requires_os_func('spawnl')
31593149
def test_spawnl(self):
31603150
args = self.create_args()
31613151
exitcode = os.spawnl(os.P_WAIT, args[0], *args)
31623152
self.assertEqual(exitcode, self.exitcode)
31633153

3164-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
31653154
@requires_os_func('spawnle')
31663155
def test_spawnle(self):
31673156
args = self.create_args(with_env=True)
31683157
exitcode = os.spawnle(os.P_WAIT, args[0], *args, self.env)
31693158
self.assertEqual(exitcode, self.exitcode)
31703159

3171-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
31723160
@requires_os_func('spawnlp')
31733161
def test_spawnlp(self):
31743162
args = self.create_args()
31753163
exitcode = os.spawnlp(os.P_WAIT, args[0], *args)
31763164
self.assertEqual(exitcode, self.exitcode)
31773165

3178-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
31793166
@requires_os_func('spawnlpe')
31803167
def test_spawnlpe(self):
31813168
args = self.create_args(with_env=True)
31823169
exitcode = os.spawnlpe(os.P_WAIT, args[0], *args, self.env)
31833170
self.assertEqual(exitcode, self.exitcode)
31843171

3185-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
31863172
@requires_os_func('spawnv')
31873173
def test_spawnv(self):
31883174
args = self.create_args()
@@ -3193,35 +3179,32 @@ def test_spawnv(self):
31933179
exitcode = os.spawnv(os.P_WAIT, FakePath(args[0]), args)
31943180
self.assertEqual(exitcode, self.exitcode)
31953181

3196-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
31973182
@requires_os_func('spawnve')
31983183
def test_spawnve(self):
31993184
args = self.create_args(with_env=True)
32003185
exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env)
32013186
self.assertEqual(exitcode, self.exitcode)
32023187

3203-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
32043188
@requires_os_func('spawnvp')
32053189
def test_spawnvp(self):
32063190
args = self.create_args()
32073191
exitcode = os.spawnvp(os.P_WAIT, args[0], args)
32083192
self.assertEqual(exitcode, self.exitcode)
32093193

3210-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
32113194
@requires_os_func('spawnvpe')
32123195
def test_spawnvpe(self):
32133196
args = self.create_args(with_env=True)
32143197
exitcode = os.spawnvpe(os.P_WAIT, args[0], args, self.env)
32153198
self.assertEqual(exitcode, self.exitcode)
32163199

3217-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
32183200
@requires_os_func('spawnv')
32193201
def test_nowait(self):
32203202
args = self.create_args()
32213203
pid = os.spawnv(os.P_NOWAIT, args[0], args)
32223204
support.wait_process(pid, exitcode=self.exitcode)
32233205

3224-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
3206+
# TODO: RUSTPYTHON fix spawnv bytes
3207+
@unittest.expectedFailure
32253208
@requires_os_func('spawnve')
32263209
def test_spawnve_bytes(self):
32273210
# Test bytes handling in parse_arglist and parse_envlist (#28114)
@@ -3303,12 +3286,10 @@ def _test_invalid_env(self, spawn):
33033286
exitcode = spawn(os.P_WAIT, args[0], args, newenv)
33043287
self.assertEqual(exitcode, 0)
33053288

3306-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
33073289
@requires_os_func('spawnve')
33083290
def test_spawnve_invalid_env(self):
33093291
self._test_invalid_env(os.spawnve)
33103292

3311-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
33123293
@requires_os_func('spawnvpe')
33133294
def test_spawnvpe_invalid_env(self):
33143295
self._test_invalid_env(os.spawnvpe)

Lib/test/test_pty.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import threading # XXX: RUSTPYTHON
1+
from test import support
22
from test.support import verbose, reap_children
33
from test.support.import_helper import import_module
44

@@ -211,9 +211,7 @@ def test_openpty(self):
211211
s2 = _readline(master_fd)
212212
self.assertEqual(b'For my pet fish, Eric.\n', normalize_output(s2))
213213

214-
# TODO: RUSTPYTHON
215-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
216-
@unittest.expectedFailure
214+
@support.requires_fork()
217215
def test_fork(self):
218216
debug("calling pty.fork()")
219217
pid, master_fd = pty.fork()
@@ -315,9 +313,6 @@ def test_master_read(self):
315313

316314
self.assertEqual(data, b"")
317315

318-
# TODO: RUSTPYTHON; no os.fork
319-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
320-
@unittest.expectedFailure
321316
def test_spawn_doesnt_hang(self):
322317
pty.spawn([sys.executable, '-c', 'print("hi there")'])
323318

Lib/test/test_support.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import sys
1010
import tempfile
1111
import textwrap
12-
import threading # XXX: RUSTPYTHON
1312
import time
1413
import unittest
1514
import warnings
@@ -452,9 +451,6 @@ def test_check__all__(self):
452451

453452
self.assertRaises(AssertionError, support.check__all__, self, unittest)
454453

455-
# TODO: RUSTPYTHON
456-
@unittest.expectedFailure
457-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
458454
@unittest.skipUnless(hasattr(os, 'waitpid') and hasattr(os, 'WNOHANG'),
459455
'need os.waitpid() and os.WNOHANG')
460456
@support.requires_fork()

Lib/test/test_tempfile.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import pathlib
77
import sys
88
import re
9-
import threading # XXX: RUSTPYTHON; to check `_at_fork_reinit`
109
import warnings
1110
import contextlib
1211
import stat
@@ -199,7 +198,6 @@ def supports_iter(self):
199198
if i == 20:
200199
break
201200

202-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
203201
@unittest.skipUnless(hasattr(os, 'fork'),
204202
"os.fork is required for this test")
205203
def test_process_awareness(self):
@@ -467,7 +465,7 @@ def test_file_mode(self):
467465
expected = user * (1 + 8 + 64)
468466
self.assertEqual(mode, expected)
469467

470-
@unittest.skipUnless(hasattr(threading.Lock(), '_at_fork_reinit'), 'TODO: RUSTPYTHON, test needs lock._at_fork_reinit')
468+
@support.requires_fork()
471469
@unittest.skipUnless(has_spawnl, 'os.spawnl not available')
472470
def test_noinherit(self):
473471
# _mkstemp_inner file handles are not inherited by child processes

0 commit comments

Comments
 (0)