1+ from __future__ import annotations
2+
13import inspect
24import os
35import subprocess
46import sys
57import textwrap
8+ from dataclasses import dataclass
69from io import BytesIO
10+ from pathlib import Path
11+ from typing import Any
712
813import execnet
914import pytest
2126)
2227
2328
29+ @pytest .mark .parametrize ("val" , ["123" , 42 , [1 , 2 , 3 ], ["23" , 25 ]])
2430class TestSerializeAPI :
25- pytestmark = [pytest .mark .parametrize ("val" , ["123" , 42 , [1 , 2 , 3 ], ["23" , 25 ]])]
26-
2731 def test_serializer_api (self , val ):
2832 dumped = execnet .dumps (val )
2933 val2 = execnet .loads (dumped )
3034 assert val == val2
3135
3236 def test_mmap (self , tmp_path , val ):
3337 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 ))
3741 with p .open ("r+b" ) as f :
3842 m = mmap (f .fileno (), 0 )
3943 val2 = execnet .load (m )
@@ -112,67 +116,83 @@ def read_write_loop():
112116 break
113117
114118
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 ,
145167 )
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
146178 )
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
152181
153182
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 (
157185 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" ,
166193 )
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
176196
177197
178198def test_popen_io_readloop (monkeypatch , execmodel ):
@@ -190,60 +210,45 @@ def newread(numbytes):
190210 assert result == b"tes"
191211
192212
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+ """
210223 )
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
216224
225+ print (out .stdout )
226+ assert "all passed" in out .stdout
217227
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 (
221231 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")
236245 """
237- )
238246 )
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
244249
245250
246- @pytest .mark .skipif (not hasattr (os , " dup" ), reason = "no os.dup " )
251+ @pytest .mark .skipif (" not hasattr(os, ' dup') " )
247252def test_stdouterrin_setnull (execmodel , capfd ):
248253 gateway_base .init_popen_io (execmodel )
249254 os .write (1 , b"hello" )
@@ -297,15 +302,15 @@ def test_wire_protocol(self):
297302class TestPureChannel :
298303 @pytest .fixture
299304 def fac (self , execmodel ):
300- class Gateway :
305+ class FakeGateway :
301306 def _trace (self , * args ):
302307 pass
303308
304309 def _send (self , * k ):
305310 pass
306311
307- Gateway .execmodel = execmodel
308- return ChannelFactory (Gateway ())
312+ FakeGateway .execmodel = execmodel
313+ return ChannelFactory (FakeGateway ())
309314
310315 def test_factory_create (self , fac ):
311316 chan1 = fac .new ()
0 commit comments