1
+ from __future__ import annotations
2
+
1
3
import inspect
2
4
import os
3
5
import subprocess
4
6
import sys
5
7
import textwrap
8
+ from dataclasses import dataclass
6
9
from io import BytesIO
10
+ from pathlib import Path
11
+ from typing import Any
7
12
8
13
import execnet
9
14
import pytest
21
26
)
22
27
23
28
29
+ @pytest .mark .parametrize ("val" , ["123" , 42 , [1 , 2 , 3 ], ["23" , 25 ]])
24
30
class TestSerializeAPI :
25
- pytestmark = [pytest .mark .parametrize ("val" , ["123" , 42 , [1 , 2 , 3 ], ["23" , 25 ]])]
26
-
27
31
def test_serializer_api (self , val ):
28
32
dumped = execnet .dumps (val )
29
33
val2 = execnet .loads (dumped )
30
34
assert val == val2
31
35
32
36
def test_mmap (self , tmp_path , val ):
33
37
mmap = pytest .importorskip ("mmap" ).mmap
34
- p = tmp_path / "data"
35
- with p . open ( "wb" ) as f :
36
- f . write (execnet .dumps (val ))
38
+ p = tmp_path / "data.bin "
39
+
40
+ p . write_bytes (execnet .dumps (val ))
37
41
with p .open ("r+b" ) as f :
38
42
m = mmap (f .fileno (), 0 )
39
43
val2 = execnet .load (m )
@@ -112,67 +116,83 @@ def read_write_loop():
112
116
break
113
117
114
118
115
- def test_io_message (anypython , tmp_path , execmodel ):
116
- check = tmp_path / "check.py"
117
- check .write_text (
118
- inspect .getsource (gateway_base )
119
- + textwrap .dedent (
120
- """
121
- from io import BytesIO
122
- import tempfile
123
- temp_out = BytesIO()
124
- temp_in = BytesIO()
125
- io = Popen2IO(temp_out, temp_in, get_execmodel({backend!r}))
126
- for i, handler in enumerate(Message._types):
127
- print ("checking %s %s" %(i, handler))
128
- for data in "hello", "hello".encode('ascii'):
129
- msg1 = Message(i, i, dumps(data))
130
- msg1.to_io(io)
131
- x = io.outfile.getvalue()
132
- io.outfile.truncate(0)
133
- io.outfile.seek(0)
134
- io.infile.seek(0)
135
- io.infile.write(x)
136
- io.infile.seek(0)
137
- msg2 = Message.from_io(io)
138
- assert msg1.channelid == msg2.channelid, (msg1, msg2)
139
- assert msg1.data == msg2.data, (msg1.data, msg2.data)
140
- assert msg1.msgcode == msg2.msgcode
141
- print ("all passed")
142
- """ .format (
143
- backend = execmodel .backend
144
- ),
119
+ IO_MESSAGE_EXTRA_SOURCE = """
120
+ import sys
121
+ backend = sys.argv[1]
122
+ try:
123
+ from io import BytesIO
124
+ except ImportError:
125
+ from StringIO import StringIO as BytesIO
126
+ import tempfile
127
+ temp_out = BytesIO()
128
+ temp_in = BytesIO()
129
+ io = Popen2IO(temp_out, temp_in, get_execmodel(backend))
130
+ for i, handler in enumerate(Message._types):
131
+ print ("checking", i, handler)
132
+ for data in "hello", "hello".encode('ascii'):
133
+ msg1 = Message(i, i, dumps(data))
134
+ msg1.to_io(io)
135
+ x = io.outfile.getvalue()
136
+ io.outfile.truncate(0)
137
+ io.outfile.seek(0)
138
+ io.infile.seek(0)
139
+ io.infile.write(x)
140
+ io.infile.seek(0)
141
+ msg2 = Message.from_io(io)
142
+ assert msg1.channelid == msg2.channelid, (msg1, msg2)
143
+ assert msg1.data == msg2.data, (msg1.data, msg2.data)
144
+ assert msg1.msgcode == msg2.msgcode
145
+ print ("all passed")
146
+ """
147
+
148
+
149
+ @dataclass
150
+ class Checker :
151
+ python : str
152
+ path : Path
153
+ idx : int = 0
154
+
155
+ def run_check (
156
+ self , script : str , * extra_args : str , ** process_args : Any
157
+ ) -> subprocess .CompletedProcess [str ]:
158
+ self .idx += 1
159
+ check_path = self .path / f"check{ self .idx } .py"
160
+ check_path .write_text (script )
161
+ return subprocess .run (
162
+ [self .python , os .fspath (check_path ), * extra_args ],
163
+ capture_output = True ,
164
+ text = True ,
165
+ check = True ,
166
+ ** process_args ,
145
167
)
168
+
169
+
170
+ @pytest .fixture
171
+ def checker (anypython : str , tmp_path : Path ) -> Checker :
172
+ return Checker (python = anypython , path = tmp_path )
173
+
174
+
175
+ def test_io_message (checker , execmodel ):
176
+ out = checker .run_check (
177
+ inspect .getsource (gateway_base ) + IO_MESSAGE_EXTRA_SOURCE , execmodel .backend
146
178
)
147
- out = subprocess .run (
148
- [str (anypython ), str (check )], text = True , capture_output = True , check = True
149
- ).stdout
150
- print (out )
151
- assert "all passed" in out
179
+ print (out .stdout )
180
+ assert "all passed" in out .stdout
152
181
153
182
154
- def test_popen_io (anypython , tmp_path , execmodel ):
155
- check = tmp_path / "check.py"
156
- check .write_text (
183
+ def test_popen_io (checker , execmodel ):
184
+ out = checker .run_check (
157
185
inspect .getsource (gateway_base )
158
- + textwrap .dedent (
159
- f"""
160
- io = init_popen_io(get_execmodel({ execmodel .backend !r} ))
161
- io.write("hello".encode('ascii'))
162
- s = io.read(1)
163
- assert s == "x".encode('ascii')
164
- """
165
- ),
186
+ + f"""
187
+ io = init_popen_io(get_execmodel({ execmodel .backend !r} ))
188
+ io.write(b"hello")
189
+ s = io.read(1)
190
+ assert s == b"x"
191
+ """ ,
192
+ input = "x" ,
166
193
)
167
- from subprocess import Popen , PIPE
168
-
169
- args = [str (anypython ), str (check )]
170
- proc = Popen (args , stdin = PIPE , stdout = PIPE , stderr = PIPE )
171
- proc .stdin .write (b"x" )
172
- stdout , stderr = proc .communicate ()
173
- print (stderr )
174
- proc .wait ()
175
- assert b"hello" in stdout
194
+ print (out .stderr )
195
+ assert "hello" in out .stdout
176
196
177
197
178
198
def test_popen_io_readloop (monkeypatch , execmodel ):
@@ -190,60 +210,45 @@ def newread(numbytes):
190
210
assert result == b"tes"
191
211
192
212
193
- def test_rinfo_source (anypython , tmp_path ):
194
- check = tmp_path / "check.py"
195
- check .write_text (
196
- textwrap .dedent (
197
- """
198
- class Channel:
199
- def send(self, data):
200
- assert eval(repr(data), {}) == data
201
- channel = Channel()
202
- """
203
- )
204
- + inspect .getsource (gateway .rinfo_source )
205
- + textwrap .dedent (
206
- """
207
- print ('all passed')
208
- """
209
- )
213
+ def test_rinfo_source (checker ):
214
+ out = checker .run_check (
215
+ f"""
216
+ class Channel:
217
+ def send(self, data):
218
+ assert eval(repr(data), {{}}) == data
219
+ channel = Channel()
220
+ { inspect .getsource (gateway .rinfo_source )}
221
+ print ('all passed')
222
+ """
210
223
)
211
- out = subprocess .run (
212
- [str (anypython ), str (check )], text = True , capture_output = True , check = True
213
- ).stdout
214
- print (out )
215
- assert "all passed" in out
216
224
225
+ print (out .stdout )
226
+ assert "all passed" in out .stdout
217
227
218
- def test_geterrortext ( anypython , tmp_path ):
219
- check = tmp_path / "check.py"
220
- check . write_text (
228
+
229
+ def test_geterrortext ( checker ):
230
+ out = checker . run_check (
221
231
inspect .getsource (gateway_base )
222
- + textwrap .dedent (
223
- """
224
- class Arg:
225
- pass
226
- errortext = geterrortext((Arg, "1", 4))
227
- assert "Arg" in errortext
228
- import sys
229
- try:
230
- raise ValueError("17")
231
- except ValueError:
232
- excinfo = sys.exc_info()
233
- s = geterrortext(excinfo)
234
- assert "17" in s
235
- print ("all passed")
232
+ + """
233
+ class Arg:
234
+ pass
235
+ errortext = geterrortext((Arg, "1", 4))
236
+ assert "Arg" in errortext
237
+ import sys
238
+ try:
239
+ raise ValueError("17")
240
+ except ValueError:
241
+ excinfo = sys.exc_info()
242
+ s = geterrortext(excinfo)
243
+ assert "17" in s
244
+ print ("all passed")
236
245
"""
237
- )
238
246
)
239
- out = subprocess .run (
240
- [str (anypython ), str (check )], text = True , capture_output = True , check = True
241
- ).stdout
242
- print (out )
243
- assert "all passed" in out
247
+ print (out .stdout )
248
+ assert "all passed" in out .stdout
244
249
245
250
246
- @pytest .mark .skipif (not hasattr (os , " dup" ), reason = "no os.dup " )
251
+ @pytest .mark .skipif (" not hasattr(os, ' dup') " )
247
252
def test_stdouterrin_setnull (execmodel , capfd ):
248
253
gateway_base .init_popen_io (execmodel )
249
254
os .write (1 , b"hello" )
@@ -297,15 +302,15 @@ def test_wire_protocol(self):
297
302
class TestPureChannel :
298
303
@pytest .fixture
299
304
def fac (self , execmodel ):
300
- class Gateway :
305
+ class FakeGateway :
301
306
def _trace (self , * args ):
302
307
pass
303
308
304
309
def _send (self , * k ):
305
310
pass
306
311
307
- Gateway .execmodel = execmodel
308
- return ChannelFactory (Gateway ())
312
+ FakeGateway .execmodel = execmodel
313
+ return ChannelFactory (FakeGateway ())
309
314
310
315
def test_factory_create (self , fac ):
311
316
chan1 = fac .new ()
0 commit comments