zprocess 2.23.0__tar.gz → 2.25.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.
Files changed (56) hide show
  1. {zprocess-2.23.0/zprocess.egg-info → zprocess-2.25.0}/PKG-INFO +10 -1
  2. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/security.py +82 -17
  3. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/tasks.py +8 -0
  4. {zprocess-2.23.0 → zprocess-2.25.0/zprocess.egg-info}/PKG-INFO +10 -1
  5. {zprocess-2.23.0 → zprocess-2.25.0}/.coveragerc +0 -0
  6. {zprocess-2.23.0 → zprocess-2.25.0}/.github/workflows/release.yml +0 -0
  7. {zprocess-2.23.0 → zprocess-2.25.0}/.gitignore +0 -0
  8. {zprocess-2.23.0 → zprocess-2.25.0}/.travis.yml +0 -0
  9. {zprocess-2.23.0 → zprocess-2.25.0}/LICENSE.txt +0 -0
  10. {zprocess-2.23.0 → zprocess-2.25.0}/README.md +0 -0
  11. {zprocess-2.23.0 → zprocess-2.25.0}/doc/Makefile +0 -0
  12. {zprocess-2.23.0 → zprocess-2.25.0}/doc/conf.py +0 -0
  13. {zprocess-2.23.0 → zprocess-2.25.0}/doc/index.rst +0 -0
  14. {zprocess-2.23.0 → zprocess-2.25.0}/doc/requirements.txt +0 -0
  15. {zprocess-2.23.0 → zprocess-2.25.0}/pyproject.toml +0 -0
  16. {zprocess-2.23.0 → zprocess-2.25.0}/requirements.txt +0 -0
  17. {zprocess-2.23.0 → zprocess-2.25.0}/run_tests.py +0 -0
  18. {zprocess-2.23.0 → zprocess-2.25.0}/setup.cfg +0 -0
  19. {zprocess-2.23.0 → zprocess-2.25.0}/setup.py +0 -0
  20. {zprocess-2.23.0 → zprocess-2.25.0}/tests/GUI_output_redirection.py +0 -0
  21. {zprocess-2.23.0 → zprocess-2.25.0}/tests/output_redirection.py +0 -0
  22. {zprocess-2.23.0 → zprocess-2.25.0}/tests/test_remote.py +0 -0
  23. {zprocess-2.23.0 → zprocess-2.25.0}/tests/test_zlock_server.py +0 -0
  24. {zprocess-2.23.0 → zprocess-2.25.0}/tests/test_zlog_server.py +0 -0
  25. {zprocess-2.23.0 → zprocess-2.25.0}/tests/tests.py +0 -0
  26. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/__init__.py +0 -0
  27. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/__version__.py +0 -0
  28. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/clientserver.py +0 -0
  29. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/cryptoproxy.py +0 -0
  30. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/examples/example_child.py +0 -0
  31. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/examples/example_parent.py +0 -0
  32. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/examples/processclass_example.py +0 -0
  33. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/examples/processclass_remote_example.py +0 -0
  34. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/locking/__init__.py +0 -0
  35. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/locking/__main__.py +0 -0
  36. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/makesecret.py +0 -0
  37. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/process_class_wrapper.py +0 -0
  38. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/process_tree.py +0 -0
  39. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/remote/__init__.py +0 -0
  40. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/remote/__main__.py +0 -0
  41. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/remote/curses_server.py +0 -0
  42. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/remote/server.py +0 -0
  43. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/socks/__init__.py +0 -0
  44. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/socks/server.py +0 -0
  45. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/utils.py +0 -0
  46. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/zlock/__init__.py +0 -0
  47. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/zlock/__main__.py +0 -0
  48. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/zlock/server.py +0 -0
  49. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/zlog/__init__.py +0 -0
  50. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/zlog/__main__.py +0 -0
  51. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess/zlog/server.py +0 -0
  52. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess.egg-info/SOURCES.txt +0 -0
  53. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess.egg-info/dependency_links.txt +0 -0
  54. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess.egg-info/not-zip-safe +0 -0
  55. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess.egg-info/requires.txt +0 -0
  56. {zprocess-2.23.0 → zprocess-2.25.0}/zprocess.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zprocess
3
- Version: 2.23.0
3
+ Version: 2.25.0
4
4
  Summary: A set of utilities for multiprocessing using zeromq.
5
5
  Home-page: http://github.com/chrisjbillington/zprocess
6
6
  Author: Chris Billington
@@ -9,6 +9,15 @@ License: BSD
9
9
  Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5
10
10
  Description-Content-Type: text/markdown
11
11
  License-File: LICENSE.txt
