portal 3.2.4__tar.gz → 3.4.1__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.
Files changed (35) hide show
  1. {portal-3.2.4/portal.egg-info → portal-3.4.1}/PKG-INFO +1 -1
  2. {portal-3.2.4 → portal-3.4.1}/portal/__init__.py +1 -1
  3. {portal-3.2.4 → portal-3.4.1}/portal/batching.py +1 -1
  4. {portal-3.2.4 → portal-3.4.1}/portal/client.py +2 -4
  5. {portal-3.2.4 → portal-3.4.1}/portal/client_socket.py +26 -22
  6. {portal-3.2.4 → portal-3.4.1}/portal/contextlib.py +5 -2
  7. {portal-3.2.4 → portal-3.4.1}/portal/server.py +9 -7
  8. {portal-3.2.4 → portal-3.4.1}/portal/server_socket.py +7 -5
  9. {portal-3.2.4 → portal-3.4.1}/portal/utils.py +5 -3
  10. {portal-3.2.4 → portal-3.4.1/portal.egg-info}/PKG-INFO +1 -1
  11. {portal-3.2.4 → portal-3.4.1}/tests/test_batching.py +10 -10
  12. {portal-3.2.4 → portal-3.4.1}/tests/test_client.py +33 -15
  13. {portal-3.2.4 → portal-3.4.1}/tests/test_server.py +36 -17
  14. {portal-3.2.4 → portal-3.4.1}/tests/test_socket.py +13 -12
  15. {portal-3.2.4 → portal-3.4.1}/LICENSE +0 -0
  16. {portal-3.2.4 → portal-3.4.1}/MANIFEST.in +0 -0
  17. {portal-3.2.4 → portal-3.4.1}/README.md +0 -0
  18. {portal-3.2.4 → portal-3.4.1}/portal/buffers.py +0 -0
  19. {portal-3.2.4 → portal-3.4.1}/portal/packlib.py +0 -0
  20. {portal-3.2.4 → portal-3.4.1}/portal/poollib.py +0 -0
  21. {portal-3.2.4 → portal-3.4.1}/portal/process.py +0 -0
  22. {portal-3.2.4 → portal-3.4.1}/portal/sharray.py +0 -0
  23. {portal-3.2.4 → portal-3.4.1}/portal/thread.py +0 -0
  24. {portal-3.2.4 → portal-3.4.1}/portal.egg-info/SOURCES.txt +0 -0
  25. {portal-3.2.4 → portal-3.4.1}/portal.egg-info/dependency_links.txt +0 -0
  26. {portal-3.2.4 → portal-3.4.1}/portal.egg-info/requires.txt +0 -0
  27. {portal-3.2.4 → portal-3.4.1}/portal.egg-info/top_level.txt +0 -0
  28. {portal-3.2.4 → portal-3.4.1}/pyproject.toml +0 -0
  29. {portal-3.2.4 → portal-3.4.1}/requirements.txt +0 -0
  30. {portal-3.2.4 → portal-3.4.1}/setup.cfg +0 -0
  31. {portal-3.2.4 → portal-3.4.1}/setup.py +0 -0
  32. {portal-3.2.4 → portal-3.4.1}/tests/test_errfile.py +0 -0
  33. {portal-3.2.4 → portal-3.4.1}/tests/test_pack.py +0 -0
  34. {portal-3.2.4 → portal-3.4.1}/tests/test_process.py +0 -0
  35. {portal-3.2.4 → portal-3.4.1}/tests/test_thread.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: portal
3
- Version: 3.2.4
3
+ Version: 3.4.1
4
4
  Summary: Fast and reliable distributed systems in Python
5
5
  Home-page: http://github.com/danijar/portal
6
6
  Author: Danijar Hafner
@@ -1,4 +1,4 @@
1
- __version__ = '3.2.4'
1
+ __version__ = '3.4.1'
2
2
 
3
3
  import multiprocessing as mp
4
4
  try:
@@ -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('localhost', inner_port, f'{name}Client', **kwargs)
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, host, port=None, name='Client', start=True, **kwargs):
37
- assert port or ':' in host, (host, port)
38
- assert '://' not in host, (host, port)
39
- if port is None:
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 = []
@@ -203,35 +203,39 @@ class ClientSocket:
203
203
  error = e
204
204
  except socket.gaierror as e:
205
205
  error = e
206
- time.sleep(0.1)
207
206
  if once:
208
207
  self._log(f'Still trying to connect... ({error})')
209
208
  once = False
210
209
  sock.close()
210
+ time.sleep(self.options.connect_wait)
211
211
  return None
