portal 3.2.4__tar.gz → 3.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {portal-3.2.4/portal.egg-info → portal-3.4.0}/PKG-INFO +1 -1
- {portal-3.2.4 → portal-3.4.0}/portal/__init__.py +1 -1
- {portal-3.2.4 → portal-3.4.0}/portal/batching.py +1 -1
- {portal-3.2.4 → portal-3.4.0}/portal/client.py +2 -4
- {portal-3.2.4 → portal-3.4.0}/portal/client_socket.py +25 -21
- {portal-3.2.4 → portal-3.4.0}/portal/server.py +9 -7
- {portal-3.2.4 → portal-3.4.0}/portal/server_socket.py +4 -3
- {portal-3.2.4 → portal-3.4.0}/portal/utils.py +5 -3
- {portal-3.2.4 → portal-3.4.0/portal.egg-info}/PKG-INFO +1 -1
- {portal-3.2.4 → portal-3.4.0}/tests/test_batching.py +10 -10
- {portal-3.2.4 → portal-3.4.0}/tests/test_client.py +33 -15
- {portal-3.2.4 → portal-3.4.0}/tests/test_server.py +36 -17
- {portal-3.2.4 → portal-3.4.0}/tests/test_socket.py +13 -12
- {portal-3.2.4 → portal-3.4.0}/LICENSE +0 -0
- {portal-3.2.4 → portal-3.4.0}/MANIFEST.in +0 -0
- {portal-3.2.4 → portal-3.4.0}/README.md +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal/buffers.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal/contextlib.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal/packlib.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal/poollib.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal/process.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal/sharray.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal/thread.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal.egg-info/SOURCES.txt +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal.egg-info/dependency_links.txt +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal.egg-info/requires.txt +0 -0
- {portal-3.2.4 → portal-3.4.0}/portal.egg-info/top_level.txt +0 -0
- {portal-3.2.4 → portal-3.4.0}/pyproject.toml +0 -0
- {portal-3.2.4 → portal-3.4.0}/requirements.txt +0 -0
- {portal-3.2.4 → portal-3.4.0}/setup.cfg +0 -0
- {portal-3.2.4 → portal-3.4.0}/setup.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/tests/test_errfile.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/tests/test_pack.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/tests/test_process.py +0 -0
- {portal-3.2.4 → portal-3.4.0}/tests/test_thread.py +0 -0
@@ -162,7 +162,7 @@ def batcher(
|
|
162
162
|
|
163
163
|
try:
|
164
164
|
outer = server_socket.ServerSocket(outer_port, f'{name}Server', **kwargs)
|
165
|
-
inner = client.Client(
|
165
|
+
inner = client.Client(inner_port, f'{name}Client', **kwargs)
|
166
166
|
batches = {} # {method: ([addr], [reqnum], structure, [array])}
|
167
167
|
jobs = []
|
168
168
|
shutdown = False
|
@@ -11,8 +11,7 @@ from . import packlib
|
|
11
11
|
|
12
12
|
class Client:
|
13
13
|
|
14
|
-
def __init__(
|
15
|
-
self, host, port=None, name='Client', maxinflight=16, **kwargs):
|
14
|
+
def __init__(self, addr, name='Client', maxinflight=16, **kwargs):
|
16
15
|
assert 1 <= maxinflight, maxinflight
|
17
16
|
self.maxinflight = maxinflight
|
18
17
|
self.reqnum = iter(itertools.count(0))
|
@@ -25,8 +24,7 @@ class Client:
|
|
25
24
|
self.lock = threading.Lock()
|
26
25
|
# Socket is created after the above attributes because the callbacks access
|
27
26
|
# some of the attributes.
|
28
|
-
self.socket = client_socket.ClientSocket(
|
29
|
-
host, port, name, start=False, **kwargs)
|
27
|
+
self.socket = client_socket.ClientSocket(addr, name, start=False, **kwargs)
|
30
28
|
self.socket.callbacks_recv.append(self._recv)
|
31
29
|
self.socket.callbacks_disc.append(self._disc)
|
32
30
|
self.socket.callbacks_conn.append(self._conn)
|
@@ -29,19 +29,19 @@ class Options:
|
|
29
29
|
keepalive_fails: int = 10
|
30
30
|
logging: bool = True
|
31
31
|
logging_color: str = 'yellow'
|
32
|
+
connect_wait: float = 0.1
|
32
33
|
|
33
34
|
|
34
35
|
class ClientSocket:
|
35
36
|
|
36
|
-
def __init__(self,
|
37
|
-
|
38
|
-
assert '://' not in
|
39
|
-
|
40
|
-
host, port = host.rsplit(':', 1)
|
41
|
-
assert host and port, (host, port)
|
42
|
-
self.addr = (host, port)
|
37
|
+
def __init__(self, addr, name='Client', start=True, **kwargs):
|
38
|
+
addr = str(addr)
|
39
|
+
assert '://' not in addr, addr
|
40
|
+
host, port = addr.rsplit(':', 1) if ':' in addr else ('', addr)
|
43
41
|
self.name = name
|
44
42
|
self.options = Options(**{**contextlib.context.clientkw, **kwargs})
|
43
|
+
host = host or ('::1' if self.options.ipv6 else '127.0.0.1')
|
44
|
+
self.addr = (host, port)
|
45
45
|
|
46
46
|
self.callbacks_recv = []
|
47
47
|
self.callbacks_conn = []
|
@@ -190,6 +190,7 @@ class ClientSocket:
|
|
190
190
|
port = int(port)
|
191
191
|
addr = (host, port, 0, 0) if self.options.ipv6 else (host, port)
|
192
192
|
sock = self._create()
|
193
|
+
start = time.time()
|
193
194
|
error = None
|
194
195
|
try:
|
195
196
|
sock.settimeout(10)
|
@@ -203,11 +204,11 @@ class ClientSocket:
|
|
203
204
|
error = e
|
204
205
|
except socket.gaierror as e:
|
205
206
|
error = e
|
206
|
-
time.sleep(0.1)
|
207
207
|
if once:
|
208
208
|
self._log(f'Still trying to connect... ({error})')
|
209
209
|
once = False
|
210
210
|
sock.close()
|
211
|
+
time.sleep(self.options.connect_wait)
|
211
212
|
return None
|
212
213
|
|
213
214
|
def _create(self):
|
@@ -216,22 +217,25 @@ class ClientSocket:
|
|
216
217
|
else:
|
217
218
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
218
219
|
# sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
220
|
+
|
219
221
|
after = self.options.keepalive_after
|
220
222
|
every = self.options.keepalive_every
|
221
223
|
fails = self.options.keepalive_fails
|
222
|
-
if
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
224
|
+
if after and every and fails:
|
225
|
+
if sys.platform == 'linux':
|
226
|
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
227
|
+
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after)
|
228
|
+
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, every)
|
229
|
+
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, fails)
|
230
|
+
sock.setsockopt(
|
231
|
+
socket.IPPROTO_TCP, socket.TCP_USER_TIMEOUT,
|
232
|
+
1000 * (after + every * fails))
|
233
|
+
if sys.platform == 'darwin':
|
234
|
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
235
|
+
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPALIVE, every)
|
236
|
+
if sys.platform == 'win32':
|
237
|
+
sock.ioctl(socket.SIO_KEEPALIVE_VALS, (1, after * 1000, every * 1000))
|
238
|
+
|
235
239
|
return sock
|
236
240
|
|
237
241
|
def _log(self, *args):
|
@@ -47,12 +47,13 @@ class Server:
|
|
47
47
|
if block:
|
48
48
|
self.loop.join(timeout=None)
|
49
49
|
|
50
|
-
def close(self, timeout=None):
|
50
|
+
def close(self, timeout=None, internal=False):
|
51
51
|
assert self.running
|
52
52
|
self.socket.shutdown()
|
53
53
|
self.running = False
|
54
|
-
|
55
|
-
|
54
|
+
if not internal:
|
55
|
+
self.loop.join(timeout)
|
56
|
+
self.loop.kill()
|
56
57
|
[x.close() for x in self.pools]
|
57
58
|
self.socket.close()
|
58
59
|
|
@@ -123,14 +124,16 @@ class Server:
|
|
123
124
|
data = job.result()
|
124
125
|
if job.postfn:
|
125
126
|
data, info = data
|
126
|
-
|
127
|
-
job.active.release()
|
127
|
+
del info
|
128
128
|
data = packlib.pack(data)
|
129
129
|
status = int(0).to_bytes(8, 'little', signed=False)
|
130
130
|
self.socket.send(job.addr, job.reqnum, status, *data)
|
131
131
|
self.metrics['send'] += 1
|
132
132
|
except Exception as e:
|
133
133
|
self._error(job.addr, job.reqnum, 4, f'Error in server method: {e}')
|
134
|
+
finally:
|
135
|
+
if not job.postfn:
|
136
|
+
job.active.release()
|
134
137
|
if completed:
|
135
138
|
while self.postfn_inp and self.postfn_inp[0].done():
|
136
139
|
job = self.postfn_inp.popleft()
|
@@ -149,6 +152,5 @@ class Server:
|
|
149
152
|
self.socket.send(addr, reqnum, status, data)
|
150
153
|
if self.errors:
|
151
154
|
# Wait until the error is delivered to the client and then raise.
|
152
|
-
self.
|
153
|
-
self.socket.close()
|
155
|
+
self.close(internal=True)
|
154
156
|
raise RuntimeError(message)
|
@@ -37,15 +37,16 @@ class ServerSocket:
|
|
37
37
|
|
38
38
|
def __init__(self, port, name='Server', **kwargs):
|
39
39
|
if isinstance(port, str):
|
40
|
-
|
40
|
+
assert '://' not in port, port
|
41
|
+
port = int(port.rsplit(':', 1)[-1])
|
41
42
|
self.name = name
|
42
43
|
self.options = Options(**{**contextlib.context.serverkw, **kwargs})
|
43
44
|
if self.options.ipv6:
|
44
45
|
self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
45
|
-
self.addr = (self.options.host, port, 0, 0)
|
46
|
+
self.addr = (self.options.host or '::', port, 0, 0)
|
46
47
|
else:
|
47
48
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
48
|
-
self.addr = (self.options.host, port)
|
49
|
+
self.addr = (self.options.host or '0.0.0.0', port)
|
49
50
|
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
50
51
|
# self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
51
52
|
self._log(f'Binding to {self.addr[0]}:{self.addr[1]}')
|
@@ -98,10 +98,12 @@ def free_port():
|
|
98
98
|
# Return a port that is currently free. This function is not thread or
|
99
99
|
# process safe, because there is no way to guarantee that the port will still
|
100
100
|
# be free at the time it will be used.
|
101
|
-
|
102
|
-
|
101
|
+
ipv6 = contextlib.context.serverkw.get('ipv6', False)
|
102
|
+
host = contextlib.context.serverkw.get('host', '')
|
103
|
+
if ipv6:
|
104
|
+
family, addr = socket.AF_INET6, (host or '::', 0, 0, 0)
|
103
105
|
else:
|
104
|
-
family, addr = socket.AF_INET, ('
|
106
|
+
family, addr = socket.AF_INET, (host or '0.0.0.0', 0)
|
105
107
|
sock = socket.socket(family, socket.SOCK_STREAM)
|
106
108
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
107
109
|
sock.bind(addr)
|
@@ -23,7 +23,7 @@ class TestBatching:
|
|
23
23
|
return 2 * x
|
24
24
|
server.bind('fn', fn, batch=4)
|
25
25
|
server.start(block=False)
|
26
|
-
client = portal.Client(
|
26
|
+
client = portal.Client(port)
|
27
27
|
futures = [client.fn(x) for x in range(8)]
|
28
28
|
results = [x.result() for x in futures]
|
29
29
|
assert (results == 2 * np.arange(8)).all()
|
@@ -38,7 +38,7 @@ class TestBatching:
|
|
38
38
|
return 2 * x
|
39
39
|
server.bind('fn', fn, batch=4)
|
40
40
|
server.start(block=False)
|
41
|
-
clients = [portal.Client(
|
41
|
+
clients = [portal.Client(port) for _ in range(8)]
|
42
42
|
futures = [x.fn(i) for i, x in enumerate(clients)]
|
43
43
|
results = [x.result() for x in futures]
|
44
44
|
assert (results == 2 * np.arange(8)).all()
|
@@ -53,7 +53,7 @@ class TestBatching:
|
|
53
53
|
return 2 * x
|
54
54
|
server.bind('fn', fn, workers=4, batch=4)
|
55
55
|
server.start(block=False)
|
56
|
-
clients = [portal.Client(
|
56
|
+
clients = [portal.Client(port) for _ in range(32)]
|
57
57
|
futures = [x.fn(i) for i, x in enumerate(clients)]
|
58
58
|
results = [x.result() for x in futures]
|
59
59
|
assert (results == 2 * np.arange(32)).all()
|
@@ -70,14 +70,14 @@ class TestBatching:
|
|
70
70
|
server.start(block=False)
|
71
71
|
|
72
72
|
kwargs = dict(name='ProxyClient', maxinflight=4)
|
73
|
-
proxy_client = portal.Client(
|
73
|
+
proxy_client = portal.Client(inner_port, **kwargs)
|
74
74
|
proxy_server = portal.BatchServer(
|
75
75
|
outer_port, 'ProxyServer', workers=workers)
|
76
76
|
proxy_server.bind(
|
77
77
|
'fn2', lambda x: proxy_client.fn(x).result(), batch=2)
|
78
78
|
proxy_server.start(block=False)
|
79
79
|
|
80
|
-
client = portal.Client(
|
80
|
+
client = portal.Client(outer_port, 'OuterClient')
|
81
81
|
futures = [client.fn2(x) for x in range(16)]
|
82
82
|
results = [future.result() for future in futures]
|
83
83
|
assert (results == 2 * np.arange(16)).all()
|
@@ -102,7 +102,7 @@ class TestBatching:
|
|
102
102
|
server = portal.BatchServer(port)
|
103
103
|
server.bind('fn', lambda x: x, batch=4)
|
104
104
|
server.start(block=False)
|
105
|
-
client = portal.Client(
|
105
|
+
client = portal.Client(port)
|
106
106
|
futures = [client.fn(data) for _ in range(4)]
|
107
107
|
results = [x.result() for x in futures]
|
108
108
|
for result in results:
|
@@ -116,7 +116,7 @@ class TestBatching:
|
|
116
116
|
server = portal.BatchServer(port, errors=False)
|
117
117
|
server.bind('fn', lambda x: x, batch=2)
|
118
118
|
server.start(block=False)
|
119
|
-
client = portal.Client(
|
119
|
+
client = portal.Client(port)
|
120
120
|
future1 = client.fn({'a': np.array(12)})
|
121
121
|
future2 = client.fn(42)
|
122
122
|
with pytest.raises(RuntimeError):
|
@@ -133,12 +133,12 @@ class TestBatching:
|
|
133
133
|
server = portal.BatchServer(port)
|
134
134
|
server.bind('fn', lambda x: 2 * x, batch=4)
|
135
135
|
server.start(block=False)
|
136
|
-
client = portal.Client(
|
136
|
+
client = portal.Client(port, 'Client1', autoconn=False)
|
137
137
|
client.connect()
|
138
138
|
future1 = client.fn(1)
|
139
139
|
future2 = client.fn(2)
|
140
140
|
client.close()
|
141
|
-
client = portal.Client(
|
141
|
+
client = portal.Client(port, 'Client2')
|
142
142
|
future3 = client.fn(3)
|
143
143
|
future4 = client.fn(4)
|
144
144
|
with pytest.raises(portal.Disconnected):
|
@@ -156,7 +156,7 @@ class TestBatching:
|
|
156
156
|
server = portal.BatchServer(port)
|
157
157
|
server.bind('fn', lambda x: 2 * x, batch=2)
|
158
158
|
server.start(block=False)
|
159
|
-
client = portal.Client(
|
159
|
+
client = portal.Client(port, autoconn=False)
|
160
160
|
client.connect()
|
161
161
|
future1 = client.fn(1)
|
162
162
|
server.close()
|
@@ -20,14 +20,14 @@ class TestClient:
|
|
20
20
|
pass
|
21
21
|
server.bind('fn', fn)
|
22
22
|
server.start(block=False)
|
23
|
-
client = portal.Client(
|
23
|
+
client = portal.Client(port)
|
24
24
|
assert client.fn().result() is None
|
25
25
|
client.close()
|
26
26
|
server.close()
|
27
27
|
|
28
28
|
def test_manual_connect(self):
|
29
29
|
port = portal.free_port()
|
30
|
-
client = portal.Client(
|
30
|
+
client = portal.Client(port, autoconn=False)
|
31
31
|
assert not client.connected
|
32
32
|
server = portal.Server(port)
|
33
33
|
server.bind('fn', lambda x: x)
|
@@ -44,7 +44,7 @@ class TestClient:
|
|
44
44
|
server = portal.Server(port)
|
45
45
|
server.bind('fn', lambda x: x)
|
46
46
|
server.start(block=False)
|
47
|
-
client = portal.Client(
|
47
|
+
client = portal.Client(port, autoconn=False)
|
48
48
|
client.connect()
|
49
49
|
assert client.fn(1).result() == 1
|
50
50
|
server.close()
|
@@ -77,7 +77,7 @@ class TestClient:
|
|
77
77
|
results = []
|
78
78
|
|
79
79
|
def client():
|
80
|
-
client = portal.Client(
|
80
|
+
client = portal.Client(port)
|
81
81
|
results.append(client.fn(12).result())
|
82
82
|
client.close()
|
83
83
|
|
@@ -95,7 +95,7 @@ class TestClient:
|
|
95
95
|
server = portal.Server(port)
|
96
96
|
server.bind('fn', lambda x: x)
|
97
97
|
server.start(block=False)
|
98
|
-
client = portal.Client(
|
98
|
+
client = portal.Client(port)
|
99
99
|
future1 = client.fn(1)
|
100
100
|
future2 = client.fn(2)
|
101
101
|
future3 = client.fn(3)
|
@@ -113,7 +113,7 @@ class TestClient:
|
|
113
113
|
return x
|
114
114
|
server.bind('fn', fn)
|
115
115
|
server.start(block=False)
|
116
|
-
client = portal.Client(
|
116
|
+
client = portal.Client(port)
|
117
117
|
future = client.fn(42)
|
118
118
|
with pytest.raises(TimeoutError):
|
119
119
|
future.result(timeout=0)
|
@@ -142,7 +142,7 @@ class TestClient:
|
|
142
142
|
server.bind('fn', fn, workers=4)
|
143
143
|
server.start(block=False)
|
144
144
|
|
145
|
-
client = portal.Client(
|
145
|
+
client = portal.Client(port, maxinflight=2)
|
146
146
|
futures = [client.fn(i) for i in range(16)]
|
147
147
|
results = [x.result() for x in futures]
|
148
148
|
assert results == list(range(16))
|
@@ -155,7 +155,7 @@ class TestClient:
|
|
155
155
|
server = portal.Server(port)
|
156
156
|
server.bind('fn', lambda x: x)
|
157
157
|
server.start(block=False)
|
158
|
-
client = portal.Client(
|
158
|
+
client = portal.Client(port, maxinflight=1)
|
159
159
|
client.fn(1)
|
160
160
|
client.fn(2)
|
161
161
|
future3 = client.fn(3)
|
@@ -175,7 +175,7 @@ class TestClient:
|
|
175
175
|
return x
|
176
176
|
server.bind('fn', fn)
|
177
177
|
server.start(block=False)
|
178
|
-
client = portal.Client(
|
178
|
+
client = portal.Client(port, maxinflight=1)
|
179
179
|
client.fn(1)
|
180
180
|
client.fn(2)
|
181
181
|
time.sleep(0.2)
|
@@ -191,7 +191,7 @@ class TestClient:
|
|
191
191
|
server = portal.Server(port)
|
192
192
|
server.bind('fn', lambda x: x, workers=4)
|
193
193
|
server.start(block=False)
|
194
|
-
client = portal.Client(
|
194
|
+
client = portal.Client(port, maxinflight=8)
|
195
195
|
barrier = threading.Barrier(users)
|
196
196
|
|
197
197
|
def user():
|
@@ -228,7 +228,7 @@ class TestClient:
|
|
228
228
|
server.close()
|
229
229
|
|
230
230
|
def client():
|
231
|
-
client = portal.Client(
|
231
|
+
client = portal.Client(port, maxinflight=2)
|
232
232
|
futures = [client.fn(x) for x in range(5)]
|
233
233
|
results = [x.result() for x in futures]
|
234
234
|
assert results == list(range(5))
|
@@ -265,8 +265,7 @@ class TestClient:
|
|
265
265
|
server.close()
|
266
266
|
|
267
267
|
def client():
|
268
|
-
client = portal.Client(
|
269
|
-
'localhost', port, maxinflight=1, autoconn=True)
|
268
|
+
client = portal.Client(port, maxinflight=1, autoconn=True)
|
270
269
|
assert client.fn(1).result() == 1
|
271
270
|
a.wait()
|
272
271
|
b.wait()
|
@@ -304,8 +303,7 @@ class TestClient:
|
|
304
303
|
server.close()
|
305
304
|
|
306
305
|
def client():
|
307
|
-
client = portal.Client(
|
308
|
-
'localhost', port, maxinflight=1, autoconn=False)
|
306
|
+
client = portal.Client(port, maxinflight=1, autoconn=False)
|
309
307
|
client.connect()
|
310
308
|
assert client.fn(1).result() == 1
|
311
309
|
a.wait()
|
@@ -322,6 +320,26 @@ class TestClient:
|
|
322
320
|
portal.Thread(client),
|
323
321
|
])
|
324
322
|
|
323
|
+
@pytest.mark.parametrize('ipv6', (False, True))
|
324
|
+
@pytest.mark.parametrize('fmt,typ', (
|
325
|
+
('{port}', int),
|
326
|
+
('{port}', str),
|
327
|
+
(':{port}', str),
|
328
|
+
('localhost:{port}', str),
|
329
|
+
('{localhost}:{port}', str),
|
330
|
+
))
|
331
|
+
def test_address_formats(self, fmt, typ, ipv6):
|
332
|
+
port = portal.free_port()
|
333
|
+
server = portal.Server(port, ipv6=ipv6)
|
334
|
+
server.bind('fn', lambda x: x)
|
335
|
+
server.start(block=False)
|
336
|
+
localhost = '::1' if ipv6 else '127.0.0.1'
|
337
|
+
addr = typ(fmt.format(port=port, localhost=localhost))
|
338
|
+
client = portal.Client(addr, ipv6=ipv6)
|
339
|
+
assert client.fn(42).result() == 42
|
340
|
+
client.close()
|
341
|
+
server.close()
|
342
|
+
|
325
343
|
def test_resolver(self):
|
326
344
|
portnum = portal.free_port()
|
327
345
|
|
@@ -24,7 +24,7 @@ class TestServer:
|
|
24
24
|
return 2 * x
|
25
25
|
server.bind('fn', fn)
|
26
26
|
server.start(block=False)
|
27
|
-
client = portal.Client(
|
27
|
+
client = portal.Client(port)
|
28
28
|
future = client.call('fn', 42)
|
29
29
|
assert future.result() == 84
|
30
30
|
client.close()
|
@@ -39,7 +39,7 @@ class TestServer:
|
|
39
39
|
server = Server(port)
|
40
40
|
server.bind('fn', fn)
|
41
41
|
with server:
|
42
|
-
client = portal.Client(
|
42
|
+
client = portal.Client(port)
|
43
43
|
future = client.fn({'foo': np.array(1)})
|
44
44
|
result = future.result()
|
45
45
|
assert result['foo'] == 2
|
@@ -51,7 +51,7 @@ class TestServer:
|
|
51
51
|
server = Server(port)
|
52
52
|
server.bind('fn', lambda data: data)
|
53
53
|
server.start(block=False)
|
54
|
-
clients = [portal.Client(
|
54
|
+
clients = [portal.Client(port) for _ in range(10)]
|
55
55
|
futures = [client.fn(i) for i, client in enumerate(clients)]
|
56
56
|
results = [future.result() for future in futures]
|
57
57
|
assert results == list(range(10))
|
@@ -65,7 +65,7 @@ class TestServer:
|
|
65
65
|
server.bind('add', lambda x, y: x + y)
|
66
66
|
server.bind('sub', lambda x, y: x - y)
|
67
67
|
with server:
|
68
|
-
client = portal.Client(
|
68
|
+
client = portal.Client(port)
|
69
69
|
assert client.add(3, 5).result() == 8
|
70
70
|
assert client.sub(3, 5).result() == -2
|
71
71
|
client.close()
|
@@ -76,7 +76,7 @@ class TestServer:
|
|
76
76
|
server = Server(port, errors=False)
|
77
77
|
server.bind('foo', lambda x: x)
|
78
78
|
server.start(block=False)
|
79
|
-
client = portal.Client(
|
79
|
+
client = portal.Client(port)
|
80
80
|
future = client.bar(42)
|
81
81
|
try:
|
82
82
|
future.result()
|
@@ -99,7 +99,7 @@ class TestServer:
|
|
99
99
|
server.bind('fn', fn)
|
100
100
|
server.start(block=False)
|
101
101
|
|
102
|
-
client = portal.Client(
|
102
|
+
client = portal.Client(port)
|
103
103
|
assert client.fn(1).result() == 1
|
104
104
|
with pytest.raises(RuntimeError):
|
105
105
|
client.fn(2).result()
|
@@ -108,8 +108,9 @@ class TestServer:
|
|
108
108
|
client.close()
|
109
109
|
server.close()
|
110
110
|
|
111
|
+
@pytest.mark.parametrize('repeat', range(3))
|
111
112
|
@pytest.mark.parametrize('Server', SERVERS)
|
112
|
-
def test_server_errors_raise(self, Server):
|
113
|
+
def test_server_errors_raise(self, repeat, Server):
|
113
114
|
port = portal.free_port()
|
114
115
|
|
115
116
|
def server(port):
|
@@ -126,7 +127,7 @@ class TestServer:
|
|
126
127
|
server = portal.Process(server, port, start=True)
|
127
128
|
del os.environ['PYTHONWARNINGS']
|
128
129
|
|
129
|
-
client = portal.Client(
|
130
|
+
client = portal.Client(port)
|
130
131
|
assert client.fn(1).result() == 1
|
131
132
|
assert server.running
|
132
133
|
with pytest.raises((RuntimeError, TimeoutError)):
|
@@ -155,7 +156,7 @@ class TestServer:
|
|
155
156
|
server = Server(port, workers=4)
|
156
157
|
server.bind('fn', workfn, postfn)
|
157
158
|
server.start(block=False)
|
158
|
-
client = portal.Client(
|
159
|
+
client = portal.Client(port)
|
159
160
|
futures = [client.fn(x) for x in range(10)]
|
160
161
|
results = [x.result() for x in futures]
|
161
162
|
server.close()
|
@@ -188,7 +189,7 @@ class TestServer:
|
|
188
189
|
server = Server(port, workers=workers)
|
189
190
|
server.bind('fn', workfn, postfn)
|
190
191
|
server.start(block=False)
|
191
|
-
client = portal.Client(
|
192
|
+
client = portal.Client(port)
|
192
193
|
futures = [client.fn(i) for i in range(20)]
|
193
194
|
[future.result() for future in futures]
|
194
195
|
client.close()
|
@@ -210,7 +211,7 @@ class TestServer:
|
|
210
211
|
server.bind('slow', slow)
|
211
212
|
server.bind('fast', fast)
|
212
213
|
server.start(block=False)
|
213
|
-
client = portal.Client(
|
214
|
+
client = portal.Client(port)
|
214
215
|
slow_future = client.slow(0)
|
215
216
|
fast_future = client.fast(0)
|
216
217
|
assert not slow_future.done()
|
@@ -237,7 +238,7 @@ class TestServer:
|
|
237
238
|
server.bind('slow', slow, workers=1)
|
238
239
|
server.bind('fast', fast, workers=1)
|
239
240
|
server.start(block=False)
|
240
|
-
client = portal.Client(
|
241
|
+
client = portal.Client(port)
|
241
242
|
slow_future = client.slow(0)
|
242
243
|
fast_future = client.fast(0)
|
243
244
|
# Both requests are processed in parallel, so the fast request returns
|
@@ -258,12 +259,12 @@ class TestServer:
|
|
258
259
|
server.start(block=False)
|
259
260
|
|
260
261
|
kwargs = dict(name='ProxyClient', maxinflight=4)
|
261
|
-
proxy_client = portal.Client(
|
262
|
+
proxy_client = portal.Client(inner_port, **kwargs)
|
262
263
|
proxy_server = Server(outer_port, 'ProxyServer', workers=workers)
|
263
264
|
proxy_server.bind('fn2', lambda x: proxy_client.fn(x).result())
|
264
265
|
proxy_server.start(block=False)
|
265
266
|
|
266
|
-
client = portal.Client(
|
267
|
+
client = portal.Client(outer_port, 'OuterClient')
|
267
268
|
futures = [client.fn2(x) for x in range(20)]
|
268
269
|
results = [future.result() for future in futures]
|
269
270
|
assert results == list(range(0, 40, 2))
|
@@ -291,7 +292,7 @@ class TestServer:
|
|
291
292
|
def client(port):
|
292
293
|
data = portal.SharedArray((3, 2), np.float32)
|
293
294
|
data.array[:] = np.arange(6, dtype=np.float32).reshape(3, 2)
|
294
|
-
client = portal.Client(
|
295
|
+
client = portal.Client(port)
|
295
296
|
result = client.call('fn', data).result()
|
296
297
|
assert result.name == data.name
|
297
298
|
assert result, data
|
@@ -320,7 +321,7 @@ class TestServer:
|
|
320
321
|
server.bind('fn', fn)
|
321
322
|
server.start(block=False)
|
322
323
|
|
323
|
-
client = portal.Client(
|
324
|
+
client = portal.Client(port)
|
324
325
|
client.fn(1)
|
325
326
|
barrier.wait()
|
326
327
|
client.close()
|
@@ -328,7 +329,25 @@ class TestServer:
|
|
328
329
|
assert stats['numrecv'] == 1
|
329
330
|
assert stats['numsend'] == 0
|
330
331
|
|
331
|
-
client = portal.Client(
|
332
|
+
client = portal.Client(port)
|
332
333
|
assert client.fn(2).result() == 2
|
333
334
|
client.close()
|
334
335
|
server.close()
|
336
|
+
|
337
|
+
@pytest.mark.parametrize('ipv6', (False, True))
|
338
|
+
@pytest.mark.parametrize('fmt,typ', (
|
339
|
+
('{port}', int),
|
340
|
+
('{port}', str),
|
341
|
+
(':{port}', str),
|
342
|
+
('localhost:{port}', str),
|
343
|
+
('123.456:789:::{port}', str),
|
344
|
+
))
|
345
|
+
def test_port_formats(self, fmt, typ, ipv6):
|
346
|
+
port = portal.free_port()
|
347
|
+
server = portal.Server(typ(fmt.format(port=port)), ipv6=ipv6)
|
348
|
+
server.bind('fn', lambda x: x)
|
349
|
+
server.start(block=False)
|
350
|
+
client = portal.Client(port, ipv6=ipv6)
|
351
|
+
assert client.fn(42).result() == 42
|
352
|
+
client.close()
|
353
|
+
server.close()
|
@@ -6,15 +6,16 @@ import portal
|
|
6
6
|
|
7
7
|
class TestSocket:
|
8
8
|
|
9
|
-
|
9
|
+
@pytest.mark.parametrize('ipv6', (False, True))
|
10
|
+
def test_basic(self, ipv6):
|
10
11
|
port = portal.free_port()
|
11
|
-
server = portal.ServerSocket(port)
|
12
|
-
client = portal.ClientSocket(
|
12
|
+
server = portal.ServerSocket(port, ipv6=ipv6)
|
13
|
+
client = portal.ClientSocket(port, ipv6=ipv6)
|
13
14
|
client.connect()
|
14
15
|
assert client.connected
|
15
16
|
client.send(b'foo')
|
16
17
|
addr, data = server.recv()
|
17
|
-
assert addr[0] == '127.0.0.1'
|
18
|
+
assert addr[0] == '::1' if ipv6 else '127.0.0.1'
|
18
19
|
assert data == b'foo'
|
19
20
|
server.send(addr, b'bar')
|
20
21
|
assert client.recv() == b'bar'
|
@@ -24,7 +25,7 @@ class TestSocket:
|
|
24
25
|
def test_multi_buffer(self):
|
25
26
|
port = portal.free_port()
|
26
27
|
server = portal.ServerSocket(port)
|
27
|
-
client = portal.ClientSocket(
|
28
|
+
client = portal.ClientSocket(port)
|
28
29
|
client.send(b'foo', b'bar', b'baz')
|
29
30
|
addr, data = server.recv()
|
30
31
|
assert data == b'foobarbaz'
|
@@ -36,7 +37,7 @@ class TestSocket:
|
|
36
37
|
def test_multiple_send(self):
|
37
38
|
port = portal.free_port()
|
38
39
|
server = portal.ServerSocket(port)
|
39
|
-
client = portal.ClientSocket(
|
40
|
+
client = portal.ClientSocket(port)
|
40
41
|
client.send(b'foo')
|
41
42
|
client.send(b'ba', b'r')
|
42
43
|
client.send(b'baz')
|
@@ -58,7 +59,7 @@ class TestSocket:
|
|
58
59
|
def test_disconnect_server(self, repeat):
|
59
60
|
port = portal.free_port()
|
60
61
|
server = portal.ServerSocket(port)
|
61
|
-
client = portal.ClientSocket(
|
62
|
+
client = portal.ClientSocket(port, autoconn=False)
|
62
63
|
client.connect()
|
63
64
|
server.close()
|
64
65
|
with pytest.raises(portal.Disconnected):
|
@@ -79,14 +80,14 @@ class TestSocket:
|
|
79
80
|
def test_disconnect_client(self, repeat):
|
80
81
|
port = portal.free_port()
|
81
82
|
server = portal.ServerSocket(port)
|
82
|
-
client = portal.ClientSocket(
|
83
|
+
client = portal.ClientSocket(port)
|
83
84
|
client.send(b'foo')
|
84
85
|
assert server.recv()[1] == b'foo'
|
85
86
|
assert len(server.connections) == 1
|
86
87
|
client.close()
|
87
88
|
time.sleep(0.2)
|
88
89
|
assert len(server.connections) == 0
|
89
|
-
client = portal.ClientSocket(
|
90
|
+
client = portal.ClientSocket(port)
|
90
91
|
time.sleep(0.2)
|
91
92
|
assert len(server.connections) == 1
|
92
93
|
server.close()
|
@@ -107,7 +108,7 @@ class TestSocket:
|
|
107
108
|
|
108
109
|
def client_fn(port, q):
|
109
110
|
client = portal.ClientSocket(
|
110
|
-
|
111
|
+
port,
|
111
112
|
autoconn=False,
|
112
113
|
keepalive_after=1,
|
113
114
|
keepalive_every=1,
|
@@ -154,7 +155,7 @@ class TestSocket:
|
|
154
155
|
|
155
156
|
def client(port):
|
156
157
|
data = bytearray(size)
|
157
|
-
client = portal.ClientSocket(
|
158
|
+
client = portal.ClientSocket(port)
|
158
159
|
for _ in range(prefetch):
|
159
160
|
client.send(data)
|
160
161
|
for _ in range(100):
|
@@ -184,7 +185,7 @@ class TestSocket:
|
|
184
185
|
server.close()
|
185
186
|
|
186
187
|
def client(port):
|
187
|
-
client = portal.ClientSocket(
|
188
|
+
client = portal.ClientSocket(port)
|
188
189
|
client.send(b'foo')
|
189
190
|
assert client.recv() == bytes(1024 ** 2)
|
190
191
|
client.close()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|