12
+ Requires-Dist: pyzmq>=18.0
13
+ Requires-Dist: ipaddress; python_version == "2.7"
14
+ Requires-Dist: subprocess32; python_version == "2.7"
15
+ Requires-Dist: enum34; python_version == "2.7"
16
+ Requires-Dist: pathlib; python_version == "2.7"
17
+ Requires-Dist: pywin32; sys_platform == "win32"
18
+ Requires-Dist: windows-curses; sys_platform == "win32"
19
+ Requires-Dist: importlib_metadata; python_version < "3.8"
20
+ Requires-Dist: setuptools_scm>=4.1.0
12
21
 
13
22
  # zprocess
14
23
 
@@ -3,6 +3,7 @@ import sys
3
3
  import base64
4
4
  import weakref
5
5
  import os
6
+ import threading
6
7
  import ipaddress
7
8
  import zmq
8
9
  import zmq.auth.thread
@@ -24,6 +25,7 @@ if sys.version_info[0] == 2:
24
25
  else:
25
26
  from time import monotonic
26
27
 
28
+ PYZMQ_VER_MAJOR = int(zmq.__version__.split('.')[0])
27
29
 
28
30
  _bundle_warning = """zprocess warning: pyzmq is using bundled libzmq, which on Windows
29
31
  is not built with the cryptography library libsodium. Encryption/decryption will be
@@ -165,9 +167,10 @@ class SecureSocket(zmq.Socket):
165
167
  are a server or not"""
166
168
  orig_server = self.curve_server
167
169
  if server:
170
+ self.curve_server = True
171
+ self.zap_domain = self.context.zap_domain
168
172
  self.curve_publickey = self.context.server_publickey
169
173
  self.curve_secretkey = self.context.server_secretkey
170
- self.curve_server = True
171
174
  else:
172
175
  self.curve_server = False
173
176
  self.curve_publickey = self.context.client_publickey
@@ -306,6 +309,72 @@ class SecureSocket(zmq.Socket):
306
309
  return msg
307
310
 
308
311
 
312
+ class _ThreadAuthenticator:
313
+ # We roll our own thread authenticator (just implementing what we need) since a)
314
+ # zmq.auth.thread.ThreadAuthenticator uses asyncio, and we do not want to express an
315
+ # opinion on the kerfuffle that is Windows asyncio selectors (see:
316
+ # https://github.com/zeromq/pyzmq/issues/1423) and impose it on the rest of the
317
+ # interpreter, when we're not even using async stuff ourself and b)
318
+ # zmq.auth.thread.ThreadAuthenticator spawns a non-daemon thread which is difficult
319
+ # to ensure gets shut down at interpreter shutdown, and otherwise holds the
320
+ # interpreter open.
321
+ def __init__(self, ctx, zap_domain, allowed_clients):
322
+ if PYZMQ_VER_MAJOR >= 25:
323
+ self.zap_socket = ctx.socket(zmq.REP, socket_class=zmq.Socket)
324
+ else:
325
+ self.zap_socket = ctx.socket(zmq.REP)
326
+ self.zap_socket.linger = 1
327
+ self.zap_socket.bind("inproc://zeromq.zap.01")
328
+
329
+ # Note: we hold a reference to the zap socket, since if the thread crashes, we
330
+ # don't want the socket to be cleaned up and closed - that would have zmq
331
+ # (stupidly and dangerously) fall back to its default authentication method,
332
+ # which is to allow all.
333
+ self.thread = threading.Thread(
334
+ target=self.run,
335
+ args=(self.zap_socket, zap_domain, allowed_clients),
336
+ daemon=True,
337
+ )
338
+ self.started = threading.Event()
339
+ self.thread.start()
340
+
341
+ def run(self, zap_socket, zap_domain, allowed_clients):
342
+ VERSION = b'1.0'
343
+ MECHANISM = b'CURVE'
344
+ while True:
345
+ try:
346
+ msg = zap_socket.recv_multipart()
347
+ except zmq.error.ContextTerminated:
348
+ zap_socket.close()
349
+ return
350
+ version, request_id, domain, address, identity, mechanism = msg[:6]
351
+ credentials = msg[6:]
352
+ if version != VERSION:
353
+ status_code = b"400"
354
+ status_text = b"Invalid version"
355
+ user_id = b""
356
+ elif mechanism != MECHANISM:
357
+ status_code = b"400"
358
+ status_text = b"Security mechanism not supported"
359
+ user_id = b""
360
+ elif domain != zap_domain:
361
+ status_code = b"400"
362
+ status_text = b"Unknown domain"
363
+ user_id = b""
364
+ else:
365
+ key = zmq.utils.z85.encode(credentials[0])
366
+ if key in allowed_clients:
367
+ status_code = b"200"
368
+ status_text = b"OK"
369
+ user_id = key
370
+ else:
371
+ status_code = b"400"
372
+ status_text = b"Unknown key"
373
+ user_id = b""
374
+ response = [VERSION, request_id, status_code, status_text, user_id, b""]
375
+ zap_socket.send_multipart(response)
376
+
377
+
309
378
  class SecureContext(zmq.Context):