212
212
 
213
213
  def _create(self):
214
214
  if self.options.ipv6:
215
215
  sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
216
+ sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
216
217
  else:
217
218
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
218
- # sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
219
+ # sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # TODO
220
+
219
221
  after = self.options.keepalive_after
220
222
  every = self.options.keepalive_every
221
223
  fails = self.options.keepalive_fails
222
- if sys.platform == 'linux':
223
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
224
- sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after)
225
- sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, every)
226
- sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, fails)
227
- sock.setsockopt(
228
- socket.IPPROTO_TCP, socket.TCP_USER_TIMEOUT,
229
- 1000 * (after + every * fails))
230
- if sys.platform == 'darwin':
231
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
232
- sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPALIVE, every)
233
- if sys.platform == 'win32':
234
- sock.ioctl(socket.SIO_KEEPALIVE_VALS, (1, after * 1000, every * 1000))
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):
@@ -21,10 +21,13 @@ class Context:
21
21
  self.interval = 20
22
22
  self.clientkw = {}
23
23
  self.serverkw = {}
24
+ self.printlock = threading.Lock()
24
25
  self.done = threading.Event()
25
26
  self.watcher = None
26
- self.mp = mp.get_context()
27
- self.printlock = self.mp.Lock()
27
+
28
+ @property
29
+ def mp(self):
30
+ return mp.get_context('spawn')
28
31
 
29
32
  def options(self):
30
33
  return {
@@ -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
- self.loop.join(timeout)
55
- self.loop.kill()
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
- else:
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.socket.shutdown()
153
- self.socket.close()
155
+ self.close(internal=True)
154
156
  raise RuntimeError(message)
@@ -37,21 +37,23 @@ class ServerSocket:
37
37
 
38
38
  def __init__(self, port, name='Server', **kwargs):
39
39
  if isinstance(port, str):
40
- port = int(port.rsplit(':', 1)[1])
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.sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
47
+ self.addr = (self.options.host or '::', port, 0, 0)
46
48
  else:
47
49
  self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
48
- self.addr = (self.options.host, port)
50
+ self.addr = (self.options.host or '0.0.0.0', port)
49
51
  self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
50
- # self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
52
+ # self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # TODO
51
53
  self._log(f'Binding to {self.addr[0]}:{self.addr[1]}')
52
54
  self.sock.bind(self.addr)
53
55
  self.sock.setblocking(False)
54
- self.sock.listen()
56
+ self.sock.listen(8192)
55
57
  self.sel = selectors.DefaultSelector()
56
58
  self.sel.register(self.sock, selectors.EVENT_READ, data=None)
57
59
  self._log(f'Listening at {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
- if contextlib.context.serverkw.get('ipv6', False):
102
- family, addr = socket.AF_INET6, ('localhost', 0, 0, 0)
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, ('localhost', 0)
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: portal
3
- Version: 3.2.4
3
+ Version: 3.4.1
4
4
  Summary: Fast and reliable distributed systems in Python
5
5
  Home-page: http://github.com/danijar/portal
6
6
  Author: Danijar Hafner
@@ -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('localhost', port)
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('localhost', port) for _ in range(8)]
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('localhost', port) for _ in range(32)]
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('localhost', inner_port, **kwargs)
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('localhost', outer_port, 'OuterClient')
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('localhost', port)
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('localhost', port)
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('localhost', port, name='Client1', autoconn=False)
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('localhost', port, name='Client2')
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('localhost', port, autoconn=False)
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('localhost', port)
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('localhost', port, autoconn=False)
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('localhost', port, autoconn=False)
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('localhost', port)
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('localhost', port)
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('localhost', port)
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('localhost', port, maxinflight=2)
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('localhost', port, maxinflight=1)
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('localhost', port, maxinflight=1)
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('localhost', port, maxinflight=8)
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('localhost', port, maxinflight=2)
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('localhost', port)
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('localhost', port)
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('localhost', port) for _ in range(10)]
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('localhost', port)
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('localhost', port)
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('localhost', port)
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('localhost', port)
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('localhost', port)
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('localhost', port)
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('localhost', port)
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('localhost', port)
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('localhost', inner_port, **kwargs)
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('localhost', outer_port, 'OuterClient')
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('localhost', port)
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('localhost', port)
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('localhost', port)
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
- def test_basic(self):
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('localhost', port)
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('localhost', port)
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('localhost', port)
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('localhost', port, autoconn=False)
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('localhost', port)
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('localhost', port)
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
- 'localhost', port,
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('localhost', port)
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('localhost', port)
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