310
379
  """A ZeroMQ Context with SecureContext.socket() returning a
311
380
  SecureSocket(), which can authenticate and communicate securely with all
@@ -315,7 +384,10 @@ class SecureContext(zmq.Context):
315
384
 
316
385
  _socket_class = SecureSocket
317
386
  _instances = weakref.WeakValueDictionary()
387
+ zap_domain = b"zprocess"
388
+
318
389
  # Dummy class attrs to distinguish from zmq options:
390
+ auth = None
319
391
  secure = False
320
392
  client_publickey = None
321
393
  client_secretkey = None
@@ -331,22 +403,15 @@ class SecureContext(zmq.Context):
331
403
  self.client_publickey = zmq.curve_public(self.client_secretkey)
332
404
  self.server_publickey = zmq.curve_public(self.server_secretkey)
333
405
 
334
- # There are potential reference cycles causing the authentication thread to
335
- # prevent the interpreter from shutting down. In pyzmq <25, the
336
- # authentication thread holds a reference to the context. So we must avoid
337
- # holding a reference to it. In pyzmq 25+, the authentication thread and
338
- # threadauthenticator objects both hold references to each other. So we
339
- # replace one with a weakref to break the cycle.
340
-
341
- auth = zmq.auth.thread.ThreadAuthenticator(self)
342
- auth.start()
343
-
344
- if auth.thread.authenticator is auth:
345
- auth.thread.authenticator = weakref.proxy(auth)
346
-
347
- # Allow only clients who have the client public key:
348
- auth.allow_any = False
349
- auth.certs['*'] = {self.client_publickey: True}
406
+ # Note: it is crucial we hold a reference to the authenticator, so that in
407
+ # the case the zap authentication thread crashes, the zap socket does not
408
+ # get cleaned up and closed - zmq will interpret that situation as us not
409
+ # requiring any authentication.
410
+ self.auth = _ThreadAuthenticator(
411
+ self,
412
+ zap_domain=self.zap_domain,
413
+ allowed_clients=[self.client_publickey],
414
+ )
350
415
  self.secure = True
351
416
 
352
417
  @classmethod
@@ -42,6 +42,7 @@ import copy
42
42
 
43
43
 
44
44
  class Task(object):
45
+ _next_id = 0
45
46
  def __init__(self, due_in, func, *args, **kwargs):
46
47
  """Wrapper for a function call to be executed after a specified time interval.
47
48
  `due_in` is how long in the future, in seconds, the function should be called,
@@ -56,6 +57,8 @@ class Task(object):
56
57
  self.kwargs = kwargs
57
58
  self._called = False
58
59
  self.repeat = False
60
+ self._id = self._next_id
61
+ Task._next_id += 1
59
62
 
60
63
  def due_in(self):
61
64
  """The time interval in seconds until the task is due"""
@@ -72,6 +75,9 @@ class Task(object):
72
75
  # insort() and pop() as used with TaskQueue.
73
76
  return self.due_at < other.due_at
74
77
 
78
+ def __eq__(self, other):
79
+ return isinstance(other, Task) and self._id == other._id
80
+
75
81
 
76
82
  class TaskQueue(list):
77
83
  """A list of pending tasks due at certain times. Tasks are stored with the soonest
@@ -96,6 +102,8 @@ class TaskQueue(list):
96
102
  be re-added to the queue after it is removed via a call to `TaskQueue.pop()`."""
97
103
  if repeat is not None:
98
104
  task.repeat = repeat
105
+ # Re-adding an already-called task resets it
106
+ task._called = False
99
107
  insort(self, task)
100
108
 
101
109
  def next(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zprocess
3
- Version: 2.23.0
3
+ Version: 2.25.0
4
4
  Summary: A set of utilities for multiprocessing using zeromq.
5
5
  Home-page: http://github.com/chrisjbillington/zprocess
6
6
  Author: Chris Billington
@@ -9,6 +9,15 @@ License: BSD
9
9
  Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5
10
10
  Description-Content-Type: text/markdown
11
11
  License-File: LICENSE.txt
12
+ Requires-Dist: pyzmq>=18.0
13
+ Requires-Dist: ipaddress; python_version == "2.7"
14
+ Requires-Dist: subprocess32; python_version == "2.7"
15
+ Requires-Dist: enum34; python_version == "2.7"
16
+ Requires-Dist: pathlib; python_version == "2.7"
17
+ Requires-Dist: pywin32; sys_platform == "win32"
18
+ Requires-Dist: windows-curses; sys_platform == "win32"
19
+ Requires-Dist: importlib_metadata; python_version < "3.8"
20
+ Requires-Dist: setuptools_scm>=4.1.0
12
21
 
13
22
  # zprocess
14
23
 
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