koichi12 commited on
Commit
ec07269
·
verified ·
1 Parent(s): 9112421

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .venv/lib/python3.11/site-packages/zmq/backend/__init__.py +34 -0
  2. .venv/lib/python3.11/site-packages/zmq/backend/__init__.pyi +122 -0
  3. .venv/lib/python3.11/site-packages/zmq/backend/__pycache__/__init__.cpython-311.pyc +0 -0
  4. .venv/lib/python3.11/site-packages/zmq/backend/__pycache__/select.cpython-311.pyc +0 -0
  5. .venv/lib/python3.11/site-packages/zmq/backend/cffi/README.md +1 -0
  6. .venv/lib/python3.11/site-packages/zmq/backend/cffi/__init__.py +35 -0
  7. .venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/__init__.cpython-311.pyc +0 -0
  8. .venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/_poll.cpython-311.pyc +0 -0
  9. .venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/context.cpython-311.pyc +0 -0
  10. .venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/devices.cpython-311.pyc +0 -0
  11. .venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/error.cpython-311.pyc +0 -0
  12. .venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/message.cpython-311.pyc +0 -0
  13. .venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/socket.cpython-311.pyc +0 -0
  14. .venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/utils.cpython-311.pyc +0 -0
  15. .venv/lib/python3.11/site-packages/zmq/backend/cffi/_cdefs.h +91 -0
  16. .venv/lib/python3.11/site-packages/zmq/backend/cffi/_cffi_src.c +50 -0
  17. .venv/lib/python3.11/site-packages/zmq/backend/cffi/_poll.py +92 -0
  18. .venv/lib/python3.11/site-packages/zmq/backend/cffi/context.py +77 -0
  19. .venv/lib/python3.11/site-packages/zmq/backend/cffi/devices.py +63 -0
  20. .venv/lib/python3.11/site-packages/zmq/backend/cffi/error.py +20 -0
  21. .venv/lib/python3.11/site-packages/zmq/backend/cffi/message.py +222 -0
  22. .venv/lib/python3.11/site-packages/zmq/backend/cffi/socket.py +368 -0
  23. .venv/lib/python3.11/site-packages/zmq/backend/cffi/utils.py +78 -0
  24. .venv/lib/python3.11/site-packages/zmq/backend/cython/__init__.pxd +1 -0
  25. .venv/lib/python3.11/site-packages/zmq/backend/cython/__init__.py +15 -0
  26. .venv/lib/python3.11/site-packages/zmq/backend/cython/__pycache__/__init__.cpython-311.pyc +0 -0
  27. .venv/lib/python3.11/site-packages/zmq/backend/cython/__pycache__/_zmq.cpython-311.pyc +0 -0
  28. .venv/lib/python3.11/site-packages/zmq/backend/cython/_externs.pxd +13 -0
  29. .venv/lib/python3.11/site-packages/zmq/backend/cython/_zmq.pxd +50 -0
  30. .venv/lib/python3.11/site-packages/zmq/backend/cython/_zmq.py +1958 -0
  31. .venv/lib/python3.11/site-packages/zmq/backend/cython/constant_enums.pxi +250 -0
  32. .venv/lib/python3.11/site-packages/zmq/backend/cython/libzmq.pxd +122 -0
  33. .venv/lib/python3.11/site-packages/zmq/backend/select.py +41 -0
  34. .venv/lib/python3.11/site-packages/zmq/eventloop/__init__.py +5 -0
  35. .venv/lib/python3.11/site-packages/zmq/eventloop/__pycache__/__init__.cpython-311.pyc +0 -0
  36. .venv/lib/python3.11/site-packages/zmq/eventloop/__pycache__/_deprecated.cpython-311.pyc +0 -0
  37. .venv/lib/python3.11/site-packages/zmq/eventloop/__pycache__/future.cpython-311.pyc +0 -0
  38. .venv/lib/python3.11/site-packages/zmq/eventloop/__pycache__/ioloop.cpython-311.pyc +0 -0
  39. .venv/lib/python3.11/site-packages/zmq/eventloop/__pycache__/zmqstream.cpython-311.pyc +0 -0
  40. .venv/lib/python3.11/site-packages/zmq/eventloop/_deprecated.py +211 -0
  41. .venv/lib/python3.11/site-packages/zmq/eventloop/future.py +104 -0
  42. .venv/lib/python3.11/site-packages/zmq/eventloop/ioloop.py +37 -0
  43. .venv/lib/python3.11/site-packages/zmq/eventloop/zmqstream.py +689 -0
  44. .venv/lib/python3.11/site-packages/zmq/green/__init__.py +48 -0
  45. .venv/lib/python3.11/site-packages/zmq/green/__pycache__/__init__.cpython-311.pyc +0 -0
  46. .venv/lib/python3.11/site-packages/zmq/green/__pycache__/core.cpython-311.pyc +0 -0
  47. .venv/lib/python3.11/site-packages/zmq/green/__pycache__/device.cpython-311.pyc +0 -0
  48. .venv/lib/python3.11/site-packages/zmq/green/__pycache__/poll.cpython-311.pyc +0 -0
  49. .venv/lib/python3.11/site-packages/zmq/green/core.py +317 -0
  50. .venv/lib/python3.11/site-packages/zmq/green/device.py +34 -0
.venv/lib/python3.11/site-packages/zmq/backend/__init__.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Import basic exposure of libzmq C API as a backend"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ import os
7
+ import platform
8
+
9
+ from .select import public_api, select_backend
10
+
11
+ if 'PYZMQ_BACKEND' in os.environ:
12
+ backend = os.environ['PYZMQ_BACKEND']
13
+ if backend in ('cython', 'cffi'):
14
+ backend = f'zmq.backend.{backend}'
15
+ _ns = select_backend(backend)
16
+ else:
17
+ # default to cython, fallback to cffi
18
+ # (reverse on PyPy)
19
+ if platform.python_implementation() == 'PyPy':
20
+ first, second = ('zmq.backend.cffi', 'zmq.backend.cython')
21
+ else:
22
+ first, second = ('zmq.backend.cython', 'zmq.backend.cffi')
23
+
24
+ try:
25
+ _ns = select_backend(first)
26
+ except Exception as original_error:
27
+ try:
28
+ _ns = select_backend(second)
29
+ except ImportError:
30
+ raise original_error from None
31
+
32
+ globals().update(_ns)
33
+
34
+ __all__ = public_api
.venv/lib/python3.11/site-packages/zmq/backend/__init__.pyi ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, Callable, List, Optional, Set, Tuple, TypeVar, Union, overload
2
+
3
+ from typing_extensions import Literal
4
+
5
+ import zmq
6
+
7
+ from .select import select_backend
8
+
9
+ # avoid collision in Frame.bytes
10
+ _bytestr = bytes
11
+
12
+ T = TypeVar("T")
13
+
14
+ class Frame:
15
+ buffer: Any
16
+ bytes: bytes
17
+ more: bool
18
+ tracker: Any
19
+ def __init__(
20
+ self,
21
+ data: Any = None,
22
+ track: bool = False,
23
+ copy: bool | None = None,
24
+ copy_threshold: int | None = None,
25
+ ): ...
26
+ def copy_fast(self: T) -> T: ...
27
+ def get(self, option: int) -> int | _bytestr | str: ...
28
+ def set(self, option: int, value: int | _bytestr | str) -> None: ...
29
+
30
+ class Socket:
31
+ underlying: int
32
+ context: zmq.Context
33
+ copy_threshold: int
34
+
35
+ # specific option types
36
+ FD: int
37
+
38
+ def __init__(
39
+ self,
40
+ context: Context | None = None,
41
+ socket_type: int = 0,
42
+ shadow: int = 0,
43
+ copy_threshold: int | None = zmq.COPY_THRESHOLD,
44
+ ) -> None: ...
45
+ def close(self, linger: int | None = ...) -> None: ...
46
+ def get(self, option: int) -> int | bytes | str: ...
47
+ def set(self, option: int, value: int | bytes | str) -> None: ...
48
+ def connect(self, url: str): ...
49
+ def disconnect(self, url: str) -> None: ...
50
+ def bind(self, url: str): ...
51
+ def unbind(self, url: str) -> None: ...
52
+ def send(
53
+ self,
54
+ data: Any,
55
+ flags: int = ...,
56
+ copy: bool = ...,
57
+ track: bool = ...,
58
+ ) -> zmq.MessageTracker | None: ...
59
+ @overload
60
+ def recv(
61
+ self,
62
+ flags: int = ...,
63
+ *,
64
+ copy: Literal[False],
65
+ track: bool = ...,
66
+ ) -> zmq.Frame: ...
67
+ @overload
68
+ def recv(
69
+ self,
70
+ flags: int = ...,
71
+ *,
72
+ copy: Literal[True],
73
+ track: bool = ...,
74
+ ) -> bytes: ...
75
+ @overload
76
+ def recv(
77
+ self,
78
+ flags: int = ...,
79
+ track: bool = False,
80
+ ) -> bytes: ...
81
+ @overload
82
+ def recv(
83
+ self,
84
+ flags: int | None = ...,
85
+ copy: bool = ...,
86
+ track: bool | None = False,
87
+ ) -> zmq.Frame | bytes: ...
88
+ def monitor(self, addr: str | None, events: int) -> None: ...
89
+ # draft methods
90
+ def join(self, group: str) -> None: ...
91
+ def leave(self, group: str) -> None: ...
92
+
93
+ class Context:
94
+ underlying: int
95
+ def __init__(self, io_threads: int = 1, shadow: int = 0): ...
96
+ def get(self, option: int) -> int | bytes | str: ...
97
+ def set(self, option: int, value: int | bytes | str) -> None: ...
98
+ def socket(self, socket_type: int) -> Socket: ...
99
+ def term(self) -> None: ...
100
+
101
+ IPC_PATH_MAX_LEN: int
102
+
103
+ def has(capability: str) -> bool: ...
104
+ def curve_keypair() -> tuple[bytes, bytes]: ...
105
+ def curve_public(secret_key: bytes) -> bytes: ...
106
+ def strerror(errno: int | None = ...) -> str: ...
107
+ def zmq_errno() -> int: ...
108
+ def zmq_version() -> str: ...
109
+ def zmq_version_info() -> tuple[int, int, int]: ...
110
+ def zmq_poll(
111
+ sockets: list[Any], timeout: int | None = ...
112
+ ) -> list[tuple[Socket, int]]: ...
113
+ def device(device_type: int, frontend: Socket, backend: Socket | None = ...) -> int: ...
114
+ def proxy(frontend: Socket, backend: Socket, capture: Socket | None = None) -> int: ...
115
+ def proxy_steerable(
116
+ frontend: Socket,
117
+ backend: Socket,
118
+ capture: Socket | None = ...,
119
+ control: Socket | None = ...,
120
+ ) -> int: ...
121
+
122
+ monitored_queue = Callable | None
.venv/lib/python3.11/site-packages/zmq/backend/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (1.25 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/__pycache__/select.cpython-311.pyc ADDED
Binary file (1.52 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cffi/README.md ADDED
@@ -0,0 +1 @@
 
 
1
+ PyZMQ's CFFI support is designed only for (Unix) systems conforming to `have_sys_un_h = True`.
.venv/lib/python3.11/site-packages/zmq/backend/cffi/__init__.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """CFFI backend (for PyPy)"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ from zmq.backend.cffi import _poll, context, devices, error, message, socket, utils
7
+
8
+ from ._cffi import ffi
9
+ from ._cffi import lib as C
10
+
11
+
12
+ def zmq_version_info():
13
+ """Get libzmq version as tuple of ints"""
14
+ major = ffi.new('int*')
15
+ minor = ffi.new('int*')
16
+ patch = ffi.new('int*')
17
+
18
+ C.zmq_version(major, minor, patch)
19
+
20
+ return (int(major[0]), int(minor[0]), int(patch[0]))
21
+
22
+
23
+ __all__ = ["zmq_version_info"]
24
+ for submod in (error, message, context, socket, _poll, devices, utils):
25
+ __all__.extend(submod.__all__)
26
+
27
+ from ._poll import *
28
+ from .context import *
29
+ from .devices import *
30
+ from .error import *
31
+ from .message import *
32
+ from .socket import *
33
+ from .utils import *
34
+
35
+ monitored_queue = None
.venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (1.48 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/_poll.cpython-311.pyc ADDED
Binary file (3.82 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/context.cpython-311.pyc ADDED
Binary file (3.33 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/devices.cpython-311.pyc ADDED
Binary file (2.19 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/error.cpython-311.pyc ADDED
Binary file (783 Bytes). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/message.cpython-311.pyc ADDED
Binary file (9.03 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/socket.cpython-311.pyc ADDED
Binary file (17.9 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cffi/__pycache__/utils.cpython-311.pyc ADDED
Binary file (3.35 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cffi/_cdefs.h ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ void zmq_version(int *major, int *minor, int *patch);
2
+
3
+ void* zmq_socket(void *context, int type);
4
+ int zmq_close(void *socket);
5
+
6
+ int zmq_bind(void *socket, const char *endpoint);
7
+ int zmq_connect(void *socket, const char *endpoint);
8
+
9
+ int zmq_errno(void);
10
+ const char * zmq_strerror(int errnum);
11
+
12
+ int zmq_device(int device, void *frontend, void *backend);
13
+
14
+ int zmq_unbind(void *socket, const char *endpoint);
15
+ int zmq_disconnect(void *socket, const char *endpoint);
16
+ void* zmq_ctx_new();
17
+ int zmq_ctx_destroy(void *context);
18
+ int zmq_ctx_get(void *context, int opt);
19
+ int zmq_ctx_set(void *context, int opt, int optval);
20
+ int zmq_proxy(void *frontend, void *backend, void *capture);
21
+ int zmq_proxy_steerable(void *frontend,
22
+ void *backend,
23
+ void *capture,
24
+ void *control);
25
+ int zmq_socket_monitor(void *socket, const char *addr, int events);
26
+
27
+ int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key);
28
+ int zmq_curve_public (char *z85_public_key, char *z85_secret_key);
29
+ int zmq_has (const char *capability);
30
+
31
+ typedef struct { ...; } zmq_msg_t;
32
+ typedef ... zmq_free_fn;
33
+
34
+ int zmq_msg_init(zmq_msg_t *msg);
35
+ int zmq_msg_init_size(zmq_msg_t *msg, size_t size);
36
+ int zmq_msg_init_data(zmq_msg_t *msg,
37
+ void *data,
38
+ size_t size,
39
+ zmq_free_fn *ffn,
40
+ void *hint);
41
+
42
+ size_t zmq_msg_size(zmq_msg_t *msg);
43
+ void *zmq_msg_data(zmq_msg_t *msg);
44
+ int zmq_msg_close(zmq_msg_t *msg);
45
+
46
+ int zmq_msg_copy(zmq_msg_t *dst, zmq_msg_t *src);
47
+ int zmq_msg_send(zmq_msg_t *msg, void *socket, int flags);
48
+ int zmq_msg_recv(zmq_msg_t *msg, void *socket, int flags);
49
+
50
+ int zmq_getsockopt(void *socket,
51
+ int option_name,
52
+ void *option_value,
53
+ size_t *option_len);
54
+
55
+ int zmq_setsockopt(void *socket,
56
+ int option_name,
57
+ const void *option_value,
58
+ size_t option_len);
59
+
60
+ typedef int... ZMQ_FD_T;
61
+
62
+ typedef struct
63
+ {
64
+ void *socket;
65
+ ZMQ_FD_T fd;
66
+ short events;
67
+ short revents;
68
+ } zmq_pollitem_t;
69
+
70
+ int zmq_poll(zmq_pollitem_t *items, int nitems, long timeout);
71
+
72
+ // miscellany
73
+ void * memcpy(void *restrict s1, const void *restrict s2, size_t n);
74
+ void * malloc(size_t sz);
75
+ void free(void *p);
76
+ int get_ipc_path_max_len(void);
77
+
78
+ typedef struct { ...; } mutex_t;
79
+
80
+ typedef struct _zhint {
81
+ void *sock;
82
+ mutex_t *mutex;
83
+ size_t id;
84
+ } zhint;
85
+
86
+ mutex_t* mutex_allocate();
87
+
88
+ int zmq_wrap_msg_init_data(zmq_msg_t *msg,
89
+ void *data,
90
+ size_t size,
91
+ void *hint);
.venv/lib/python3.11/site-packages/zmq/backend/cffi/_cffi_src.c ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include <stdio.h>
2
+ #include <string.h>
3
+
4
+ #include "pyversion_compat.h"
5
+ #include "mutex.h"
6
+ #include "ipcmaxlen.h"
7
+ #include "zmq_compat.h"
8
+ #include <zmq.h>
9
+
10
+ typedef struct _zhint {
11
+ void *sock;
12
+ mutex_t *mutex;
13
+ size_t id;
14
+ } zhint;
15
+
16
+ void free_python_msg(void *data, void *vhint) {
17
+ zmq_msg_t msg;
18
+ zhint *hint = (zhint *)vhint;
19
+ int rc;
20
+ if (hint != NULL) {
21
+ zmq_msg_init_size(&msg, sizeof(size_t));
22
+ memcpy(zmq_msg_data(&msg), &hint->id, sizeof(size_t));
23
+ rc = mutex_lock(hint->mutex);
24
+ if (rc != 0) {
25
+ fprintf(stderr, "pyzmq-gc mutex lock failed rc=%d\n", rc);
26
+ }
27
+ rc = zmq_msg_send(&msg, hint->sock, 0);
28
+ if (rc < 0) {
29
+ /*
30
+ * gc socket could have been closed, e.g. during process teardown.
31
+ * If so, ignore the failure because there's nothing to do.
32
+ */
33
+ if (zmq_errno() != ENOTSOCK) {
34
+ fprintf(stderr, "pyzmq-gc send failed: %s\n",
35
+ zmq_strerror(zmq_errno()));
36
+ }
37
+ }
38
+ rc = mutex_unlock(hint->mutex);
39
+ if (rc != 0) {
40
+ fprintf(stderr, "pyzmq-gc mutex unlock failed rc=%d\n", rc);
41
+ }
42
+ zmq_msg_close(&msg);
43
+ free(hint);
44
+ }
45
+ }
46
+
47
+ int zmq_wrap_msg_init_data(zmq_msg_t *msg, void *data, size_t size,
48
+ void *hint) {
49
+ return zmq_msg_init_data(msg, data, size, free_python_msg, hint);
50
+ }
.venv/lib/python3.11/site-packages/zmq/backend/cffi/_poll.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """zmq poll function"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ try:
7
+ from time import monotonic
8
+ except ImportError:
9
+ from time import clock as monotonic
10
+
11
+ import warnings
12
+
13
+ from zmq.error import InterruptedSystemCall, _check_rc
14
+
15
+ from ._cffi import ffi
16
+ from ._cffi import lib as C
17
+
18
+
19
+ def _make_zmq_pollitem(socket, flags):
20
+ zmq_socket = socket._zmq_socket
21
+ zmq_pollitem = ffi.new('zmq_pollitem_t*')
22
+ zmq_pollitem.socket = zmq_socket
23
+ zmq_pollitem.fd = 0
24
+ zmq_pollitem.events = flags
25
+ zmq_pollitem.revents = 0
26
+ return zmq_pollitem[0]
27
+
28
+
29
+ def _make_zmq_pollitem_fromfd(socket_fd, flags):
30
+ zmq_pollitem = ffi.new('zmq_pollitem_t*')
31
+ zmq_pollitem.socket = ffi.NULL
32
+ zmq_pollitem.fd = socket_fd
33
+ zmq_pollitem.events = flags
34
+ zmq_pollitem.revents = 0
35
+ return zmq_pollitem[0]
36
+
37
+
38
+ def zmq_poll(sockets, timeout):
39
+ cffi_pollitem_list = []
40
+ low_level_to_socket_obj = {}
41
+ from zmq import Socket
42
+
43
+ for item in sockets:
44
+ if isinstance(item[0], Socket):
45
+ low_level_to_socket_obj[item[0]._zmq_socket] = item
46
+ cffi_pollitem_list.append(_make_zmq_pollitem(item[0], item[1]))
47
+ else:
48
+ if not isinstance(item[0], int):
49
+ # not an FD, get it from fileno()
50
+ item = (item[0].fileno(), item[1])
51
+ low_level_to_socket_obj[item[0]] = item
52
+ cffi_pollitem_list.append(_make_zmq_pollitem_fromfd(item[0], item[1]))
53
+ items = ffi.new('zmq_pollitem_t[]', cffi_pollitem_list)
54
+ list_length = ffi.cast('int', len(cffi_pollitem_list))
55
+ while True:
56
+ c_timeout = ffi.cast('long', timeout)
57
+ start = monotonic()
58
+ rc = C.zmq_poll(items, list_length, c_timeout)
59
+ try:
60
+ _check_rc(rc)
61
+ except InterruptedSystemCall:
62
+ if timeout > 0:
63
+ ms_passed = int(1000 * (monotonic() - start))
64
+ if ms_passed < 0:
65
+ # don't allow negative ms_passed,
66
+ # which can happen on old Python versions without time.monotonic.
67
+ warnings.warn(
68
+ f"Negative elapsed time for interrupted poll: {ms_passed}."
69
+ " Did the clock change?",
70
+ RuntimeWarning,
71
+ )
72
+ ms_passed = 0
73
+ timeout = max(0, timeout - ms_passed)
74
+ continue
75
+ else:
76
+ break
77
+ result = []
78
+ for item in items:
79
+ if item.revents > 0:
80
+ if item.socket != ffi.NULL:
81
+ result.append(
82
+ (
83
+ low_level_to_socket_obj[item.socket][0],
84
+ item.revents,
85
+ )
86
+ )
87
+ else:
88
+ result.append((item.fd, item.revents))
89
+ return result
90
+
91
+
92
+ __all__ = ['zmq_poll']
.venv/lib/python3.11/site-packages/zmq/backend/cffi/context.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """zmq Context class"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ from zmq.constants import EINVAL, IO_THREADS
7
+ from zmq.error import InterruptedSystemCall, ZMQError, _check_rc
8
+
9
+ from ._cffi import ffi
10
+ from ._cffi import lib as C
11
+
12
+
13
+ class Context:
14
+ _zmq_ctx = None
15
+ _iothreads = None
16
+ _closed = True
17
+ _shadow = False
18
+
19
+ def __init__(self, io_threads=1, shadow=None):
20
+ if shadow:
21
+ self._zmq_ctx = ffi.cast("void *", shadow)
22
+ self._shadow = True
23
+ else:
24
+ self._shadow = False
25
+ if not io_threads >= 0:
26
+ raise ZMQError(EINVAL)
27
+
28
+ self._zmq_ctx = C.zmq_ctx_new()
29
+ if self._zmq_ctx == ffi.NULL:
30
+ raise ZMQError(C.zmq_errno())
31
+ if not shadow:
32
+ C.zmq_ctx_set(self._zmq_ctx, IO_THREADS, io_threads)
33
+ self._closed = False
34
+
35
+ @property
36
+ def underlying(self):
37
+ """The address of the underlying libzmq context"""
38
+ return int(ffi.cast('size_t', self._zmq_ctx))
39
+
40
+ @property
41
+ def closed(self):
42
+ return self._closed
43
+
44
+ def set(self, option, value):
45
+ """set a context option
46
+
47
+ see zmq_ctx_set
48
+ """
49
+ rc = C.zmq_ctx_set(self._zmq_ctx, option, value)
50
+ _check_rc(rc)
51
+
52
+ def get(self, option):
53
+ """get context option
54
+
55
+ see zmq_ctx_get
56
+ """
57
+ rc = C.zmq_ctx_get(self._zmq_ctx, option)
58
+ _check_rc(rc, error_without_errno=False)
59
+ return rc
60
+
61
+ def term(self):
62
+ if self.closed:
63
+ return
64
+
65
+ rc = C.zmq_ctx_destroy(self._zmq_ctx)
66
+ try:
67
+ _check_rc(rc)
68
+ except InterruptedSystemCall:
69
+ # ignore interrupted term
70
+ # see PEP 475 notes about close & EINTR for why
71
+ pass
72
+
73
+ self._zmq_ctx = None
74
+ self._closed = True
75
+
76
+
77
+ __all__ = ['Context']
.venv/lib/python3.11/site-packages/zmq/backend/cffi/devices.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """zmq device functions"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ from ._cffi import ffi
7
+ from ._cffi import lib as C
8
+ from .socket import Socket
9
+ from .utils import _retry_sys_call
10
+
11
+
12
+ def device(device_type, frontend, backend):
13
+ return proxy(frontend, backend)
14
+
15
+
16
+ def proxy(frontend, backend, capture=None):
17
+ if isinstance(capture, Socket):
18
+ capture = capture._zmq_socket
19
+ else:
20
+ capture = ffi.NULL
21
+
22
+ _retry_sys_call(C.zmq_proxy, frontend._zmq_socket, backend._zmq_socket, capture)
23
+
24
+
25
+ def proxy_steerable(frontend, backend, capture=None, control=None):
26
+ """proxy_steerable(frontend, backend, capture, control)
27
+
28
+ Start a zeromq proxy with control flow.
29
+
30
+ .. versionadded:: libzmq-4.1
31
+ .. versionadded:: 18.0
32
+
33
+ Parameters
34
+ ----------
35
+ frontend : Socket
36
+ The Socket instance for the incoming traffic.
37
+ backend : Socket
38
+ The Socket instance for the outbound traffic.
39
+ capture : Socket (optional)
40
+ The Socket instance for capturing traffic.
41
+ control : Socket (optional)
42
+ The Socket instance for control flow.
43
+ """
44
+ if isinstance(capture, Socket):
45
+ capture = capture._zmq_socket
46
+ else:
47
+ capture = ffi.NULL
48
+
49
+ if isinstance(control, Socket):
50
+ control = control._zmq_socket
51
+ else:
52
+ control = ffi.NULL
53
+
54
+ _retry_sys_call(
55
+ C.zmq_proxy_steerable,
56
+ frontend._zmq_socket,
57
+ backend._zmq_socket,
58
+ capture,
59
+ control,
60
+ )
61
+
62
+
63
+ __all__ = ['device', 'proxy', 'proxy_steerable']
.venv/lib/python3.11/site-packages/zmq/backend/cffi/error.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """zmq error functions"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ from ._cffi import ffi
7
+ from ._cffi import lib as C
8
+
9
+
10
+ def strerror(errno):
11
+ s = ffi.string(C.zmq_strerror(errno))
12
+ if not isinstance(s, str):
13
+ # py3
14
+ s = s.decode()
15
+ return s
16
+
17
+
18
+ zmq_errno = C.zmq_errno
19
+
20
+ __all__ = ['strerror', 'zmq_errno']
.venv/lib/python3.11/site-packages/zmq/backend/cffi/message.py ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Dummy Frame object"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ import errno
7
+ from threading import Event
8
+
9
+ import zmq
10
+ import zmq.error
11
+ from zmq.constants import ETERM
12
+
13
+ from ._cffi import ffi
14
+ from ._cffi import lib as C
15
+
16
+ zmq_gc = None
17
+
18
+ try:
19
+ from __pypy__.bufferable import bufferable as maybe_bufferable
20
+ except ImportError:
21
+ maybe_bufferable = object
22
+
23
+
24
+ def _content(obj):
25
+ """Return content of obj as bytes"""
26
+ if type(obj) is bytes:
27
+ return obj
28
+ if not isinstance(obj, memoryview):
29
+ obj = memoryview(obj)
30
+ return obj.tobytes()
31
+
32
+
33
+ def _check_rc(rc):
34
+ err = C.zmq_errno()
35
+ if rc == -1:
36
+ if err == errno.EINTR:
37
+ raise zmq.error.InterrruptedSystemCall(err)
38
+ elif err == errno.EAGAIN:
39
+ raise zmq.error.Again(errno)
40
+ elif err == ETERM:
41
+ raise zmq.error.ContextTerminated(err)
42
+ else:
43
+ raise zmq.error.ZMQError(err)
44
+ return 0
45
+
46
+
47
+ class Frame(maybe_bufferable):
48
+ _data = None
49
+ tracker = None
50
+ closed = False
51
+ more = False
52
+ _buffer = None
53
+ _bytes = None
54
+ _failed_init = False
55
+ tracker_event = None
56
+ zmq_msg = None
57
+
58
+ def __init__(self, data=None, track=False, copy=None, copy_threshold=None):
59
+ self._failed_init = True
60
+
61
+ self.zmq_msg = ffi.cast('zmq_msg_t[1]', C.malloc(ffi.sizeof("zmq_msg_t")))
62
+
63
+ # self.tracker should start finished
64
+ # except in the case where we are sharing memory with libzmq
65
+ if track:
66
+ self.tracker = zmq._FINISHED_TRACKER
67
+
68
+ if isinstance(data, str):
69
+ raise TypeError(
70
+ "Unicode strings are not allowed. Only: bytes, buffer interfaces."
71
+ )
72
+
73
+ if data is None:
74
+ rc = C.zmq_msg_init(self.zmq_msg)
75
+ _check_rc(rc)
76
+ self._failed_init = False
77
+ return
78
+
79
+ self._data = data
80
+ if type(data) is bytes:
81
+ # avoid unnecessary copy on .bytes access
82
+ self._bytes = data
83
+
84
+ self._buffer = memoryview(data)
85
+ c_data = ffi.from_buffer(self._buffer)
86
+ data_len_c = self._buffer.nbytes
87
+
88
+ if copy is None:
89
+ if copy_threshold and data_len_c < copy_threshold:
90
+ copy = True
91
+ else:
92
+ copy = False
93
+
94
+ if copy:
95
+ # copy message data instead of sharing memory
96
+ rc = C.zmq_msg_init_size(self.zmq_msg, data_len_c)
97
+ _check_rc(rc)
98
+ ffi.buffer(C.zmq_msg_data(self.zmq_msg), data_len_c)[:] = self._buffer
99
+ self._failed_init = False
100
+ return
101
+
102
+ # Getting here means that we are doing a true zero-copy Frame,
103
+ # where libzmq and Python are sharing memory.
104
+ # Hook up garbage collection with MessageTracker and zmq_free_fn
105
+
106
+ # Event and MessageTracker for monitoring when zmq is done with data:
107
+ if track:
108
+ evt = Event()
109
+ self.tracker_event = evt
110
+ self.tracker = zmq.MessageTracker(evt)
111
+ # create the hint for zmq_free_fn
112
+ # two pointers: the zmq_gc context and a message to be sent to the zmq_gc PULL socket
113
+ # allows libzmq to signal to Python when it is done with Python-owned memory.
114
+ global zmq_gc
115
+ if zmq_gc is None:
116
+ from zmq.utils.garbage import gc as zmq_gc
117
+ # can't use ffi.new because it will be freed at the wrong time!
118
+ hint = ffi.cast("zhint[1]", C.malloc(ffi.sizeof("zhint")))
119
+ hint[0].id = zmq_gc.store(data, self.tracker_event)
120
+ if not zmq_gc._push_mutex:
121
+ zmq_gc._push_mutex = C.mutex_allocate()
122
+
123
+ hint[0].mutex = ffi.cast("mutex_t*", zmq_gc._push_mutex)
124
+ hint[0].sock = ffi.cast("void*", zmq_gc._push_socket.underlying)
125
+
126
+ # calls zmq_wrap_msg_init_data with the C.free_python_msg callback
127
+ rc = C.zmq_wrap_msg_init_data(
128
+ self.zmq_msg,
129
+ c_data,
130
+ data_len_c,
131
+ hint,
132
+ )
133
+ if rc != 0:
134
+ C.free(hint)
135
+ C.free(self.zmq_msg)
136
+ _check_rc(rc)
137
+ self._failed_init = False
138
+
139
+ def __del__(self):
140
+ if not self.closed and not self._failed_init:
141
+ self.close()
142
+
143
+ def close(self):
144
+ if self.closed or self._failed_init or self.zmq_msg is None:
145
+ return
146
+ self.closed = True
147
+ rc = C.zmq_msg_close(self.zmq_msg)
148
+ C.free(self.zmq_msg)
149
+ self.zmq_msg = None
150
+ if rc != 0:
151
+ _check_rc(rc)
152
+
153
+ def _buffer_from_zmq_msg(self):
154
+ """one-time extract buffer from zmq_msg
155
+
156
+ for Frames created by recv
157
+ """
158
+ if self._data is None:
159
+ self._data = ffi.buffer(
160
+ C.zmq_msg_data(self.zmq_msg), C.zmq_msg_size(self.zmq_msg)
161
+ )
162
+ if self._buffer is None:
163
+ self._buffer = memoryview(self._data)
164
+
165
+ @property
166
+ def buffer(self):
167
+ if self._buffer is None:
168
+ self._buffer_from_zmq_msg()
169
+ return self._buffer
170
+
171
+ @property
172
+ def bytes(self):
173
+ if self._bytes is None:
174
+ self._bytes = self.buffer.tobytes()
175
+ return self._bytes
176
+
177
+ def __len__(self):
178
+ return self.buffer.nbytes
179
+
180
+ def __eq__(self, other):
181
+ return self.bytes == _content(other)
182
+
183
+ @property
184
+ def done(self):
185
+ return self.tracker.done()
186
+
187
+ def __buffer__(self, flags):
188
+ return self.buffer
189
+
190
+ def __copy__(self):
191
+ """Create a shallow copy of the message.
192
+
193
+ This does not copy the contents of the Frame, just the pointer.
194
+ This will increment the 0MQ ref count of the message, but not
195
+ the ref count of the Python object. That is only done once when
196
+ the Python is first turned into a 0MQ message.
197
+ """
198
+ return self.fast_copy()
199
+
200
+ def fast_copy(self):
201
+ """Fast shallow copy of the Frame.
202
+
203
+ Does not copy underlying data.
204
+ """
205
+ new_msg = Frame()
206
+ # This does not copy the contents, but just increases the ref-count
207
+ # of the zmq_msg by one.
208
+ C.zmq_msg_copy(new_msg.zmq_msg, self.zmq_msg)
209
+ # Copy the ref to underlying data
210
+ new_msg._data = self._data
211
+ new_msg._buffer = self._buffer
212
+
213
+ # Frame copies share the tracker and tracker_event
214
+ new_msg.tracker_event = self.tracker_event
215
+ new_msg.tracker = self.tracker
216
+
217
+ return new_msg
218
+
219
+
220
+ Message = Frame
221
+
222
+ __all__ = ['Frame', 'Message']
.venv/lib/python3.11/site-packages/zmq/backend/cffi/socket.py ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """zmq Socket class"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ import errno as errno_mod
7
+
8
+ import zmq
9
+ from zmq.constants import SocketOption, _OptType
10
+ from zmq.error import ZMQError, _check_rc, _check_version
11
+
12
+ from ._cffi import ffi
13
+ from ._cffi import lib as C
14
+ from .message import Frame
15
+ from .utils import _retry_sys_call
16
+
17
+ nsp = new_sizet_pointer = lambda length: ffi.new('size_t*', length)
18
+
19
+
20
+ def new_uint64_pointer():
21
+ return ffi.new('uint64_t*'), nsp(ffi.sizeof('uint64_t'))
22
+
23
+
24
+ def new_int64_pointer():
25
+ return ffi.new('int64_t*'), nsp(ffi.sizeof('int64_t'))
26
+
27
+
28
+ def new_int_pointer():
29
+ return ffi.new('int*'), nsp(ffi.sizeof('int'))
30
+
31
+
32
+ def new_binary_data(length):
33
+ return ffi.new(f'char[{length:d}]'), nsp(ffi.sizeof('char') * length)
34
+
35
+
36
+ def value_uint64_pointer(val):
37
+ return ffi.new('uint64_t*', val), ffi.sizeof('uint64_t')
38
+
39
+
40
+ def value_int64_pointer(val):
41
+ return ffi.new('int64_t*', val), ffi.sizeof('int64_t')
42
+
43
+
44
+ def value_int_pointer(val):
45
+ return ffi.new('int*', val), ffi.sizeof('int')
46
+
47
+
48
+ def value_binary_data(val, length):
49
+ return ffi.new(f'char[{length + 1:d}]', val), ffi.sizeof('char') * length
50
+
51
+
52
+ ZMQ_FD_64BIT = ffi.sizeof('ZMQ_FD_T') == 8
53
+
54
+ IPC_PATH_MAX_LEN = C.get_ipc_path_max_len()
55
+
56
+
57
+ def new_pointer_from_opt(option, length=0):
58
+ opt_type = getattr(option, "_opt_type", _OptType.int)
59
+
60
+ if opt_type == _OptType.int64 or (ZMQ_FD_64BIT and opt_type == _OptType.fd):
61
+ return new_int64_pointer()
62
+ elif opt_type == _OptType.bytes:
63
+ return new_binary_data(length)
64
+ else:
65
+ # default
66
+ return new_int_pointer()
67
+
68
+
69
+ def value_from_opt_pointer(option, opt_pointer, length=0):
70
+ try:
71
+ option = SocketOption(option)
72
+ except ValueError:
73
+ # unrecognized option,
74
+ # assume from the future,
75
+ # let EINVAL raise
76
+ opt_type = _OptType.int
77
+ else:
78
+ opt_type = option._opt_type
79
+
80
+ if opt_type == _OptType.bytes:
81
+ return ffi.buffer(opt_pointer, length)[:]
82
+ else:
83
+ return int(opt_pointer[0])
84
+
85
+
86
+ def initialize_opt_pointer(option, value, length=0):
87
+ opt_type = getattr(option, "_opt_type", _OptType.int)
88
+ if opt_type == _OptType.int64 or (ZMQ_FD_64BIT and opt_type == _OptType.fd):
89
+ return value_int64_pointer(value)
90
+ elif opt_type == _OptType.bytes:
91
+ return value_binary_data(value, length)
92
+ else:
93
+ return value_int_pointer(value)
94
+
95
+
96
+ class Socket:
97
+ context = None
98
+ socket_type = None
99
+ _zmq_socket = None
100
+ _closed = None
101
+ _ref = None
102
+ _shadow = False
103
+ copy_threshold = 0
104
+
105
+ def __init__(self, context=None, socket_type=None, shadow=0, copy_threshold=None):
106
+ if copy_threshold is None:
107
+ copy_threshold = zmq.COPY_THRESHOLD
108
+ self.copy_threshold = copy_threshold
109
+
110
+ self.context = context
111
+ if shadow:
112
+ self._zmq_socket = ffi.cast("void *", shadow)
113
+ self._shadow = True
114
+ else:
115
+ self._shadow = False
116
+ self._zmq_socket = C.zmq_socket(context._zmq_ctx, socket_type)
117
+ if self._zmq_socket == ffi.NULL:
118
+ raise ZMQError()
119
+ self._closed = False
120
+
121
+ @property
122
+ def underlying(self):
123
+ """The address of the underlying libzmq socket"""
124
+ return int(ffi.cast('size_t', self._zmq_socket))
125
+
126
+ def _check_closed_deep(self):
127
+ """thorough check of whether the socket has been closed,
128
+ even if by another entity (e.g. ctx.destroy).
129
+
130
+ Only used by the `closed` property.
131
+
132
+ returns True if closed, False otherwise
133
+ """
134
+ if self._closed:
135
+ return True
136
+ try:
137
+ self.get(zmq.TYPE)
138
+ except ZMQError as e:
139
+ if e.errno == zmq.ENOTSOCK:
140
+ self._closed = True
141
+ return True
142
+ elif e.errno == zmq.ETERM:
143
+ pass
144
+ else:
145
+ raise
146
+ return False
147
+
148
+ @property
149
+ def closed(self):
150
+ return self._check_closed_deep()
151
+
152
+ def close(self, linger=None):
153
+ rc = 0
154
+ if not self._closed and hasattr(self, '_zmq_socket'):
155
+ if self._zmq_socket is not None:
156
+ if linger is not None:
157
+ self.set(zmq.LINGER, linger)
158
+ rc = C.zmq_close(self._zmq_socket)
159
+ self._closed = True
160
+ if rc < 0:
161
+ _check_rc(rc)
162
+
163
+ def bind(self, address):
164
+ if isinstance(address, str):
165
+ address_b = address.encode('utf8')
166
+ else:
167
+ address_b = address
168
+ if isinstance(address, bytes):
169
+ address = address_b.decode('utf8')
170
+ rc = C.zmq_bind(self._zmq_socket, address_b)
171
+ if rc < 0:
172
+ if IPC_PATH_MAX_LEN and C.zmq_errno() == errno_mod.ENAMETOOLONG:
173
+ path = address.split('://', 1)[-1]
174
+ msg = (
175
+ f'ipc path "{path}" is longer than {IPC_PATH_MAX_LEN} '
176
+ 'characters (sizeof(sockaddr_un.sun_path)).'
177
+ )
178
+ raise ZMQError(C.zmq_errno(), msg=msg)
179
+ elif C.zmq_errno() == errno_mod.ENOENT:
180
+ path = address.split('://', 1)[-1]
181
+ msg = f'No such file or directory for ipc path "{path}".'
182
+ raise ZMQError(C.zmq_errno(), msg=msg)
183
+ else:
184
+ _check_rc(rc)
185
+
186
+ def unbind(self, address):
187
+ _check_version((3, 2), "unbind")
188
+ if isinstance(address, str):
189
+ address = address.encode('utf8')
190
+ rc = C.zmq_unbind(self._zmq_socket, address)
191
+ _check_rc(rc)
192
+
193
+ def connect(self, address):
194
+ if isinstance(address, str):
195
+ address = address.encode('utf8')
196
+ rc = C.zmq_connect(self._zmq_socket, address)
197
+ _check_rc(rc)
198
+
199
+ def disconnect(self, address):
200
+ _check_version((3, 2), "disconnect")
201
+ if isinstance(address, str):
202
+ address = address.encode('utf8')
203
+ rc = C.zmq_disconnect(self._zmq_socket, address)
204
+ _check_rc(rc)
205
+
206
+ def set(self, option, value):
207
+ length = None
208
+ if isinstance(value, str):
209
+ raise TypeError("unicode not allowed, use bytes")
210
+
211
+ try:
212
+ option = SocketOption(option)
213
+ except ValueError:
214
+ # unrecognized option,
215
+ # assume from the future,
216
+ # let EINVAL raise
217
+ opt_type = _OptType.int
218
+ else:
219
+ opt_type = option._opt_type
220
+
221
+ if isinstance(value, bytes):
222
+ if opt_type != _OptType.bytes:
223
+ raise TypeError(f"not a bytes sockopt: {option}")
224
+ length = len(value)
225
+
226
+ c_value_pointer, c_sizet = initialize_opt_pointer(option, value, length)
227
+
228
+ _retry_sys_call(
229
+ C.zmq_setsockopt,
230
+ self._zmq_socket,
231
+ option,
232
+ ffi.cast('void*', c_value_pointer),
233
+ c_sizet,
234
+ )
235
+
236
+ def get(self, option):
237
+ try:
238
+ option = SocketOption(option)
239
+ except ValueError:
240
+ # unrecognized option,
241
+ # assume from the future,
242
+ # let EINVAL raise
243
+ opt_type = _OptType.int
244
+ else:
245
+ opt_type = option._opt_type
246
+
247
+ c_value_pointer, c_sizet_pointer = new_pointer_from_opt(option, length=255)
248
+
249
+ _retry_sys_call(
250
+ C.zmq_getsockopt, self._zmq_socket, option, c_value_pointer, c_sizet_pointer
251
+ )
252
+
253
+ sz = c_sizet_pointer[0]
254
+ v = value_from_opt_pointer(option, c_value_pointer, sz)
255
+ if (
256
+ option != zmq.SocketOption.ROUTING_ID
257
+ and opt_type == _OptType.bytes
258
+ and v.endswith(b'\0')
259
+ ):
260
+ v = v[:-1]
261
+ return v
262
+
263
+ def _send_copy(self, buf, flags):
264
+ """Send a copy of a bufferable"""
265
+ zmq_msg = ffi.new('zmq_msg_t*')
266
+ if not isinstance(buf, bytes):
267
+ # cast any bufferable data to bytes via memoryview
268
+ buf = memoryview(buf).tobytes()
269
+
270
+ c_message = ffi.new('char[]', buf)
271
+ rc = C.zmq_msg_init_size(zmq_msg, len(buf))
272
+ _check_rc(rc)
273
+ C.memcpy(C.zmq_msg_data(zmq_msg), c_message, len(buf))
274
+ _retry_sys_call(C.zmq_msg_send, zmq_msg, self._zmq_socket, flags)
275
+ rc2 = C.zmq_msg_close(zmq_msg)
276
+ _check_rc(rc2)
277
+
278
+ def _send_frame(self, frame, flags):
279
+ """Send a Frame on this socket in a non-copy manner."""
280
+ # Always copy the Frame so the original message isn't garbage collected.
281
+ # This doesn't do a real copy, just a reference.
282
+ frame_copy = frame.fast_copy()
283
+ zmq_msg = frame_copy.zmq_msg
284
+ _retry_sys_call(C.zmq_msg_send, zmq_msg, self._zmq_socket, flags)
285
+ tracker = frame_copy.tracker
286
+ frame_copy.close()
287
+ return tracker
288
+
289
+ def send(self, data, flags=0, copy=False, track=False):
290
+ if isinstance(data, str):
291
+ raise TypeError("Message must be in bytes, not a unicode object")
292
+
293
+ if copy and not isinstance(data, Frame):
294
+ return self._send_copy(data, flags)
295
+ else:
296
+ close_frame = False
297
+ if isinstance(data, Frame):
298
+ if track and not data.tracker:
299
+ raise ValueError('Not a tracked message')
300
+ frame = data
301
+ else:
302
+ if self.copy_threshold:
303
+ buf = memoryview(data)
304
+ # always copy messages smaller than copy_threshold
305
+ if buf.nbytes < self.copy_threshold:
306
+ self._send_copy(buf, flags)
307
+ return zmq._FINISHED_TRACKER
308
+ frame = Frame(data, track=track, copy_threshold=self.copy_threshold)
309
+ close_frame = True
310
+
311
+ tracker = self._send_frame(frame, flags)
312
+ if close_frame:
313
+ frame.close()
314
+ return tracker
315
+
316
+ def recv(self, flags=0, copy=True, track=False):
317
+ if copy:
318
+ zmq_msg = ffi.new('zmq_msg_t*')
319
+ C.zmq_msg_init(zmq_msg)
320
+ else:
321
+ frame = zmq.Frame(track=track)
322
+ zmq_msg = frame.zmq_msg
323
+
324
+ try:
325
+ _retry_sys_call(C.zmq_msg_recv, zmq_msg, self._zmq_socket, flags)
326
+ except Exception:
327
+ if copy:
328
+ C.zmq_msg_close(zmq_msg)
329
+ raise
330
+
331
+ if not copy:
332
+ return frame
333
+
334
+ _buffer = ffi.buffer(C.zmq_msg_data(zmq_msg), C.zmq_msg_size(zmq_msg))
335
+ _bytes = _buffer[:]
336
+ rc = C.zmq_msg_close(zmq_msg)
337
+ _check_rc(rc)
338
+ return _bytes
339
+
340
+ def monitor(self, addr, events=-1):
341
+ """s.monitor(addr, flags)
342
+
343
+ Start publishing socket events on inproc.
344
+ See libzmq docs for zmq_monitor for details.
345
+
346
+ Note: requires libzmq >= 3.2
347
+
348
+ Parameters
349
+ ----------
350
+ addr : str
351
+ The inproc url used for monitoring. Passing None as
352
+ the addr will cause an existing socket monitor to be
353
+ deregistered.
354
+ events : int [default: zmq.EVENT_ALL]
355
+ The zmq event bitmask for which events will be sent to the monitor.
356
+ """
357
+
358
+ _check_version((3, 2), "monitor")
359
+ if events < 0:
360
+ events = zmq.EVENT_ALL
361
+ if addr is None:
362
+ addr = ffi.NULL
363
+ if isinstance(addr, str):
364
+ addr = addr.encode('utf8')
365
+ C.zmq_socket_monitor(self._zmq_socket, addr, events)
366
+
367
+
368
+ __all__ = ['Socket', 'IPC_PATH_MAX_LEN']
.venv/lib/python3.11/site-packages/zmq/backend/cffi/utils.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """miscellaneous zmq_utils wrapping"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ from zmq.error import InterruptedSystemCall, _check_rc, _check_version
7
+
8
+ from ._cffi import ffi
9
+ from ._cffi import lib as C
10
+
11
+
12
+ def has(capability):
13
+ """Check for zmq capability by name (e.g. 'ipc', 'curve')
14
+
15
+ .. versionadded:: libzmq-4.1
16
+ .. versionadded:: 14.1
17
+ """
18
+ _check_version((4, 1), 'zmq.has')
19
+ if isinstance(capability, str):
20
+ capability = capability.encode('utf8')
21
+ return bool(C.zmq_has(capability))
22
+
23
+
24
+ def curve_keypair():
25
+ """generate a Z85 key pair for use with zmq.CURVE security
26
+
27
+ Requires libzmq (≥ 4.0) to have been built with CURVE support.
28
+
29
+ Returns
30
+ -------
31
+ (public, secret) : two bytestrings
32
+ The public and private key pair as 40 byte z85-encoded bytestrings.
33
+ """
34
+ _check_version((3, 2), "curve_keypair")
35
+ public = ffi.new('char[64]')
36
+ private = ffi.new('char[64]')
37
+ rc = C.zmq_curve_keypair(public, private)
38
+ _check_rc(rc)
39
+ return ffi.buffer(public)[:40], ffi.buffer(private)[:40]
40
+
41
+
42
+ def curve_public(private):
43
+ """Compute the public key corresponding to a private key for use
44
+ with zmq.CURVE security
45
+
46
+ Requires libzmq (≥ 4.2) to have been built with CURVE support.
47
+
48
+ Parameters
49
+ ----------
50
+ private
51
+ The private key as a 40 byte z85-encoded bytestring
52
+ Returns
53
+ -------
54
+ bytestring
55
+ The public key as a 40 byte z85-encoded bytestring.
56
+ """
57
+ if isinstance(private, str):
58
+ private = private.encode('utf8')
59
+ _check_version((4, 2), "curve_public")
60
+ public = ffi.new('char[64]')
61
+ rc = C.zmq_curve_public(public, private)
62
+ _check_rc(rc)
63
+ return ffi.buffer(public)[:40]
64
+
65
+
66
+ def _retry_sys_call(f, *args, **kwargs):
67
+ """make a call, retrying if interrupted with EINTR"""
68
+ while True:
69
+ rc = f(*args)
70
+ try:
71
+ _check_rc(rc)
72
+ except InterruptedSystemCall:
73
+ continue
74
+ else:
75
+ break
76
+
77
+
78
+ __all__ = ['has', 'curve_keypair', 'curve_public']
.venv/lib/python3.11/site-packages/zmq/backend/cython/__init__.pxd ADDED
@@ -0,0 +1 @@
 
 
1
+ from zmq.backend.cython._zmq cimport Context, Frame, Socket
.venv/lib/python3.11/site-packages/zmq/backend/cython/__init__.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Python bindings for core 0MQ objects."""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ from . import _zmq
7
+
8
+ # mq not in __all__
9
+ from ._zmq import * # noqa
10
+ from ._zmq import monitored_queue # noqa
11
+
12
+ Message = _zmq.Frame
13
+
14
+ __all__ = ["Message"]
15
+ __all__.extend(_zmq.__all__)
.venv/lib/python3.11/site-packages/zmq/backend/cython/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (519 Bytes). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cython/__pycache__/_zmq.cpython-311.pyc ADDED
Binary file (72.1 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/backend/cython/_externs.pxd ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef extern from "mutex.h" nogil:
2
+ ctypedef struct mutex_t:
3
+ pass
4
+ cdef mutex_t* mutex_allocate()
5
+ cdef void mutex_dallocate(mutex_t*)
6
+ cdef int mutex_lock(mutex_t*)
7
+ cdef int mutex_unlock(mutex_t*)
8
+
9
+ cdef extern from "getpid_compat.h":
10
+ int getpid()
11
+
12
+ cdef extern from "ipcmaxlen.h":
13
+ int get_ipc_path_max_len()
.venv/lib/python3.11/site-packages/zmq/backend/cython/_zmq.pxd ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """zmq Cython backend augmented declarations"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ from zmq.backend.cython.libzmq cimport zmq_msg_t
7
+
8
+
9
+ cdef class Context:
10
+
11
+ cdef object __weakref__ # enable weakref
12
+ cdef void *handle # The C handle for the underlying zmq object.
13
+ cdef bint _shadow # whether the Context is a shadow wrapper of another
14
+ cdef int _pid # the pid of the process which created me (for fork safety)
15
+
16
+ cdef public bint closed # bool property for a closed context.
17
+ cdef inline int _term(self)
18
+
19
+ cdef class MessageTracker(object):
20
+ cdef set events # Message Event objects to track.
21
+ cdef set peers # Other Message or MessageTracker objects.
22
+
23
+ cdef class Frame:
24
+
25
+ cdef zmq_msg_t zmq_msg
26
+ cdef object _data # The actual message data as a Python object.
27
+ cdef object _buffer # A Python memoryview of the message contents
28
+ cdef object _bytes # A bytes copy of the message.
29
+ cdef bint _failed_init # flag to hold failed init
30
+ cdef public object tracker_event # Event for use with zmq_free_fn.
31
+ cdef public object tracker # MessageTracker object.
32
+ cdef public bint more # whether RCVMORE was set
33
+
34
+ cdef Frame fast_copy(self) # Create shallow copy of Message object.
35
+
36
+ cdef class Socket:
37
+
38
+ cdef object __weakref__ # enable weakref
39
+ cdef void *handle # The C handle for the underlying zmq object.
40
+ cdef bint _shadow # whether the Socket is a shadow wrapper of another
41
+ # Hold on to a reference to the context to make sure it is not garbage
42
+ # collected until the socket it done with it.
43
+ cdef public Context context # The zmq Context object that owns this.
44
+ cdef public bint _closed # bool property for a closed socket.
45
+ cdef public int copy_threshold # threshold below which pyzmq will always copy messages
46
+ cdef int _pid # the pid of the process which created me (for fork safety)
47
+
48
+ # cpdef methods for direct-cython access:
49
+ cpdef object send(self, data, int flags=*, bint copy=*, bint track=*)
50
+ cpdef object recv(self, int flags=*, bint copy=*, bint track=*)
.venv/lib/python3.11/site-packages/zmq/backend/cython/_zmq.py ADDED
@@ -0,0 +1,1958 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # cython: freethreading_compatible = True
2
+ """Cython backend for pyzmq"""
3
+
4
+ # Copyright (C) PyZMQ Developers
5
+ # Distributed under the terms of the Modified BSD License.
6
+
7
+ from __future__ import annotations
8
+
9
+ try:
10
+ import cython
11
+
12
+ if not cython.compiled:
13
+ raise ImportError()
14
+ except ImportError:
15
+ from pathlib import Path
16
+
17
+ zmq_root = Path(__file__).parents[3]
18
+ msg = f"""
19
+ Attempting to import zmq Cython backend, which has not been compiled.
20
+
21
+ This probably means you are importing zmq from its source tree.
22
+ if this is what you want, make sure to do an in-place build first:
23
+
24
+ pip install -e '{zmq_root}'
25
+
26
+ If it is not, then '{zmq_root}' is probably on your sys.path,
27
+ when it shouldn't be. Is that your current working directory?
28
+
29
+ If neither of those is true and this file is actually installed,
30
+ something seems to have gone wrong with the install!
31
+ Please report at https://github.com/zeromq/pyzmq/issues
32
+ """
33
+ raise ImportError(msg)
34
+
35
+ import time
36
+ import warnings
37
+ from threading import Event
38
+ from weakref import ref
39
+
40
+ import cython as C
41
+ from cython import (
42
+ NULL,
43
+ Py_ssize_t,
44
+ address,
45
+ bint,
46
+ cast,
47
+ cclass,
48
+ cfunc,
49
+ char,
50
+ declare,
51
+ inline,
52
+ nogil,
53
+ p_char,
54
+ p_void,
55
+ pointer,
56
+ size_t,
57
+ sizeof,
58
+ )
59
+ from cython.cimports.cpython import (
60
+ PyBytes_AsString,
61
+ PyBytes_FromStringAndSize,
62
+ PyBytes_Size,
63
+ PyErr_CheckSignals,
64
+ )
65
+ from cython.cimports.libc.errno import EAGAIN, EINTR, ENAMETOOLONG, ENOENT, ENOTSOCK
66
+
67
+ # cimports require Cython 3
68
+ from cython.cimports.libc.stdint import uint32_t
69
+ from cython.cimports.libc.stdio import fprintf
70
+ from cython.cimports.libc.stdio import stderr as cstderr
71
+ from cython.cimports.libc.stdlib import free, malloc
72
+ from cython.cimports.libc.string import memcpy
73
+ from cython.cimports.zmq.backend.cython._externs import (
74
+ get_ipc_path_max_len,
75
+ getpid,
76
+ mutex_allocate,
77
+ mutex_lock,
78
+ mutex_t,
79
+ mutex_unlock,
80
+ )
81
+ from cython.cimports.zmq.backend.cython.libzmq import (
82
+ ZMQ_ENOTSOCK,
83
+ ZMQ_ETERM,
84
+ ZMQ_EVENT_ALL,
85
+ ZMQ_IDENTITY,
86
+ ZMQ_IO_THREADS,
87
+ ZMQ_LINGER,
88
+ ZMQ_POLLIN,
89
+ ZMQ_RCVMORE,
90
+ ZMQ_ROUTER,
91
+ ZMQ_SNDMORE,
92
+ ZMQ_TYPE,
93
+ ZMQ_VERSION_MAJOR,
94
+ _zmq_version,
95
+ fd_t,
96
+ int64_t,
97
+ zmq_bind,
98
+ zmq_close,
99
+ zmq_connect,
100
+ zmq_ctx_destroy,
101
+ zmq_ctx_get,
102
+ zmq_ctx_new,
103
+ zmq_ctx_set,
104
+ zmq_curve_keypair,
105
+ zmq_curve_public,
106
+ zmq_device,
107
+ zmq_disconnect,
108
+ zmq_free_fn,
109
+ zmq_getsockopt,
110
+ zmq_has,
111
+ zmq_init,
112
+ zmq_join,
113
+ zmq_leave,
114
+ zmq_msg_close,
115
+ zmq_msg_copy,
116
+ zmq_msg_data,
117
+ zmq_msg_get,
118
+ zmq_msg_gets,
119
+ zmq_msg_group,
120
+ zmq_msg_init,
121
+ zmq_msg_init_data,
122
+ zmq_msg_init_size,
123
+ zmq_msg_recv,
124
+ zmq_msg_routing_id,
125
+ zmq_msg_send,
126
+ zmq_msg_set,
127
+ zmq_msg_set_group,
128
+ zmq_msg_set_routing_id,
129
+ zmq_msg_size,
130
+ zmq_msg_t,
131
+ zmq_pollitem_t,
132
+ zmq_proxy,
133
+ zmq_proxy_steerable,
134
+ zmq_setsockopt,
135
+ zmq_socket,
136
+ zmq_socket_monitor,
137
+ zmq_strerror,
138
+ zmq_unbind,
139
+ )
140
+ from cython.cimports.zmq.backend.cython.libzmq import zmq_errno as _zmq_errno
141
+ from cython.cimports.zmq.backend.cython.libzmq import zmq_poll as zmq_poll_c
142
+ from cython.cimports.zmq.utils.buffers import asbuffer_r
143
+
144
+ import zmq
145
+ from zmq.constants import SocketOption, _OptType
146
+ from zmq.error import InterruptedSystemCall, ZMQError, _check_version
147
+
148
+ IPC_PATH_MAX_LEN = get_ipc_path_max_len()
149
+
150
+
151
+ @cfunc
152
+ @inline
153
+ @C.exceptval(-1)
154
+ def _check_rc(rc: C.int, error_without_errno: bint = False) -> C.int:
155
+ """internal utility for checking zmq return condition
156
+
157
+ and raising the appropriate Exception class
158
+ """
159
+ errno: C.int = _zmq_errno()
160
+ PyErr_CheckSignals()
161
+ if errno == 0 and not error_without_errno:
162
+ return 0
163
+ if rc == -1: # if rc < -1, it's a bug in libzmq. Should we warn?
164
+ if errno == EINTR:
165
+ from zmq.error import InterruptedSystemCall
166
+
167
+ raise InterruptedSystemCall(errno)
168
+ elif errno == EAGAIN:
169
+ from zmq.error import Again
170
+
171
+ raise Again(errno)
172
+ elif errno == ZMQ_ETERM:
173
+ from zmq.error import ContextTerminated
174
+
175
+ raise ContextTerminated(errno)
176
+ else:
177
+ from zmq.error import ZMQError
178
+
179
+ raise ZMQError(errno)
180
+ return 0
181
+
182
+
183
+ # message Frame class
184
+
185
+ _zhint = C.struct(
186
+ sock=p_void,
187
+ mutex=pointer(mutex_t),
188
+ id=size_t,
189
+ )
190
+
191
+
192
+ @cfunc
193
+ @nogil
194
+ def free_python_msg(data: p_void, vhint: p_void) -> C.int:
195
+ """A pure-C function for DECREF'ing Python-owned message data.
196
+
197
+ Sends a message on a PUSH socket
198
+
199
+ The hint is a `zhint` struct with two values:
200
+
201
+ sock (void *): pointer to the Garbage Collector's PUSH socket
202
+ id (size_t): the id to be used to construct a zmq_msg_t that should be sent on a PUSH socket,
203
+ signaling the Garbage Collector to remove its reference to the object.
204
+
205
+ When the Garbage Collector's PULL socket receives the message,
206
+ it deletes its reference to the object,
207
+ allowing Python to free the memory.
208
+ """
209
+ msg = declare(zmq_msg_t)
210
+ msg_ptr: pointer(zmq_msg_t) = address(msg)
211
+ hint: pointer(_zhint) = cast(pointer(_zhint), vhint)
212
+ rc: C.int
213
+
214
+ if hint != NULL:
215
+ zmq_msg_init_size(msg_ptr, sizeof(size_t))
216
+ memcpy(zmq_msg_data(msg_ptr), address(hint.id), sizeof(size_t))
217
+ rc = mutex_lock(hint.mutex)
218
+ if rc != 0:
219
+ fprintf(cstderr, "pyzmq-gc mutex lock failed rc=%d\n", rc)
220
+ rc = zmq_msg_send(msg_ptr, hint.sock, 0)
221
+ if rc < 0:
222
+ # gc socket could have been closed, e.g. during process teardown.
223
+ # If so, ignore the failure because there's nothing to do.
224
+ if _zmq_errno() != ZMQ_ENOTSOCK:
225
+ fprintf(
226
+ cstderr, "pyzmq-gc send failed: %s\n", zmq_strerror(_zmq_errno())
227
+ )
228
+ rc = mutex_unlock(hint.mutex)
229
+ if rc != 0:
230
+ fprintf(cstderr, "pyzmq-gc mutex unlock failed rc=%d\n", rc)
231
+
232
+ zmq_msg_close(msg_ptr)
233
+ free(hint)
234
+ return 0
235
+
236
+
237
+ @cfunc
238
+ @inline
239
+ def _copy_zmq_msg_bytes(zmq_msg: pointer(zmq_msg_t)) -> bytes:
240
+ """Copy the data from a zmq_msg_t"""
241
+ data_c: p_char = NULL
242
+ data_len_c: Py_ssize_t
243
+ data_c = cast(p_char, zmq_msg_data(zmq_msg))
244
+ data_len_c = zmq_msg_size(zmq_msg)
245
+ return PyBytes_FromStringAndSize(data_c, data_len_c)
246
+
247
+
248
+ _gc = None
249
+
250
+
251
+ @cclass
252
+ class Frame:
253
+ def __init__(
254
+ self, data=None, track=False, copy=None, copy_threshold=None, **kwargs
255
+ ):
256
+ rc: C.int
257
+ data_c: p_char = NULL
258
+ data_len_c: Py_ssize_t = 0
259
+ hint: pointer(_zhint)
260
+ if copy_threshold is None:
261
+ copy_threshold = zmq.COPY_THRESHOLD
262
+
263
+ zmq_msg_ptr: pointer(zmq_msg_t) = address(self.zmq_msg)
264
+ # init more as False
265
+ self.more = False
266
+
267
+ # Save the data object in case the user wants the the data as a str.
268
+ self._data = data
269
+ self._failed_init = True # bool switch for dealloc
270
+ self._buffer = None # buffer view of data
271
+ self._bytes = None # bytes copy of data
272
+
273
+ self.tracker_event = None
274
+ self.tracker = None
275
+ # self.tracker should start finished
276
+ # except in the case where we are sharing memory with libzmq
277
+ if track:
278
+ self.tracker = zmq._FINISHED_TRACKER
279
+
280
+ if isinstance(data, str):
281
+ raise TypeError("Str objects not allowed. Only: bytes, buffer interfaces.")
282
+
283
+ if data is None:
284
+ rc = zmq_msg_init(zmq_msg_ptr)
285
+ _check_rc(rc)
286
+ self._failed_init = False
287
+ return
288
+
289
+ asbuffer_r(data, cast(pointer(p_void), address(data_c)), address(data_len_c))
290
+
291
+ # copy unspecified, apply copy_threshold
292
+ if copy is None:
293
+ if copy_threshold and data_len_c < copy_threshold:
294
+ copy = True
295
+ else:
296
+ copy = False
297
+
298
+ if copy:
299
+ # copy message data instead of sharing memory
300
+ rc = zmq_msg_init_size(zmq_msg_ptr, data_len_c)
301
+ _check_rc(rc)
302
+ memcpy(zmq_msg_data(zmq_msg_ptr), data_c, data_len_c)
303
+ self._failed_init = False
304
+ return
305
+
306
+ # Getting here means that we are doing a true zero-copy Frame,
307
+ # where libzmq and Python are sharing memory.
308
+ # Hook up garbage collection with MessageTracker and zmq_free_fn
309
+
310
+ # Event and MessageTracker for monitoring when zmq is done with data:
311
+ if track:
312
+ evt = Event()
313
+ self.tracker_event = evt
314
+ self.tracker = zmq.MessageTracker(evt)
315
+ # create the hint for zmq_free_fn
316
+ # two pointers: the gc context and a message to be sent to the gc PULL socket
317
+ # allows libzmq to signal to Python when it is done with Python-owned memory.
318
+ global _gc
319
+ if _gc is None:
320
+ from zmq.utils.garbage import gc as _gc
321
+
322
+ hint: pointer(_zhint) = cast(pointer(_zhint), malloc(sizeof(_zhint)))
323
+ hint.id = _gc.store(data, self.tracker_event)
324
+ if not _gc._push_mutex:
325
+ hint.mutex = mutex_allocate()
326
+ _gc._push_mutex = cast(size_t, hint.mutex)
327
+ else:
328
+ hint.mutex = cast(pointer(mutex_t), cast(size_t, _gc._push_mutex))
329
+ hint.sock = cast(p_void, cast(size_t, _gc._push_socket.underlying))
330
+
331
+ rc = zmq_msg_init_data(
332
+ zmq_msg_ptr,
333
+ cast(p_void, data_c),
334
+ data_len_c,
335
+ cast(pointer(zmq_free_fn), free_python_msg),
336
+ cast(p_void, hint),
337
+ )
338
+ if rc != 0:
339
+ free(hint)
340
+ _check_rc(rc)
341
+ self._failed_init = False
342
+
343
+ def __del__(self):
344
+ if self._failed_init:
345
+ return
346
+ # This simply decreases the 0MQ ref-count of zmq_msg.
347
+ with nogil:
348
+ rc: C.int = zmq_msg_close(address(self.zmq_msg))
349
+ _check_rc(rc)
350
+
351
+ def __copy__(self):
352
+ return self.fast_copy()
353
+
354
+ def fast_copy(self) -> Frame:
355
+ new_msg: Frame = Frame()
356
+ # This does not copy the contents, but just increases the ref-count
357
+ # of the zmq_msg by one.
358
+ zmq_msg_copy(address(new_msg.zmq_msg), address(self.zmq_msg))
359
+ # Copy the ref to data so the copy won't create a copy when str is
360
+ # called.
361
+ if self._data is not None:
362
+ new_msg._data = self._data
363
+ if self._buffer is not None:
364
+ new_msg._buffer = self._buffer
365
+ if self._bytes is not None:
366
+ new_msg._bytes = self._bytes
367
+
368
+ # Frame copies share the tracker and tracker_event
369
+ new_msg.tracker_event = self.tracker_event
370
+ new_msg.tracker = self.tracker
371
+
372
+ return new_msg
373
+
374
+ # buffer interface code adapted from petsc4py by Lisandro Dalcin, a BSD project
375
+
376
+ def __getbuffer__(self, buffer: pointer(Py_buffer), flags: C.int): # noqa: F821
377
+ # new-style (memoryview) buffer interface
378
+ buffer.buf = zmq_msg_data(address(self.zmq_msg))
379
+ buffer.len = zmq_msg_size(address(self.zmq_msg))
380
+
381
+ buffer.obj = self
382
+ buffer.readonly = 0
383
+ buffer.format = "B"
384
+ buffer.ndim = 1
385
+ buffer.shape = address(buffer.len)
386
+ buffer.strides = NULL
387
+ buffer.suboffsets = NULL
388
+ buffer.itemsize = 1
389
+ buffer.internal = NULL
390
+
391
+ def __len__(self) -> size_t:
392
+ """Return the length of the message in bytes."""
393
+ sz: size_t = zmq_msg_size(address(self.zmq_msg))
394
+ return sz
395
+
396
+ @property
397
+ def buffer(self):
398
+ """A memoryview of the message contents."""
399
+ _buffer = self._buffer and self._buffer()
400
+ if _buffer is not None:
401
+ return _buffer
402
+ _buffer = memoryview(self)
403
+ self._buffer = ref(_buffer)
404
+ return _buffer
405
+
406
+ @property
407
+ def bytes(self):
408
+ """The message content as a Python bytes object.
409
+
410
+ The first time this property is accessed, a copy of the message
411
+ contents is made. From then on that same copy of the message is
412
+ returned.
413
+ """
414
+ if self._bytes is None:
415
+ self._bytes = _copy_zmq_msg_bytes(address(self.zmq_msg))
416
+ return self._bytes
417
+
418
+ def get(self, option):
419
+ """
420
+ Get a Frame option or property.
421
+
422
+ See the 0MQ API documentation for zmq_msg_get and zmq_msg_gets
423
+ for details on specific options.
424
+
425
+ .. versionadded:: libzmq-3.2
426
+ .. versionadded:: 13.0
427
+
428
+ .. versionchanged:: 14.3
429
+ add support for zmq_msg_gets (requires libzmq-4.1)
430
+ All message properties are strings.
431
+
432
+ .. versionchanged:: 17.0
433
+ Added support for `routing_id` and `group`.
434
+ Only available if draft API is enabled
435
+ with libzmq >= 4.2.
436
+ """
437
+ rc: C.int = 0
438
+ property_c: p_char = NULL
439
+
440
+ # zmq_msg_get
441
+ if isinstance(option, int):
442
+ rc = zmq_msg_get(address(self.zmq_msg), option)
443
+ _check_rc(rc)
444
+ return rc
445
+
446
+ if option == 'routing_id':
447
+ routing_id: uint32_t = zmq_msg_routing_id(address(self.zmq_msg))
448
+ if routing_id == 0:
449
+ _check_rc(-1)
450
+ return routing_id
451
+ elif option == 'group':
452
+ buf = zmq_msg_group(address(self.zmq_msg))
453
+ if buf == NULL:
454
+ _check_rc(-1)
455
+ return buf.decode('utf8')
456
+
457
+ # zmq_msg_gets
458
+ _check_version((4, 1), "get string properties")
459
+ if isinstance(option, str):
460
+ option = option.encode('utf8')
461
+
462
+ if not isinstance(option, bytes):
463
+ raise TypeError(f"expected str, got: {option!r}")
464
+
465
+ property_c = option
466
+
467
+ result: p_char = cast(p_char, zmq_msg_gets(address(self.zmq_msg), property_c))
468
+ if result == NULL:
469
+ _check_rc(-1)
470
+ return result.decode('utf8')
471
+
472
+ def set(self, option, value):
473
+ """Set a Frame option.
474
+
475
+ See the 0MQ API documentation for zmq_msg_set
476
+ for details on specific options.
477
+
478
+ .. versionadded:: libzmq-3.2
479
+ .. versionadded:: 13.0
480
+ .. versionchanged:: 17.0
481
+ Added support for `routing_id` and `group`.
482
+ Only available if draft API is enabled
483
+ with libzmq >= 4.2.
484
+ """
485
+ rc: C.int
486
+
487
+ if option == 'routing_id':
488
+ routing_id: uint32_t = value
489
+ rc = zmq_msg_set_routing_id(address(self.zmq_msg), routing_id)
490
+ _check_rc(rc)
491
+ return
492
+ elif option == 'group':
493
+ if isinstance(value, str):
494
+ value = value.encode('utf8')
495
+ rc = zmq_msg_set_group(address(self.zmq_msg), value)
496
+ _check_rc(rc)
497
+ return
498
+
499
+ rc = zmq_msg_set(address(self.zmq_msg), option, value)
500
+ _check_rc(rc)
501
+
502
+
503
+ @cclass
504
+ class Context:
505
+ """
506
+ Manage the lifecycle of a 0MQ context.
507
+
508
+ Parameters
509
+ ----------
510
+ io_threads : int
511
+ The number of IO threads.
512
+ """
513
+
514
+ def __init__(self, io_threads: C.int = 1, shadow: size_t = 0):
515
+ self.handle = NULL
516
+ self._pid = 0
517
+ self._shadow = False
518
+
519
+ if shadow:
520
+ self.handle = cast(p_void, shadow)
521
+ self._shadow = True
522
+ else:
523
+ self._shadow = False
524
+ if ZMQ_VERSION_MAJOR >= 3:
525
+ self.handle = zmq_ctx_new()
526
+ else:
527
+ self.handle = zmq_init(io_threads)
528
+
529
+ if self.handle == NULL:
530
+ raise ZMQError()
531
+
532
+ rc: C.int = 0
533
+ if ZMQ_VERSION_MAJOR >= 3 and not self._shadow:
534
+ rc = zmq_ctx_set(self.handle, ZMQ_IO_THREADS, io_threads)
535
+ _check_rc(rc)
536
+
537
+ self.closed = False
538
+ self._pid = getpid()
539
+
540
+ @property
541
+ def underlying(self):
542
+ """The address of the underlying libzmq context"""
543
+ return cast(size_t, self.handle)
544
+
545
+ @cfunc
546
+ @inline
547
+ def _term(self) -> C.int:
548
+ rc: C.int = 0
549
+ if self.handle != NULL and not self.closed and getpid() == self._pid:
550
+ with nogil:
551
+ rc = zmq_ctx_destroy(self.handle)
552
+ self.handle = NULL
553
+ return rc
554
+
555
+ def term(self):
556
+ """
557
+ Close or terminate the context.
558
+
559
+ This can be called to close the context by hand. If this is not called,
560
+ the context will automatically be closed when it is garbage collected.
561
+ """
562
+ rc: C.int = self._term()
563
+ try:
564
+ _check_rc(rc)
565
+ except InterruptedSystemCall:
566
+ # ignore interrupted term
567
+ # see PEP 475 notes about close & EINTR for why
568
+ pass
569
+
570
+ self.closed = True
571
+
572
+ def set(self, option: C.int, optval):
573
+ """
574
+ Set a context option.
575
+
576
+ See the 0MQ API documentation for zmq_ctx_set
577
+ for details on specific options.
578
+
579
+ .. versionadded:: libzmq-3.2
580
+ .. versionadded:: 13.0
581
+
582
+ Parameters
583
+ ----------
584
+ option : int
585
+ The option to set. Available values will depend on your
586
+ version of libzmq. Examples include::
587
+
588
+ zmq.IO_THREADS, zmq.MAX_SOCKETS
589
+
590
+ optval : int
591
+ The value of the option to set.
592
+ """
593
+ optval_int_c: C.int
594
+ rc: C.int
595
+
596
+ if self.closed:
597
+ raise RuntimeError("Context has been destroyed")
598
+
599
+ if not isinstance(optval, int):
600
+ raise TypeError(f'expected int, got: {optval!r}')
601
+ optval_int_c = optval
602
+ rc = zmq_ctx_set(self.handle, option, optval_int_c)
603
+ _check_rc(rc)
604
+
605
+ def get(self, option: C.int):
606
+ """
607
+ Get the value of a context option.
608
+
609
+ See the 0MQ API documentation for zmq_ctx_get
610
+ for details on specific options.
611
+
612
+ .. versionadded:: libzmq-3.2
613
+ .. versionadded:: 13.0
614
+
615
+ Parameters
616
+ ----------
617
+ option : int
618
+ The option to get. Available values will depend on your
619
+ version of libzmq. Examples include::
620
+
621
+ zmq.IO_THREADS, zmq.MAX_SOCKETS
622
+
623
+ Returns
624
+ -------
625
+ optval : int
626
+ The value of the option as an integer.
627
+ """
628
+ rc: C.int
629
+
630
+ if self.closed:
631
+ raise RuntimeError("Context has been destroyed")
632
+
633
+ rc = zmq_ctx_get(self.handle, option)
634
+ _check_rc(rc, error_without_errno=False)
635
+ return rc
636
+
637
+
638
+ @cclass
639
+ class Socket:
640
+ """
641
+ A 0MQ socket.
642
+
643
+ These objects will generally be constructed via the socket() method of a Context object.
644
+
645
+ Note: 0MQ Sockets are *not* threadsafe. **DO NOT** share them across threads.
646
+
647
+ Parameters
648
+ ----------
649
+ context : Context
650
+ The 0MQ Context this Socket belongs to.
651
+ socket_type : int
652
+ The socket type, which can be any of the 0MQ socket types:
653
+ REQ, REP, PUB, SUB, PAIR, DEALER, ROUTER, PULL, PUSH, XPUB, XSUB.
654
+
655
+ See Also
656
+ --------
657
+ .Context.socket : method for creating a socket bound to a Context.
658
+ """
659
+
660
+ def __init__(
661
+ self,
662
+ context=None,
663
+ socket_type: C.int = -1,
664
+ shadow: size_t = 0,
665
+ copy_threshold=None,
666
+ ):
667
+ # pre-init
668
+ self.handle = NULL
669
+ self._pid = 0
670
+ self._shadow = False
671
+ self.context = None
672
+
673
+ if copy_threshold is None:
674
+ copy_threshold = zmq.COPY_THRESHOLD
675
+ self.copy_threshold = copy_threshold
676
+
677
+ self.handle = NULL
678
+ self.context = context
679
+ if shadow:
680
+ self._shadow = True
681
+ self.handle = cast(p_void, shadow)
682
+ else:
683
+ if context is None:
684
+ raise TypeError("context must be specified")
685
+ if socket_type < 0:
686
+ raise TypeError("socket_type must be specified")
687
+ self._shadow = False
688
+ self.handle = zmq_socket(self.context.handle, socket_type)
689
+ if self.handle == NULL:
690
+ raise ZMQError()
691
+ self._closed = False
692
+ self._pid = getpid()
693
+
694
+ @property
695
+ def underlying(self):
696
+ """The address of the underlying libzmq socket"""
697
+ return cast(size_t, self.handle)
698
+
699
+ @property
700
+ def closed(self):
701
+ """Whether the socket is closed"""
702
+ return _check_closed_deep(self)
703
+
704
+ def close(self, linger=None):
705
+ """
706
+ Close the socket.
707
+
708
+ If linger is specified, LINGER sockopt will be set prior to closing.
709
+
710
+ This can be called to close the socket by hand. If this is not
711
+ called, the socket will automatically be closed when it is
712
+ garbage collected.
713
+ """
714
+ rc: C.int = 0
715
+ linger_c: C.int
716
+ setlinger: bint = False
717
+
718
+ if linger is not None:
719
+ linger_c = linger
720
+ setlinger = True
721
+
722
+ if self.handle != NULL and not self._closed and getpid() == self._pid:
723
+ if setlinger:
724
+ zmq_setsockopt(self.handle, ZMQ_LINGER, address(linger_c), sizeof(int))
725
+ rc = zmq_close(self.handle)
726
+ if rc < 0 and zmq_errno() != ENOTSOCK:
727
+ # ignore ENOTSOCK (closed by Context)
728
+ _check_rc(rc)
729
+ self._closed = True
730
+ self.handle = NULL
731
+
732
+ def set(self, option: C.int, optval):
733
+ """
734
+ Set socket options.
735
+
736
+ See the 0MQ API documentation for details on specific options.
737
+
738
+ Parameters
739
+ ----------
740
+ option : int
741
+ The option to set. Available values will depend on your
742
+ version of libzmq. Examples include::
743
+
744
+ zmq.SUBSCRIBE, UNSUBSCRIBE, IDENTITY, HWM, LINGER, FD
745
+
746
+ optval : int or bytes
747
+ The value of the option to set.
748
+
749
+ Notes
750
+ -----
751
+ .. warning::
752
+
753
+ All options other than zmq.SUBSCRIBE, zmq.UNSUBSCRIBE and
754
+ zmq.LINGER only take effect for subsequent socket bind/connects.
755
+ """
756
+ optval_int64_c: int64_t
757
+ optval_int_c: C.int
758
+ optval_c: p_char
759
+ sz: Py_ssize_t
760
+
761
+ _check_closed(self)
762
+ if isinstance(optval, str):
763
+ raise TypeError("unicode not allowed, use setsockopt_string")
764
+
765
+ try:
766
+ sopt = SocketOption(option)
767
+ except ValueError:
768
+ # unrecognized option,
769
+ # assume from the future,
770
+ # let EINVAL raise
771
+ opt_type = _OptType.int
772
+ else:
773
+ opt_type = sopt._opt_type
774
+
775
+ if opt_type == _OptType.bytes:
776
+ if not isinstance(optval, bytes):
777
+ raise TypeError(f'expected bytes, got: {optval!r}')
778
+ optval_c = PyBytes_AsString(optval)
779
+ sz = PyBytes_Size(optval)
780
+ _setsockopt(self.handle, option, optval_c, sz)
781
+ elif opt_type == _OptType.int64:
782
+ if not isinstance(optval, int):
783
+ raise TypeError(f'expected int, got: {optval!r}')
784
+ optval_int64_c = optval
785
+ _setsockopt(self.handle, option, address(optval_int64_c), sizeof(int64_t))
786
+ else:
787
+ # default is to assume int, which is what most new sockopts will be
788
+ # this lets pyzmq work with newer libzmq which may add constants
789
+ # pyzmq has not yet added, rather than artificially raising. Invalid
790
+ # sockopts will still raise just the same, but it will be libzmq doing
791
+ # the raising.
792
+ if not isinstance(optval, int):
793
+ raise TypeError(f'expected int, got: {optval!r}')
794
+ optval_int_c = optval
795
+ _setsockopt(self.handle, option, address(optval_int_c), sizeof(int))
796
+
797
+ def get(self, option: C.int):
798
+ """
799
+ Get the value of a socket option.
800
+
801
+ See the 0MQ API documentation for details on specific options.
802
+
803
+ Parameters
804
+ ----------
805
+ option : int
806
+ The option to get. Available values will depend on your
807
+ version of libzmq. Examples include::
808
+
809
+ zmq.IDENTITY, HWM, LINGER, FD, EVENTS
810
+
811
+ Returns
812
+ -------
813
+ optval : int or bytes
814
+ The value of the option as a bytestring or int.
815
+ """
816
+ optval_int64_c = declare(int64_t)
817
+ optval_int_c = declare(C.int)
818
+ optval_fd_c = declare(fd_t)
819
+ identity_str_c = declare(char[255])
820
+ sz: size_t
821
+
822
+ _check_closed(self)
823
+
824
+ try:
825
+ sopt = SocketOption(option)
826
+ except ValueError:
827
+ # unrecognized option,
828
+ # assume from the future,
829
+ # let EINVAL raise
830
+ opt_type = _OptType.int
831
+ else:
832
+ opt_type = sopt._opt_type
833
+
834
+ if opt_type == _OptType.bytes:
835
+ sz = 255
836
+ _getsockopt(self.handle, option, cast(p_void, identity_str_c), address(sz))
837
+ # strip null-terminated strings *except* identity
838
+ if (
839
+ option != ZMQ_IDENTITY
840
+ and sz > 0
841
+ and (cast(p_char, identity_str_c))[sz - 1] == b'\0'
842
+ ):
843
+ sz -= 1
844
+ result = PyBytes_FromStringAndSize(cast(p_char, identity_str_c), sz)
845
+ elif opt_type == _OptType.int64:
846
+ sz = sizeof(int64_t)
847
+ _getsockopt(
848
+ self.handle, option, cast(p_void, address(optval_int64_c)), address(sz)
849
+ )
850
+ result = optval_int64_c
851
+ elif opt_type == _OptType.fd:
852
+ sz = sizeof(fd_t)
853
+ _getsockopt(
854
+ self.handle, option, cast(p_void, address(optval_fd_c)), address(sz)
855
+ )
856
+ result = optval_fd_c
857
+ else:
858
+ # default is to assume int, which is what most new sockopts will be
859
+ # this lets pyzmq work with newer libzmq which may add constants
860
+ # pyzmq has not yet added, rather than artificially raising. Invalid
861
+ # sockopts will still raise just the same, but it will be libzmq doing
862
+ # the raising.
863
+ sz = sizeof(int)
864
+ _getsockopt(
865
+ self.handle, option, cast(p_void, address(optval_int_c)), address(sz)
866
+ )
867
+ result = optval_int_c
868
+
869
+ return result
870
+
871
+ def bind(self, addr):
872
+ """
873
+ Bind the socket to an address.
874
+
875
+ This causes the socket to listen on a network port. Sockets on the
876
+ other side of this connection will use ``Socket.connect(addr)`` to
877
+ connect to this socket.
878
+
879
+ Parameters
880
+ ----------
881
+ addr : str
882
+ The address string. This has the form 'protocol://interface:port',
883
+ for example 'tcp://127.0.0.1:5555'. Protocols supported include
884
+ tcp, udp, pgm, epgm, inproc and ipc. If the address is unicode, it is
885
+ encoded to utf-8 first.
886
+ """
887
+ rc: C.int
888
+ c_addr: p_char
889
+
890
+ _check_closed(self)
891
+ addr_b = addr
892
+ if isinstance(addr, str):
893
+ addr_b = addr.encode('utf-8')
894
+ elif isinstance(addr_b, bytes):
895
+ addr = addr_b.decode('utf-8')
896
+
897
+ if not isinstance(addr_b, bytes):
898
+ raise TypeError(f'expected str, got: {addr!r}')
899
+ c_addr = addr_b
900
+ rc = zmq_bind(self.handle, c_addr)
901
+ if rc != 0:
902
+ if IPC_PATH_MAX_LEN and zmq_errno() == ENAMETOOLONG:
903
+ path = addr.split('://', 1)[-1]
904
+ msg = (
905
+ f'ipc path "{path}" is longer than {IPC_PATH_MAX_LEN} '
906
+ 'characters (sizeof(sockaddr_un.sun_path)). '
907
+ 'zmq.IPC_PATH_MAX_LEN constant can be used '
908
+ 'to check addr length (if it is defined).'
909
+ )
910
+ raise ZMQError(msg=msg)
911
+ elif zmq_errno() == ENOENT:
912
+ path = addr.split('://', 1)[-1]
913
+ msg = f'No such file or directory for ipc path "{path}".'
914
+ raise ZMQError(msg=msg)
915
+ while True:
916
+ try:
917
+ _check_rc(rc)
918
+ except InterruptedSystemCall:
919
+ rc = zmq_bind(self.handle, c_addr)
920
+ continue
921
+ else:
922
+ break
923
+
924
+ def connect(self, addr):
925
+ """
926
+ Connect to a remote 0MQ socket.
927
+
928
+ Parameters
929
+ ----------
930
+ addr : str
931
+ The address string. This has the form 'protocol://interface:port',
932
+ for example 'tcp://127.0.0.1:5555'. Protocols supported are
933
+ tcp, udp, pgm, inproc and ipc. If the address is unicode, it is
934
+ encoded to utf-8 first.
935
+ """
936
+ rc: C.int
937
+ c_addr: p_char
938
+
939
+ _check_closed(self)
940
+ if isinstance(addr, str):
941
+ addr = addr.encode('utf-8')
942
+ if not isinstance(addr, bytes):
943
+ raise TypeError(f'expected str, got: {addr!r}')
944
+ c_addr = addr
945
+
946
+ while True:
947
+ try:
948
+ rc = zmq_connect(self.handle, c_addr)
949
+ _check_rc(rc)
950
+ except InterruptedSystemCall:
951
+ # retry syscall
952
+ continue
953
+ else:
954
+ break
955
+
956
+ def unbind(self, addr):
957
+ """
958
+ Unbind from an address (undoes a call to bind).
959
+
960
+ .. versionadded:: libzmq-3.2
961
+ .. versionadded:: 13.0
962
+
963
+ Parameters
964
+ ----------
965
+ addr : str
966
+ The address string. This has the form 'protocol://interface:port',
967
+ for example 'tcp://127.0.0.1:5555'. Protocols supported are
968
+ tcp, udp, pgm, inproc and ipc. If the address is unicode, it is
969
+ encoded to utf-8 first.
970
+ """
971
+ rc: C.int
972
+ c_addr: p_char
973
+
974
+ _check_version((3, 2), "unbind")
975
+ _check_closed(self)
976
+ if isinstance(addr, str):
977
+ addr = addr.encode('utf-8')
978
+ if not isinstance(addr, bytes):
979
+ raise TypeError(f'expected str, got: {addr!r}')
980
+ c_addr = addr
981
+
982
+ rc = zmq_unbind(self.handle, c_addr)
983
+ if rc != 0:
984
+ raise ZMQError()
985
+
986
+ def disconnect(self, addr):
987
+ """
988
+ Disconnect from a remote 0MQ socket (undoes a call to connect).
989
+
990
+ .. versionadded:: libzmq-3.2
991
+ .. versionadded:: 13.0
992
+
993
+ Parameters
994
+ ----------
995
+ addr : str
996
+ The address string. This has the form 'protocol://interface:port',
997
+ for example 'tcp://127.0.0.1:5555'. Protocols supported are
998
+ tcp, udp, pgm, inproc and ipc. If the address is unicode, it is
999
+ encoded to utf-8 first.
1000
+ """
1001
+ rc: C.int
1002
+ c_addr: p_char
1003
+
1004
+ _check_version((3, 2), "disconnect")
1005
+ _check_closed(self)
1006
+ if isinstance(addr, str):
1007
+ addr = addr.encode('utf-8')
1008
+ if not isinstance(addr, bytes):
1009
+ raise TypeError(f'expected str, got: {addr!r}')
1010
+ c_addr = addr
1011
+
1012
+ rc = zmq_disconnect(self.handle, c_addr)
1013
+ if rc != 0:
1014
+ raise ZMQError()
1015
+
1016
+ def monitor(self, addr, events: C.int = ZMQ_EVENT_ALL):
1017
+ """
1018
+ Start publishing socket events on inproc.
1019
+ See libzmq docs for zmq_monitor for details.
1020
+
1021
+ While this function is available from libzmq 3.2,
1022
+ pyzmq cannot parse monitor messages from libzmq prior to 4.0.
1023
+
1024
+ .. versionadded: libzmq-3.2
1025
+ .. versionadded: 14.0
1026
+
1027
+ Parameters
1028
+ ----------
1029
+ addr : str
1030
+ The inproc url used for monitoring. Passing None as
1031
+ the addr will cause an existing socket monitor to be
1032
+ deregistered.
1033
+ events : int
1034
+ default: zmq.EVENT_ALL
1035
+ The zmq event bitmask for which events will be sent to the monitor.
1036
+ """
1037
+ _check_version((3, 2), "monitor")
1038
+
1039
+ if isinstance(addr, str):
1040
+ # cast str to utf8 bytes
1041
+ addr = addr.encode("utf-8")
1042
+
1043
+ # cast bytes to char*
1044
+ c_addr: p_char
1045
+
1046
+ if addr is None:
1047
+ c_addr = NULL
1048
+ else:
1049
+ # let Cython do the casting,
1050
+ # but return a nicer error message if it fails
1051
+ try:
1052
+ c_addr = addr
1053
+ except TypeError:
1054
+ raise TypeError(f"Monitor addr must be str, got {addr!r}") from None
1055
+
1056
+ _check_rc(zmq_socket_monitor(self.handle, c_addr, events))
1057
+
1058
+ def join(self, group):
1059
+ """
1060
+ Join a RADIO-DISH group
1061
+
1062
+ Only for DISH sockets.
1063
+
1064
+ libzmq and pyzmq must have been built with ZMQ_BUILD_DRAFT_API
1065
+
1066
+ .. versionadded:: 17
1067
+ """
1068
+ _check_version((4, 2), "RADIO-DISH")
1069
+ if not zmq.has('draft'):
1070
+ raise RuntimeError("libzmq must be built with draft support")
1071
+ if isinstance(group, str):
1072
+ group = group.encode('utf8')
1073
+ rc: C.int = zmq_join(self.handle, group)
1074
+ _check_rc(rc)
1075
+
1076
+ def leave(self, group):
1077
+ """
1078
+ Leave a RADIO-DISH group
1079
+
1080
+ Only for DISH sockets.
1081
+
1082
+ libzmq and pyzmq must have been built with ZMQ_BUILD_DRAFT_API
1083
+
1084
+ .. versionadded:: 17
1085
+ """
1086
+ _check_version((4, 2), "RADIO-DISH")
1087
+ if not zmq.has('draft'):
1088
+ raise RuntimeError("libzmq must be built with draft support")
1089
+ rc: C.int = zmq_leave(self.handle, group)
1090
+ _check_rc(rc)
1091
+
1092
+ def send(self, data, flags=0, copy: bint = True, track: bint = False):
1093
+ """
1094
+ Send a single zmq message frame on this socket.
1095
+
1096
+ This queues the message to be sent by the IO thread at a later time.
1097
+
1098
+ With flags=NOBLOCK, this raises :class:`ZMQError` if the queue is full;
1099
+ otherwise, this waits until space is available.
1100
+ See :class:`Poller` for more general non-blocking I/O.
1101
+
1102
+ Parameters
1103
+ ----------
1104
+ data : bytes, Frame, memoryview
1105
+ The content of the message. This can be any object that provides
1106
+ the Python buffer API (`memoryview(data)` can be called).
1107
+ flags : int
1108
+ 0, NOBLOCK, SNDMORE, or NOBLOCK|SNDMORE.
1109
+ copy : bool
1110
+ Should the message be sent in a copying or non-copying manner.
1111
+ track : bool
1112
+ Should the message be tracked for notification that ZMQ has
1113
+ finished with it? (ignored if copy=True)
1114
+
1115
+ Returns
1116
+ -------
1117
+ None : if `copy` or not track
1118
+ None if message was sent, raises an exception otherwise.
1119
+ MessageTracker : if track and not copy
1120
+ a MessageTracker object, whose `done` property will
1121
+ be False until the send is completed.
1122
+
1123
+ Raises
1124
+ ------
1125
+ TypeError
1126
+ If a unicode object is passed
1127
+ ValueError
1128
+ If `track=True`, but an untracked Frame is passed.
1129
+ ZMQError
1130
+ for any of the reasons zmq_msg_send might fail (including
1131
+ if NOBLOCK is set and the outgoing queue is full).
1132
+
1133
+ """
1134
+ _check_closed(self)
1135
+
1136
+ if isinstance(data, str):
1137
+ raise TypeError("unicode not allowed, use send_string")
1138
+
1139
+ if copy and not isinstance(data, Frame):
1140
+ return _send_copy(self.handle, data, flags)
1141
+ else:
1142
+ if isinstance(data, Frame):
1143
+ if track and not data.tracker:
1144
+ raise ValueError('Not a tracked message')
1145
+ msg = data
1146
+ else:
1147
+ if self.copy_threshold:
1148
+ buf = memoryview(data)
1149
+ # always copy messages smaller than copy_threshold
1150
+ if buf.nbytes < self.copy_threshold:
1151
+ _send_copy(self.handle, buf, flags)
1152
+ return zmq._FINISHED_TRACKER
1153
+ msg = Frame(data, track=track, copy_threshold=self.copy_threshold)
1154
+ return _send_frame(self.handle, msg, flags)
1155
+
1156
+ def recv(self, flags=0, copy: bint = True, track: bint = False):
1157
+ """
1158
+ Receive a message.
1159
+
1160
+ With flags=NOBLOCK, this raises :class:`ZMQError` if no messages have
1161
+ arrived; otherwise, this waits until a message arrives.
1162
+ See :class:`Poller` for more general non-blocking I/O.
1163
+
1164
+ Parameters
1165
+ ----------
1166
+ flags : int
1167
+ 0 or NOBLOCK.
1168
+ copy : bool
1169
+ Should the message be received in a copying or non-copying manner?
1170
+ If False a Frame object is returned, if True a string copy of
1171
+ message is returned.
1172
+ track : bool
1173
+ Should the message be tracked for notification that ZMQ has
1174
+ finished with it? (ignored if copy=True)
1175
+
1176
+ Returns
1177
+ -------
1178
+ msg : bytes or Frame
1179
+ The received message frame. If `copy` is False, then it will be a Frame,
1180
+ otherwise it will be bytes.
1181
+
1182
+ Raises
1183
+ ------
1184
+ ZMQError
1185
+ for any of the reasons zmq_msg_recv might fail (including if
1186
+ NOBLOCK is set and no new messages have arrived).
1187
+ """
1188
+ _check_closed(self)
1189
+
1190
+ if copy:
1191
+ return _recv_copy(self.handle, flags)
1192
+ else:
1193
+ frame = _recv_frame(self.handle, flags, track)
1194
+ frame.more = self.get(zmq.RCVMORE)
1195
+ return frame
1196
+
1197
+
1198
+ # inline socket methods
1199
+
1200
+
1201
+ @inline
1202
+ @cfunc
1203
+ def _check_closed(s: Socket):
1204
+ """raise ENOTSUP if socket is closed
1205
+
1206
+ Does not do a deep check
1207
+ """
1208
+ if s._closed:
1209
+ raise ZMQError(ENOTSOCK)
1210
+
1211
+
1212
+ @inline
1213
+ @cfunc
1214
+ def _check_closed_deep(s: Socket) -> bint:
1215
+ """thorough check of whether the socket has been closed,
1216
+ even if by another entity (e.g. ctx.destroy).
1217
+
1218
+ Only used by the `closed` property.
1219
+
1220
+ returns True if closed, False otherwise
1221
+ """
1222
+ rc: C.int
1223
+ errno: C.int
1224
+ stype = declare(C.int)
1225
+ sz: size_t = sizeof(int)
1226
+
1227
+ if s._closed:
1228
+ return True
1229
+ else:
1230
+ rc = zmq_getsockopt(
1231
+ s.handle, ZMQ_TYPE, cast(p_void, address(stype)), address(sz)
1232
+ )
1233
+ if rc < 0:
1234
+ errno = zmq_errno()
1235
+ if errno == ENOTSOCK:
1236
+ s._closed = True
1237
+ return True
1238
+ elif errno == ZMQ_ETERM:
1239
+ # don't raise ETERM when checking if we're closed
1240
+ return False
1241
+ else:
1242
+ _check_rc(rc)
1243
+ return False
1244
+
1245
+
1246
+ @cfunc
1247
+ @inline
1248
+ def _recv_frame(handle: p_void, flags: C.int = 0, track: bint = False) -> Frame:
1249
+ """Receive a message in a non-copying manner and return a Frame."""
1250
+ rc: C.int
1251
+ msg = zmq.Frame(track=track)
1252
+ cmsg: Frame = msg
1253
+
1254
+ while True:
1255
+ with nogil:
1256
+ rc = zmq_msg_recv(address(cmsg.zmq_msg), handle, flags)
1257
+ try:
1258
+ _check_rc(rc)
1259
+ except InterruptedSystemCall:
1260
+ continue
1261
+ else:
1262
+ break
1263
+ return msg
1264
+
1265
+
1266
+ @cfunc
1267
+ @inline
1268
+ def _recv_copy(handle: p_void, flags: C.int = 0):
1269
+ """Receive a message and return a copy"""
1270
+ zmq_msg = declare(zmq_msg_t)
1271
+ zmq_msg_p: pointer(zmq_msg_t) = address(zmq_msg)
1272
+ rc: C.int = zmq_msg_init(zmq_msg_p)
1273
+ _check_rc(rc)
1274
+ while True:
1275
+ with nogil:
1276
+ rc = zmq_msg_recv(zmq_msg_p, handle, flags)
1277
+ try:
1278
+ _check_rc(rc)
1279
+ except InterruptedSystemCall:
1280
+ continue
1281
+ except Exception:
1282
+ zmq_msg_close(zmq_msg_p) # ensure msg is closed on failure
1283
+ raise
1284
+ else:
1285
+ break
1286
+
1287
+ msg_bytes = _copy_zmq_msg_bytes(zmq_msg_p)
1288
+ zmq_msg_close(zmq_msg_p)
1289
+ return msg_bytes
1290
+
1291
+
1292
+ @cfunc
1293
+ @inline
1294
+ def _send_frame(handle: p_void, msg: Frame, flags: C.int = 0):
1295
+ """Send a Frame on this socket in a non-copy manner."""
1296
+ rc: C.int
1297
+ msg_copy: Frame
1298
+
1299
+ # Always copy so the original message isn't garbage collected.
1300
+ # This doesn't do a real copy, just a reference.
1301
+ msg_copy = msg.fast_copy()
1302
+
1303
+ while True:
1304
+ with nogil:
1305
+ rc = zmq_msg_send(address(msg_copy.zmq_msg), handle, flags)
1306
+ try:
1307
+ _check_rc(rc)
1308
+ except InterruptedSystemCall:
1309
+ continue
1310
+ else:
1311
+ break
1312
+
1313
+ return msg.tracker
1314
+
1315
+
1316
+ @cfunc
1317
+ @inline
1318
+ def _send_copy(handle: p_void, buf, flags: C.int = 0):
1319
+ """Send a message on this socket by copying its content."""
1320
+ rc: C.int
1321
+ msg = declare(zmq_msg_t)
1322
+ c_bytes = declare(p_char)
1323
+ c_bytes_len: Py_ssize_t = 0
1324
+
1325
+ # copy to c array:
1326
+ asbuffer_r(buf, cast(pointer(p_void), address(c_bytes)), address(c_bytes_len))
1327
+
1328
+ # Copy the msg before sending. This avoids any complications with
1329
+ # the GIL, etc.
1330
+ # If zmq_msg_init_* fails we must not call zmq_msg_close (Bus Error)
1331
+ rc = zmq_msg_init_size(address(msg), c_bytes_len)
1332
+ _check_rc(rc)
1333
+
1334
+ while True:
1335
+ with nogil:
1336
+ memcpy(zmq_msg_data(address(msg)), c_bytes, zmq_msg_size(address(msg)))
1337
+ rc = zmq_msg_send(address(msg), handle, flags)
1338
+ try:
1339
+ _check_rc(rc)
1340
+ except InterruptedSystemCall:
1341
+ continue
1342
+ except Exception:
1343
+ zmq_msg_close(address(msg)) # close the unused msg
1344
+ raise # raise original exception
1345
+ else:
1346
+ rc = zmq_msg_close(address(msg))
1347
+ _check_rc(rc)
1348
+ break
1349
+
1350
+
1351
+ @cfunc
1352
+ @inline
1353
+ def _getsockopt(handle: p_void, option: C.int, optval: p_void, sz: pointer(size_t)):
1354
+ """getsockopt, retrying interrupted calls
1355
+
1356
+ checks rc, raising ZMQError on failure.
1357
+ """
1358
+ rc: C.int = 0
1359
+ while True:
1360
+ rc = zmq_getsockopt(handle, option, optval, sz)
1361
+ try:
1362
+ _check_rc(rc)
1363
+ except InterruptedSystemCall:
1364
+ continue
1365
+ else:
1366
+ break
1367
+
1368
+
1369
+ @cfunc
1370
+ @inline
1371
+ def _setsockopt(handle: p_void, option: C.int, optval: p_void, sz: size_t):
1372
+ """setsockopt, retrying interrupted calls
1373
+
1374
+ checks rc, raising ZMQError on failure.
1375
+ """
1376
+ rc: C.int = 0
1377
+ while True:
1378
+ rc = zmq_setsockopt(handle, option, optval, sz)
1379
+ try:
1380
+ _check_rc(rc)
1381
+ except InterruptedSystemCall:
1382
+ continue
1383
+ else:
1384
+ break
1385
+
1386
+
1387
+ # General utility functions
1388
+
1389
+
1390
+ def zmq_errno():
1391
+ """Return the integer errno of the most recent zmq error."""
1392
+ return _zmq_errno()
1393
+
1394
+
1395
+ def strerror(errno: C.int) -> str:
1396
+ """
1397
+ Return the error string given the error number.
1398
+ """
1399
+ str_e: bytes = zmq_strerror(errno)
1400
+ return str_e.decode("utf8", "replace")
1401
+
1402
+
1403
+ def zmq_version_info() -> tuple[int, int, int]:
1404
+ """Return the version of ZeroMQ itself as a 3-tuple of ints."""
1405
+ major: C.int = 0
1406
+ minor: C.int = 0
1407
+ patch: C.int = 0
1408
+ _zmq_version(address(major), address(minor), address(patch))
1409
+ return (major, minor, patch)
1410
+
1411
+
1412
+ def has(capability) -> bool:
1413
+ """Check for zmq capability by name (e.g. 'ipc', 'curve')
1414
+
1415
+ .. versionadded:: libzmq-4.1
1416
+ .. versionadded:: 14.1
1417
+ """
1418
+ _check_version((4, 1), 'zmq.has')
1419
+ ccap: bytes
1420
+ if isinstance(capability, str):
1421
+ capability = capability.encode('utf8')
1422
+ ccap = capability
1423
+ return bool(zmq_has(ccap))
1424
+
1425
+
1426
+ def curve_keypair() -> tuple[bytes, bytes]:
1427
+ """generate a Z85 key pair for use with zmq.CURVE security
1428
+
1429
+ Requires libzmq (≥ 4.0) to have been built with CURVE support.
1430
+
1431
+ .. versionadded:: libzmq-4.0
1432
+ .. versionadded:: 14.0
1433
+
1434
+ Returns
1435
+ -------
1436
+ public: bytes
1437
+ The public key as 40 byte z85-encoded bytestring.
1438
+ private: bytes
1439
+ The private key as 40 byte z85-encoded bytestring.
1440
+ """
1441
+ rc: C.int
1442
+ public_key = declare(char[64])
1443
+ secret_key = declare(char[64])
1444
+ _check_version((4, 0), "curve_keypair")
1445
+ # see huge comment in libzmq/src/random.cpp
1446
+ # about threadsafety of random initialization
1447
+ rc = zmq_curve_keypair(public_key, secret_key)
1448
+ _check_rc(rc)
1449
+ return public_key, secret_key
1450
+
1451
+
1452
+ def curve_public(secret_key) -> bytes:
1453
+ """Compute the public key corresponding to a secret key for use
1454
+ with zmq.CURVE security
1455
+
1456
+ Requires libzmq (≥ 4.2) to have been built with CURVE support.
1457
+
1458
+ Parameters
1459
+ ----------
1460
+ private
1461
+ The private key as a 40 byte z85-encoded bytestring
1462
+
1463
+ Returns
1464
+ -------
1465
+ bytes
1466
+ The public key as a 40 byte z85-encoded bytestring
1467
+ """
1468
+ if isinstance(secret_key, str):
1469
+ secret_key = secret_key.encode('utf8')
1470
+ if not len(secret_key) == 40:
1471
+ raise ValueError('secret key must be a 40 byte z85 encoded string')
1472
+
1473
+ rc: C.int
1474
+ public_key = declare(char[64])
1475
+ c_secret_key: pointer(char) = secret_key
1476
+ _check_version((4, 2), "curve_public")
1477
+ # see huge comment in libzmq/src/random.cpp
1478
+ # about threadsafety of random initialization
1479
+ rc = zmq_curve_public(public_key, c_secret_key)
1480
+ _check_rc(rc)
1481
+ return public_key[:40]
1482
+
1483
+
1484
+ # polling
1485
+ def zmq_poll(sockets, timeout: C.int = -1):
1486
+ """zmq_poll(sockets, timeout=-1)
1487
+
1488
+ Poll a set of 0MQ sockets, native file descs. or sockets.
1489
+
1490
+ Parameters
1491
+ ----------
1492
+ sockets : list of tuples of (socket, flags)
1493
+ Each element of this list is a two-tuple containing a socket
1494
+ and a flags. The socket may be a 0MQ socket or any object with
1495
+ a ``fileno()`` method. The flags can be zmq.POLLIN (for detecting
1496
+ for incoming messages), zmq.POLLOUT (for detecting that send is OK)
1497
+ or zmq.POLLIN|zmq.POLLOUT for detecting both.
1498
+ timeout : int
1499
+ The number of milliseconds to poll for. Negative means no timeout.
1500
+ """
1501
+ rc: C.int
1502
+ i: C.int
1503
+ pollitems: pointer(zmq_pollitem_t) = NULL
1504
+ nsockets: C.int = len(sockets)
1505
+
1506
+ if nsockets == 0:
1507
+ return []
1508
+
1509
+ pollitems = cast(pointer(zmq_pollitem_t), malloc(nsockets * sizeof(zmq_pollitem_t)))
1510
+ if pollitems == NULL:
1511
+ raise MemoryError("Could not allocate poll items")
1512
+
1513
+ if ZMQ_VERSION_MAJOR < 3:
1514
+ # timeout is us in 2.x, ms in 3.x
1515
+ # expected input is ms (matches 3.x)
1516
+ timeout = 1000 * timeout
1517
+
1518
+ for i in range(nsockets):
1519
+ s, events = sockets[i]
1520
+ if isinstance(s, Socket):
1521
+ pollitems[i].socket = cast(Socket, s).handle
1522
+ pollitems[i].fd = 0
1523
+ pollitems[i].events = events
1524
+ pollitems[i].revents = 0
1525
+ elif isinstance(s, int):
1526
+ pollitems[i].socket = NULL
1527
+ pollitems[i].fd = s
1528
+ pollitems[i].events = events
1529
+ pollitems[i].revents = 0
1530
+ elif hasattr(s, 'fileno'):
1531
+ try:
1532
+ fileno = int(s.fileno())
1533
+ except Exception:
1534
+ free(pollitems)
1535
+ raise ValueError('fileno() must return a valid integer fd')
1536
+ else:
1537
+ pollitems[i].socket = NULL
1538
+ pollitems[i].fd = fileno
1539
+ pollitems[i].events = events
1540
+ pollitems[i].revents = 0
1541
+ else:
1542
+ free(pollitems)
1543
+ raise TypeError(
1544
+ "Socket must be a 0MQ socket, an integer fd or have "
1545
+ f"a fileno() method: {s!r}"
1546
+ )
1547
+
1548
+ ms_passed: int = 0
1549
+ try:
1550
+ while True:
1551
+ start = time.monotonic()
1552
+ with nogil:
1553
+ rc = zmq_poll_c(pollitems, nsockets, timeout)
1554
+ try:
1555
+ _check_rc(rc)
1556
+ except InterruptedSystemCall:
1557
+ if timeout > 0:
1558
+ ms_passed = int(1000 * (time.monotonic() - start))
1559
+ if ms_passed < 0:
1560
+ # don't allow negative ms_passed,
1561
+ # which can happen on old Python versions without time.monotonic.
1562
+ warnings.warn(
1563
+ f"Negative elapsed time for interrupted poll: {ms_passed}."
1564
+ " Did the clock change?",
1565
+ RuntimeWarning,
1566
+ )
1567
+ # treat this case the same as no time passing,
1568
+ # since it should be rare and not happen twice in a row.
1569
+ ms_passed = 0
1570
+ timeout = max(0, timeout - ms_passed)
1571
+ continue
1572
+ else:
1573
+ break
1574
+ except Exception:
1575
+ free(pollitems)
1576
+ raise
1577
+
1578
+ results = []
1579
+ for i in range(nsockets):
1580
+ revents = pollitems[i].revents
1581
+ # for compatibility with select.poll:
1582
+ # - only return sockets with non-zero status
1583
+ # - return the fd for plain sockets
1584
+ if revents > 0:
1585
+ if pollitems[i].socket != NULL:
1586
+ s = sockets[i][0]
1587
+ else:
1588
+ s = pollitems[i].fd
1589
+ results.append((s, revents))
1590
+
1591
+ free(pollitems)
1592
+ return results
1593
+
1594
+
1595
+ # device functions
1596
+
1597
+
1598
+ def device(device_type: C.int, frontend: Socket, backend: Socket = None):
1599
+ """
1600
+ Start a zeromq device.
1601
+
1602
+ .. deprecated:: libzmq-3.2
1603
+ Use zmq.proxy
1604
+
1605
+ Parameters
1606
+ ----------
1607
+ device_type : int
1608
+ one of: QUEUE, FORWARDER, STREAMER
1609
+ The type of device to start.
1610
+ frontend : Socket
1611
+ The Socket instance for the incoming traffic.
1612
+ backend : Socket
1613
+ The Socket instance for the outbound traffic.
1614
+ """
1615
+ if ZMQ_VERSION_MAJOR >= 3:
1616
+ return proxy(frontend, backend)
1617
+
1618
+ rc: C.int = 0
1619
+ while True:
1620
+ with nogil:
1621
+ rc = zmq_device(device_type, frontend.handle, backend.handle)
1622
+ try:
1623
+ _check_rc(rc)
1624
+ except InterruptedSystemCall:
1625
+ continue
1626
+ else:
1627
+ break
1628
+ return rc
1629
+
1630
+
1631
+ def proxy(frontend: Socket, backend: Socket, capture: Socket = None):
1632
+ """
1633
+ Start a zeromq proxy (replacement for device).
1634
+
1635
+ .. versionadded:: libzmq-3.2
1636
+ .. versionadded:: 13.0
1637
+
1638
+ Parameters
1639
+ ----------
1640
+ frontend : Socket
1641
+ The Socket instance for the incoming traffic.
1642
+ backend : Socket
1643
+ The Socket instance for the outbound traffic.
1644
+ capture : Socket (optional)
1645
+ The Socket instance for capturing traffic.
1646
+ """
1647
+ rc: C.int = 0
1648
+ capture_handle: p_void
1649
+ if isinstance(capture, Socket):
1650
+ capture_handle = capture.handle
1651
+ else:
1652
+ capture_handle = NULL
1653
+ while True:
1654
+ with nogil:
1655
+ rc = zmq_proxy(frontend.handle, backend.handle, capture_handle)
1656
+ try:
1657
+ _check_rc(rc)
1658
+ except InterruptedSystemCall:
1659
+ continue
1660
+ else:
1661
+ break
1662
+ return rc
1663
+
1664
+
1665
+ def proxy_steerable(
1666
+ frontend: Socket,
1667
+ backend: Socket,
1668
+ capture: Socket = None,
1669
+ control: Socket = None,
1670
+ ):
1671
+ """
1672
+ Start a zeromq proxy with control flow.
1673
+
1674
+ .. versionadded:: libzmq-4.1
1675
+ .. versionadded:: 18.0
1676
+
1677
+ Parameters
1678
+ ----------
1679
+ frontend : Socket
1680
+ The Socket instance for the incoming traffic.
1681
+ backend : Socket
1682
+ The Socket instance for the outbound traffic.
1683
+ capture : Socket (optional)
1684
+ The Socket instance for capturing traffic.
1685
+ control : Socket (optional)
1686
+ The Socket instance for control flow.
1687
+ """
1688
+ rc: C.int = 0
1689
+ capture_handle: p_void
1690
+ if isinstance(capture, Socket):
1691
+ capture_handle = capture.handle
1692
+ else:
1693
+ capture_handle = NULL
1694
+ if isinstance(control, Socket):
1695
+ control_handle = control.handle
1696
+ else:
1697
+ control_handle = NULL
1698
+ while True:
1699
+ with nogil:
1700
+ rc = zmq_proxy_steerable(
1701
+ frontend.handle, backend.handle, capture_handle, control_handle
1702
+ )
1703
+ try:
1704
+ _check_rc(rc)
1705
+ except InterruptedSystemCall:
1706
+ continue
1707
+ else:
1708
+ break
1709
+ return rc
1710
+
1711
+
1712
+ # monitored queue - like proxy (predates libzmq proxy)
1713
+ # but supports ROUTER-ROUTER devices
1714
+ @cfunc
1715
+ @inline
1716
+ @nogil
1717
+ def _mq_relay(
1718
+ in_socket: p_void,
1719
+ out_socket: p_void,
1720
+ side_socket: p_void,
1721
+ msg: zmq_msg_t,
1722
+ side_msg: zmq_msg_t,
1723
+ id_msg: zmq_msg_t,
1724
+ swap_ids: bint,
1725
+ ) -> C.int:
1726
+ rc: C.int
1727
+ flags: C.int
1728
+ flagsz = declare(size_t)
1729
+ more = declare(int)
1730
+ flagsz = sizeof(int)
1731
+
1732
+ if swap_ids: # both router, must send second identity first
1733
+ # recv two ids into msg, id_msg
1734
+ rc = zmq_msg_recv(address(msg), in_socket, 0)
1735
+ if rc < 0:
1736
+ return rc
1737
+
1738
+ rc = zmq_msg_recv(address(id_msg), in_socket, 0)
1739
+ if rc < 0:
1740
+ return rc
1741
+
1742
+ # send second id (id_msg) first
1743
+ # !!!! always send a copy before the original !!!!
1744
+ rc = zmq_msg_copy(address(side_msg), address(id_msg))
1745
+ if rc < 0:
1746
+ return rc
1747
+ rc = zmq_msg_send(address(side_msg), out_socket, ZMQ_SNDMORE)
1748
+ if rc < 0:
1749
+ return rc
1750
+ rc = zmq_msg_send(address(id_msg), side_socket, ZMQ_SNDMORE)
1751
+ if rc < 0:
1752
+ return rc
1753
+ # send first id (msg) second
1754
+ rc = zmq_msg_copy(address(side_msg), address(msg))
1755
+ if rc < 0:
1756
+ return rc
1757
+ rc = zmq_msg_send(address(side_msg), out_socket, ZMQ_SNDMORE)
1758
+ if rc < 0:
1759
+ return rc
1760
+ rc = zmq_msg_send(address(msg), side_socket, ZMQ_SNDMORE)
1761
+ if rc < 0:
1762
+ return rc
1763
+ while True:
1764
+ rc = zmq_msg_recv(address(msg), in_socket, 0)
1765
+ if rc < 0:
1766
+ return rc
1767
+ # assert (rc == 0)
1768
+ rc = zmq_getsockopt(in_socket, ZMQ_RCVMORE, address(more), address(flagsz))
1769
+ if rc < 0:
1770
+ return rc
1771
+ flags = 0
1772
+ if more:
1773
+ flags |= ZMQ_SNDMORE
1774
+
1775
+ rc = zmq_msg_copy(address(side_msg), address(msg))
1776
+ if rc < 0:
1777
+ return rc
1778
+ if flags:
1779
+ rc = zmq_msg_send(address(side_msg), out_socket, flags)
1780
+ if rc < 0:
1781
+ return rc
1782
+ # only SNDMORE for side-socket
1783
+ rc = zmq_msg_send(address(msg), side_socket, ZMQ_SNDMORE)
1784
+ if rc < 0:
1785
+ return rc
1786
+ else:
1787
+ rc = zmq_msg_send(address(side_msg), out_socket, 0)
1788
+ if rc < 0:
1789
+ return rc
1790
+ rc = zmq_msg_send(address(msg), side_socket, 0)
1791
+ if rc < 0:
1792
+ return rc
1793
+ break
1794
+ return rc
1795
+
1796
+
1797
+ @cfunc
1798
+ @inline
1799
+ @nogil
1800
+ def _mq_inline(
1801
+ in_socket: p_void,
1802
+ out_socket: p_void,
1803
+ side_socket: p_void,
1804
+ in_msg_ptr: pointer(zmq_msg_t),
1805
+ out_msg_ptr: pointer(zmq_msg_t),
1806
+ swap_ids: bint,
1807
+ ) -> C.int:
1808
+ """
1809
+ inner C function for monitored_queue
1810
+ """
1811
+
1812
+ msg: zmq_msg_t = declare(zmq_msg_t)
1813
+ rc: C.int = zmq_msg_init(address(msg))
1814
+ id_msg = declare(zmq_msg_t)
1815
+ rc = zmq_msg_init(address(id_msg))
1816
+ if rc < 0:
1817
+ return rc
1818
+ side_msg = declare(zmq_msg_t)
1819
+ rc = zmq_msg_init(address(side_msg))
1820
+ if rc < 0:
1821
+ return rc
1822
+
1823
+ items = declare(zmq_pollitem_t[2])
1824
+ items[0].socket = in_socket
1825
+ items[0].events = ZMQ_POLLIN
1826
+ items[0].fd = items[0].revents = 0
1827
+ items[1].socket = out_socket
1828
+ items[1].events = ZMQ_POLLIN
1829
+ items[1].fd = items[1].revents = 0
1830
+
1831
+ while True:
1832
+ # wait for the next message to process
1833
+ rc = zmq_poll_c(address(items[0]), 2, -1)
1834
+ if rc < 0:
1835
+ return rc
1836
+ if items[0].revents & ZMQ_POLLIN:
1837
+ # send in_prefix to side socket
1838
+ rc = zmq_msg_copy(address(side_msg), in_msg_ptr)
1839
+ if rc < 0:
1840
+ return rc
1841
+ rc = zmq_msg_send(address(side_msg), side_socket, ZMQ_SNDMORE)
1842
+ if rc < 0:
1843
+ return rc
1844
+ # relay the rest of the message
1845
+ rc = _mq_relay(
1846
+ in_socket, out_socket, side_socket, msg, side_msg, id_msg, swap_ids
1847
+ )
1848
+ if rc < 0:
1849
+ return rc
1850
+ if items[1].revents & ZMQ_POLLIN:
1851
+ # send out_prefix to side socket
1852
+ rc = zmq_msg_copy(address(side_msg), out_msg_ptr)
1853
+ if rc < 0:
1854
+ return rc
1855
+ rc = zmq_msg_send(address(side_msg), side_socket, ZMQ_SNDMORE)
1856
+ if rc < 0:
1857
+ return rc
1858
+ # relay the rest of the message
1859
+ rc = _mq_relay(
1860
+ out_socket, in_socket, side_socket, msg, side_msg, id_msg, swap_ids
1861
+ )
1862
+ if rc < 0:
1863
+ return rc
1864
+ return rc
1865
+
1866
+
1867
+ def monitored_queue(
1868
+ in_socket: Socket,
1869
+ out_socket: Socket,
1870
+ mon_socket: Socket,
1871
+ in_prefix: bytes = b'in',
1872
+ out_prefix: bytes = b'out',
1873
+ ):
1874
+ """
1875
+ Start a monitored queue device.
1876
+
1877
+ A monitored queue is very similar to the zmq.proxy device (monitored queue came first).
1878
+
1879
+ Differences from zmq.proxy:
1880
+
1881
+ - monitored_queue supports both in and out being ROUTER sockets
1882
+ (via swapping IDENTITY prefixes).
1883
+ - monitor messages are prefixed, making in and out messages distinguishable.
1884
+
1885
+ Parameters
1886
+ ----------
1887
+ in_socket : zmq.Socket
1888
+ One of the sockets to the Queue. Its messages will be prefixed with
1889
+ 'in'.
1890
+ out_socket : zmq.Socket
1891
+ One of the sockets to the Queue. Its messages will be prefixed with
1892
+ 'out'. The only difference between in/out socket is this prefix.
1893
+ mon_socket : zmq.Socket
1894
+ This socket sends out every message received by each of the others
1895
+ with an in/out prefix specifying which one it was.
1896
+ in_prefix : str
1897
+ Prefix added to broadcast messages from in_socket.
1898
+ out_prefix : str
1899
+ Prefix added to broadcast messages from out_socket.
1900
+ """
1901
+ ins: p_void = in_socket.handle
1902
+ outs: p_void = out_socket.handle
1903
+ mons: p_void = mon_socket.handle
1904
+ in_msg = declare(zmq_msg_t)
1905
+ out_msg = declare(zmq_msg_t)
1906
+ swap_ids: bint
1907
+ msg_c: p_char = NULL
1908
+ msg_c_len = declare(Py_ssize_t)
1909
+ rc: C.int
1910
+
1911
+ # force swap_ids if both ROUTERs
1912
+ swap_ids = in_socket.type == ZMQ_ROUTER and out_socket.type == ZMQ_ROUTER
1913
+
1914
+ # build zmq_msg objects from str prefixes
1915
+ asbuffer_r(in_prefix, cast(pointer(p_void), address(msg_c)), address(msg_c_len))
1916
+ rc = zmq_msg_init_size(address(in_msg), msg_c_len)
1917
+ _check_rc(rc)
1918
+
1919
+ memcpy(zmq_msg_data(address(in_msg)), msg_c, zmq_msg_size(address(in_msg)))
1920
+
1921
+ asbuffer_r(out_prefix, cast(pointer(p_void), address(msg_c)), address(msg_c_len))
1922
+
1923
+ rc = zmq_msg_init_size(address(out_msg), msg_c_len)
1924
+ _check_rc(rc)
1925
+
1926
+ while True:
1927
+ with nogil:
1928
+ memcpy(
1929
+ zmq_msg_data(address(out_msg)), msg_c, zmq_msg_size(address(out_msg))
1930
+ )
1931
+ rc = _mq_inline(
1932
+ ins, outs, mons, address(in_msg), address(out_msg), swap_ids
1933
+ )
1934
+ try:
1935
+ _check_rc(rc)
1936
+ except InterruptedSystemCall:
1937
+ continue
1938
+ else:
1939
+ break
1940
+ return rc
1941
+
1942
+
1943
+ __all__ = [
1944
+ 'IPC_PATH_MAX_LEN',
1945
+ 'Context',
1946
+ 'Socket',
1947
+ 'Frame',
1948
+ 'has',
1949
+ 'curve_keypair',
1950
+ 'curve_public',
1951
+ 'zmq_version_info',
1952
+ 'zmq_errno',
1953
+ 'zmq_poll',
1954
+ 'strerror',
1955
+ 'device',
1956
+ 'proxy',
1957
+ 'proxy_steerable',
1958
+ ]
.venv/lib/python3.11/site-packages/zmq/backend/cython/constant_enums.pxi ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef extern from "zmq.h" nogil:
2
+ enum: PYZMQ_DRAFT_API
3
+ enum: ZMQ_VERSION
4
+ enum: ZMQ_VERSION_MAJOR
5
+ enum: ZMQ_VERSION_MINOR
6
+ enum: ZMQ_VERSION_PATCH
7
+ enum: ZMQ_IO_THREADS
8
+ enum: ZMQ_MAX_SOCKETS
9
+ enum: ZMQ_SOCKET_LIMIT
10
+ enum: ZMQ_THREAD_PRIORITY
11
+ enum: ZMQ_THREAD_SCHED_POLICY
12
+ enum: ZMQ_MAX_MSGSZ
13
+ enum: ZMQ_MSG_T_SIZE
14
+ enum: ZMQ_THREAD_AFFINITY_CPU_ADD
15
+ enum: ZMQ_THREAD_AFFINITY_CPU_REMOVE
16
+ enum: ZMQ_THREAD_NAME_PREFIX
17
+ enum: ZMQ_STREAMER
18
+ enum: ZMQ_FORWARDER
19
+ enum: ZMQ_QUEUE
20
+ enum: ZMQ_EAGAIN "EAGAIN"
21
+ enum: ZMQ_EFAULT "EFAULT"
22
+ enum: ZMQ_EINVAL "EINVAL"
23
+ enum: ZMQ_ENOTSUP "ENOTSUP"
24
+ enum: ZMQ_EPROTONOSUPPORT "EPROTONOSUPPORT"
25
+ enum: ZMQ_ENOBUFS "ENOBUFS"
26
+ enum: ZMQ_ENETDOWN "ENETDOWN"
27
+ enum: ZMQ_EADDRINUSE "EADDRINUSE"
28
+ enum: ZMQ_EADDRNOTAVAIL "EADDRNOTAVAIL"
29
+ enum: ZMQ_ECONNREFUSED "ECONNREFUSED"
30
+ enum: ZMQ_EINPROGRESS "EINPROGRESS"
31
+ enum: ZMQ_ENOTSOCK "ENOTSOCK"
32
+ enum: ZMQ_EMSGSIZE "EMSGSIZE"
33
+ enum: ZMQ_EAFNOSUPPORT "EAFNOSUPPORT"
34
+ enum: ZMQ_ENETUNREACH "ENETUNREACH"
35
+ enum: ZMQ_ECONNABORTED "ECONNABORTED"
36
+ enum: ZMQ_ECONNRESET "ECONNRESET"
37
+ enum: ZMQ_ENOTCONN "ENOTCONN"
38
+ enum: ZMQ_ETIMEDOUT "ETIMEDOUT"
39
+ enum: ZMQ_EHOSTUNREACH "EHOSTUNREACH"
40
+ enum: ZMQ_ENETRESET "ENETRESET"
41
+ enum: ZMQ_EFSM "EFSM"
42
+ enum: ZMQ_ENOCOMPATPROTO "ENOCOMPATPROTO"
43
+ enum: ZMQ_ETERM "ETERM"
44
+ enum: ZMQ_EMTHREAD "EMTHREAD"
45
+ enum: ZMQ_PROTOCOL_ERROR_WS_UNSPECIFIED
46
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED
47
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
48
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE
49
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE
50
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED
51
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE
52
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO
53
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE
54
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR
55
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY
56
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME
57
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA
58
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
59
+ enum: ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH
60
+ enum: ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED
61
+ enum: ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY
62
+ enum: ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID
63
+ enum: ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION
64
+ enum: ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE
65
+ enum: ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA
66
+ enum: ZMQ_EVENT_CONNECTED
67
+ enum: ZMQ_EVENT_CONNECT_DELAYED
68
+ enum: ZMQ_EVENT_CONNECT_RETRIED
69
+ enum: ZMQ_EVENT_LISTENING
70
+ enum: ZMQ_EVENT_BIND_FAILED
71
+ enum: ZMQ_EVENT_ACCEPTED
72
+ enum: ZMQ_EVENT_ACCEPT_FAILED
73
+ enum: ZMQ_EVENT_CLOSED
74
+ enum: ZMQ_EVENT_CLOSE_FAILED
75
+ enum: ZMQ_EVENT_DISCONNECTED
76
+ enum: ZMQ_EVENT_MONITOR_STOPPED
77
+ enum: ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL
78
+ enum: ZMQ_EVENT_HANDSHAKE_SUCCEEDED
79
+ enum: ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL
80
+ enum: ZMQ_EVENT_HANDSHAKE_FAILED_AUTH
81
+ enum: ZMQ_EVENT_ALL_V1
82
+ enum: ZMQ_EVENT_ALL
83
+ enum: ZMQ_EVENT_PIPES_STATS
84
+ enum: ZMQ_EVENT_ALL_V2
85
+ enum: ZMQ_DONTWAIT
86
+ enum: ZMQ_SNDMORE
87
+ enum: ZMQ_NOBLOCK
88
+ enum: ZMQ_MORE
89
+ enum: ZMQ_SHARED
90
+ enum: ZMQ_SRCFD
91
+ enum: ZMQ_NORM_FIXED
92
+ enum: ZMQ_NORM_CC
93
+ enum: ZMQ_NORM_CCL
94
+ enum: ZMQ_NORM_CCE
95
+ enum: ZMQ_NORM_CCE_ECNONLY
96
+ enum: ZMQ_POLLIN
97
+ enum: ZMQ_POLLOUT
98
+ enum: ZMQ_POLLERR
99
+ enum: ZMQ_POLLPRI
100
+ enum: ZMQ_RECONNECT_STOP_CONN_REFUSED
101
+ enum: ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED
102
+ enum: ZMQ_RECONNECT_STOP_AFTER_DISCONNECT
103
+ enum: ZMQ_NOTIFY_CONNECT
104
+ enum: ZMQ_NOTIFY_DISCONNECT
105
+ enum: ZMQ_NULL
106
+ enum: ZMQ_PLAIN
107
+ enum: ZMQ_CURVE
108
+ enum: ZMQ_GSSAPI
109
+ enum: ZMQ_HWM
110
+ enum: ZMQ_AFFINITY
111
+ enum: ZMQ_ROUTING_ID
112
+ enum: ZMQ_SUBSCRIBE
113
+ enum: ZMQ_UNSUBSCRIBE
114
+ enum: ZMQ_RATE
115
+ enum: ZMQ_RECOVERY_IVL
116
+ enum: ZMQ_SNDBUF
117
+ enum: ZMQ_RCVBUF
118
+ enum: ZMQ_RCVMORE
119
+ enum: ZMQ_FD
120
+ enum: ZMQ_EVENTS
121
+ enum: ZMQ_TYPE
122
+ enum: ZMQ_LINGER
123
+ enum: ZMQ_RECONNECT_IVL
124
+ enum: ZMQ_BACKLOG
125
+ enum: ZMQ_RECONNECT_IVL_MAX
126
+ enum: ZMQ_MAXMSGSIZE
127
+ enum: ZMQ_SNDHWM
128
+ enum: ZMQ_RCVHWM
129
+ enum: ZMQ_MULTICAST_HOPS
130
+ enum: ZMQ_RCVTIMEO
131
+ enum: ZMQ_SNDTIMEO
132
+ enum: ZMQ_LAST_ENDPOINT
133
+ enum: ZMQ_ROUTER_MANDATORY
134
+ enum: ZMQ_TCP_KEEPALIVE
135
+ enum: ZMQ_TCP_KEEPALIVE_CNT
136
+ enum: ZMQ_TCP_KEEPALIVE_IDLE
137
+ enum: ZMQ_TCP_KEEPALIVE_INTVL
138
+ enum: ZMQ_IMMEDIATE
139
+ enum: ZMQ_XPUB_VERBOSE
140
+ enum: ZMQ_ROUTER_RAW
141
+ enum: ZMQ_IPV6
142
+ enum: ZMQ_MECHANISM
143
+ enum: ZMQ_PLAIN_SERVER
144
+ enum: ZMQ_PLAIN_USERNAME
145
+ enum: ZMQ_PLAIN_PASSWORD
146
+ enum: ZMQ_CURVE_SERVER
147
+ enum: ZMQ_CURVE_PUBLICKEY
148
+ enum: ZMQ_CURVE_SECRETKEY
149
+ enum: ZMQ_CURVE_SERVERKEY
150
+ enum: ZMQ_PROBE_ROUTER
151
+ enum: ZMQ_REQ_CORRELATE
152
+ enum: ZMQ_REQ_RELAXED
153
+ enum: ZMQ_CONFLATE
154
+ enum: ZMQ_ZAP_DOMAIN
155
+ enum: ZMQ_ROUTER_HANDOVER
156
+ enum: ZMQ_TOS
157
+ enum: ZMQ_CONNECT_ROUTING_ID
158
+ enum: ZMQ_GSSAPI_SERVER
159
+ enum: ZMQ_GSSAPI_PRINCIPAL
160
+ enum: ZMQ_GSSAPI_SERVICE_PRINCIPAL
161
+ enum: ZMQ_GSSAPI_PLAINTEXT
162
+ enum: ZMQ_HANDSHAKE_IVL
163
+ enum: ZMQ_SOCKS_PROXY
164
+ enum: ZMQ_XPUB_NODROP
165
+ enum: ZMQ_BLOCKY
166
+ enum: ZMQ_XPUB_MANUAL
167
+ enum: ZMQ_XPUB_WELCOME_MSG
168
+ enum: ZMQ_STREAM_NOTIFY
169
+ enum: ZMQ_INVERT_MATCHING
170
+ enum: ZMQ_HEARTBEAT_IVL
171
+ enum: ZMQ_HEARTBEAT_TTL
172
+ enum: ZMQ_HEARTBEAT_TIMEOUT
173
+ enum: ZMQ_XPUB_VERBOSER
174
+ enum: ZMQ_CONNECT_TIMEOUT
175
+ enum: ZMQ_TCP_MAXRT
176
+ enum: ZMQ_THREAD_SAFE
177
+ enum: ZMQ_MULTICAST_MAXTPDU
178
+ enum: ZMQ_VMCI_BUFFER_SIZE
179
+ enum: ZMQ_VMCI_BUFFER_MIN_SIZE
180
+ enum: ZMQ_VMCI_BUFFER_MAX_SIZE
181
+ enum: ZMQ_VMCI_CONNECT_TIMEOUT
182
+ enum: ZMQ_USE_FD
183
+ enum: ZMQ_GSSAPI_PRINCIPAL_NAMETYPE
184
+ enum: ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE
185
+ enum: ZMQ_BINDTODEVICE
186
+ enum: ZMQ_IDENTITY
187
+ enum: ZMQ_CONNECT_RID
188
+ enum: ZMQ_TCP_ACCEPT_FILTER
189
+ enum: ZMQ_IPC_FILTER_PID
190
+ enum: ZMQ_IPC_FILTER_UID
191
+ enum: ZMQ_IPC_FILTER_GID
192
+ enum: ZMQ_IPV4ONLY
193
+ enum: ZMQ_DELAY_ATTACH_ON_CONNECT
194
+ enum: ZMQ_FAIL_UNROUTABLE
195
+ enum: ZMQ_ROUTER_BEHAVIOR
196
+ enum: ZMQ_ZAP_ENFORCE_DOMAIN
197
+ enum: ZMQ_LOOPBACK_FASTPATH
198
+ enum: ZMQ_METADATA
199
+ enum: ZMQ_MULTICAST_LOOP
200
+ enum: ZMQ_ROUTER_NOTIFY
201
+ enum: ZMQ_XPUB_MANUAL_LAST_VALUE
202
+ enum: ZMQ_SOCKS_USERNAME
203
+ enum: ZMQ_SOCKS_PASSWORD
204
+ enum: ZMQ_IN_BATCH_SIZE
205
+ enum: ZMQ_OUT_BATCH_SIZE
206
+ enum: ZMQ_WSS_KEY_PEM
207
+ enum: ZMQ_WSS_CERT_PEM
208
+ enum: ZMQ_WSS_TRUST_PEM
209
+ enum: ZMQ_WSS_HOSTNAME
210
+ enum: ZMQ_WSS_TRUST_SYSTEM
211
+ enum: ZMQ_ONLY_FIRST_SUBSCRIBE
212
+ enum: ZMQ_RECONNECT_STOP
213
+ enum: ZMQ_HELLO_MSG
214
+ enum: ZMQ_DISCONNECT_MSG
215
+ enum: ZMQ_PRIORITY
216
+ enum: ZMQ_BUSY_POLL
217
+ enum: ZMQ_HICCUP_MSG
218
+ enum: ZMQ_XSUB_VERBOSE_UNSUBSCRIBE
219
+ enum: ZMQ_TOPICS_COUNT
220
+ enum: ZMQ_NORM_MODE
221
+ enum: ZMQ_NORM_UNICAST_NACK
222
+ enum: ZMQ_NORM_BUFFER_SIZE
223
+ enum: ZMQ_NORM_SEGMENT_SIZE
224
+ enum: ZMQ_NORM_BLOCK_SIZE
225
+ enum: ZMQ_NORM_NUM_PARITY
226
+ enum: ZMQ_NORM_NUM_AUTOPARITY
227
+ enum: ZMQ_NORM_PUSH
228
+ enum: ZMQ_PAIR
229
+ enum: ZMQ_PUB
230
+ enum: ZMQ_SUB
231
+ enum: ZMQ_REQ
232
+ enum: ZMQ_REP
233
+ enum: ZMQ_DEALER
234
+ enum: ZMQ_ROUTER
235
+ enum: ZMQ_PULL
236
+ enum: ZMQ_PUSH
237
+ enum: ZMQ_XPUB
238
+ enum: ZMQ_XSUB
239
+ enum: ZMQ_STREAM
240
+ enum: ZMQ_XREQ
241
+ enum: ZMQ_XREP
242
+ enum: ZMQ_SERVER
243
+ enum: ZMQ_CLIENT
244
+ enum: ZMQ_RADIO
245
+ enum: ZMQ_DISH
246
+ enum: ZMQ_GATHER
247
+ enum: ZMQ_SCATTER
248
+ enum: ZMQ_DGRAM
249
+ enum: ZMQ_PEER
250
+ enum: ZMQ_CHANNEL
.venv/lib/python3.11/site-packages/zmq/backend/cython/libzmq.pxd ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """All the C imports for 0MQ"""
2
+
3
+ #
4
+ # Copyright (c) 2010 Brian E. Granger & Min Ragan-Kelley
5
+ #
6
+ # This file is part of pyzmq.
7
+ #
8
+ # pyzmq is free software; you can redistribute it and/or modify it under
9
+ # the terms of the Lesser GNU General Public License as published by
10
+ # the Free Software Foundation; either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # pyzmq is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # Lesser GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the Lesser GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #
21
+
22
+ #-----------------------------------------------------------------------------
23
+ # Imports
24
+ #-----------------------------------------------------------------------------
25
+
26
+ #-----------------------------------------------------------------------------
27
+ # Import the C header files
28
+ #-----------------------------------------------------------------------------
29
+
30
+ # common includes, such as zmq compat, pyversion_compat
31
+ # make sure we load pyversion compat in every Cython module
32
+ cdef extern from "pyversion_compat.h":
33
+ pass
34
+
35
+ # were it not for Windows,
36
+ # we could cimport these from libc.stdint
37
+ cdef extern from "zmq_compat.h":
38
+ ctypedef signed long long int64_t "pyzmq_int64_t"
39
+ ctypedef unsigned int uint32_t "pyzmq_uint32_t"
40
+
41
+ include "constant_enums.pxi"
42
+
43
+ cdef extern from "zmq.h" nogil:
44
+
45
+ void _zmq_version "zmq_version"(int *major, int *minor, int *patch)
46
+
47
+ ctypedef int fd_t "ZMQ_FD_T"
48
+
49
+ enum: errno
50
+ const char *zmq_strerror (int errnum)
51
+ int zmq_errno()
52
+
53
+ void *zmq_ctx_new ()
54
+ int zmq_ctx_destroy (void *context)
55
+ int zmq_ctx_set (void *context, int option, int optval)
56
+ int zmq_ctx_get (void *context, int option)
57
+ void *zmq_init (int io_threads)
58
+ int zmq_term (void *context)
59
+
60
+ # blackbox def for zmq_msg_t
61
+ ctypedef void * zmq_msg_t "zmq_msg_t"
62
+
63
+ ctypedef void zmq_free_fn(void *data, void *hint)
64
+
65
+ int zmq_msg_init (zmq_msg_t *msg)
66
+ int zmq_msg_init_size (zmq_msg_t *msg, size_t size)
67
+ int zmq_msg_init_data (zmq_msg_t *msg, void *data,
68
+ size_t size, zmq_free_fn *ffn, void *hint)
69
+ int zmq_msg_send (zmq_msg_t *msg, void *s, int flags)
70
+ int zmq_msg_recv (zmq_msg_t *msg, void *s, int flags)
71
+ int zmq_msg_close (zmq_msg_t *msg)
72
+ int zmq_msg_move (zmq_msg_t *dest, zmq_msg_t *src)
73
+ int zmq_msg_copy (zmq_msg_t *dest, zmq_msg_t *src)
74
+ void *zmq_msg_data (zmq_msg_t *msg)
75
+ size_t zmq_msg_size (zmq_msg_t *msg)
76
+ int zmq_msg_more (zmq_msg_t *msg)
77
+ int zmq_msg_get (zmq_msg_t *msg, int option)
78
+ int zmq_msg_set (zmq_msg_t *msg, int option, int optval)
79
+ const char *zmq_msg_gets (zmq_msg_t *msg, const char *property)
80
+ int zmq_has (const char *capability)
81
+
82
+ void *zmq_socket (void *context, int type)
83
+ int zmq_close (void *s)
84
+ int zmq_setsockopt (void *s, int option, void *optval, size_t optvallen)
85
+ int zmq_getsockopt (void *s, int option, void *optval, size_t *optvallen)
86
+ int zmq_bind (void *s, char *addr)
87
+ int zmq_connect (void *s, char *addr)
88
+ int zmq_unbind (void *s, char *addr)
89
+ int zmq_disconnect (void *s, char *addr)
90
+
91
+ int zmq_socket_monitor (void *s, char *addr, int flags)
92
+
93
+ # send/recv
94
+ int zmq_sendbuf (void *s, const void *buf, size_t n, int flags)
95
+ int zmq_recvbuf (void *s, void *buf, size_t n, int flags)
96
+
97
+ ctypedef struct zmq_pollitem_t:
98
+ void *socket
99
+ fd_t fd
100
+ short events
101
+ short revents
102
+
103
+ int zmq_poll (zmq_pollitem_t *items, int nitems, long timeout)
104
+
105
+ int zmq_device (int device_, void *insocket_, void *outsocket_)
106
+ int zmq_proxy (void *frontend, void *backend, void *capture)
107
+ int zmq_proxy_steerable (void *frontend,
108
+ void *backend,
109
+ void *capture,
110
+ void *control)
111
+
112
+ int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key)
113
+ int zmq_curve_public (char *z85_public_key, char *z85_secret_key)
114
+
115
+ # 4.2 draft
116
+ int zmq_join (void *s, const char *group)
117
+ int zmq_leave (void *s, const char *group)
118
+
119
+ int zmq_msg_set_routing_id(zmq_msg_t *msg, uint32_t routing_id)
120
+ uint32_t zmq_msg_routing_id(zmq_msg_t *msg)
121
+ int zmq_msg_set_group(zmq_msg_t *msg, const char *group)
122
+ const char *zmq_msg_group(zmq_msg_t *msg)
.venv/lib/python3.11/site-packages/zmq/backend/select.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Import basic exposure of libzmq C API as a backend"""
2
+
3
+ # Copyright (C) PyZMQ Developers
4
+ # Distributed under the terms of the Modified BSD License.
5
+
6
+ from importlib import import_module
7
+ from typing import Dict
8
+
9
+ public_api = [
10
+ 'Context',
11
+ 'Socket',
12
+ 'Frame',
13
+ 'Message',
14
+ 'device',
15
+ 'proxy',
16
+ 'proxy_steerable',
17
+ 'zmq_poll',
18
+ 'strerror',
19
+ 'zmq_errno',
20
+ 'has',
21
+ 'curve_keypair',
22
+ 'curve_public',
23
+ 'zmq_version_info',
24
+ 'IPC_PATH_MAX_LEN',
25
+ ]
26
+
27
+
28
+ def select_backend(name: str) -> Dict:
29
+ """Select the pyzmq backend"""
30
+ try:
31
+ mod = import_module(name)
32
+ except ImportError:
33
+ raise
34
+ except Exception as e:
35
+ raise ImportError(f"Importing {name} failed with {e}") from e
36
+ ns = {
37
+ # private API
38
+ 'monitored_queue': mod.monitored_queue,
39
+ }
40
+ ns.update({key: getattr(mod, key) for key in public_api})
41
+ return ns
.venv/lib/python3.11/site-packages/zmq/eventloop/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ """Tornado eventloop integration for pyzmq"""
2
+
3
+ from tornado.ioloop import IOLoop
4
+
5
+ __all__ = ['IOLoop']
.venv/lib/python3.11/site-packages/zmq/eventloop/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (330 Bytes). View file
 
.venv/lib/python3.11/site-packages/zmq/eventloop/__pycache__/_deprecated.cpython-311.pyc ADDED
Binary file (10.3 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/eventloop/__pycache__/future.cpython-311.pyc ADDED
Binary file (6.08 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/eventloop/__pycache__/ioloop.cpython-311.pyc ADDED
Binary file (1.18 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/eventloop/__pycache__/zmqstream.cpython-311.pyc ADDED
Binary file (29.3 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/eventloop/_deprecated.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """tornado IOLoop API with zmq compatibility
2
+
3
+ If you have tornado ≥ 3.0, this is a subclass of tornado's IOLoop,
4
+ otherwise we ship a minimal subset of tornado in zmq.eventloop.minitornado.
5
+
6
+ The minimal shipped version of tornado's IOLoop does not include
7
+ support for concurrent futures - this will only be available if you
8
+ have tornado ≥ 3.0.
9
+ """
10
+
11
+ # Copyright (C) PyZMQ Developers
12
+ # Distributed under the terms of the Modified BSD License.
13
+
14
+ import time
15
+ import warnings
16
+ from typing import Tuple
17
+
18
+ from zmq import ETERM, POLLERR, POLLIN, POLLOUT, Poller, ZMQError
19
+
20
+ tornado_version: Tuple = ()
21
+ try:
22
+ import tornado
23
+
24
+ tornado_version = tornado.version_info
25
+ except (ImportError, AttributeError):
26
+ pass
27
+
28
+ from .minitornado.ioloop import PeriodicCallback, PollIOLoop
29
+ from .minitornado.log import gen_log
30
+
31
+
32
+ class DelayedCallback(PeriodicCallback):
33
+ """Schedules the given callback to be called once.
34
+
35
+ The callback is called once, after callback_time milliseconds.
36
+
37
+ `start` must be called after the DelayedCallback is created.
38
+
39
+ The timeout is calculated from when `start` is called.
40
+ """
41
+
42
+ def __init__(self, callback, callback_time, io_loop=None):
43
+ # PeriodicCallback require callback_time to be positive
44
+ warnings.warn(
45
+ """DelayedCallback is deprecated.
46
+ Use loop.add_timeout instead.""",
47
+ DeprecationWarning,
48
+ )
49
+ callback_time = max(callback_time, 1e-3)
50
+ super().__init__(callback, callback_time, io_loop)
51
+
52
+ def start(self):
53
+ """Starts the timer."""
54
+ self._running = True
55
+ self._firstrun = True
56
+ self._next_timeout = time.time() + self.callback_time / 1000.0
57
+ self.io_loop.add_timeout(self._next_timeout, self._run)
58
+
59
+ def _run(self):
60
+ if not self._running:
61
+ return
62
+ self._running = False
63
+ try:
64
+ self.callback()
65
+ except Exception:
66
+ gen_log.error("Error in delayed callback", exc_info=True)
67
+
68
+
69
+ class ZMQPoller:
70
+ """A poller that can be used in the tornado IOLoop.
71
+
72
+ This simply wraps a regular zmq.Poller, scaling the timeout
73
+ by 1000, so that it is in seconds rather than milliseconds.
74
+ """
75
+
76
+ def __init__(self):
77
+ self._poller = Poller()
78
+
79
+ @staticmethod
80
+ def _map_events(events):
81
+ """translate IOLoop.READ/WRITE/ERROR event masks into zmq.POLLIN/OUT/ERR"""
82
+ z_events = 0
83
+ if events & IOLoop.READ:
84
+ z_events |= POLLIN
85
+ if events & IOLoop.WRITE:
86
+ z_events |= POLLOUT
87
+ if events & IOLoop.ERROR:
88
+ z_events |= POLLERR
89
+ return z_events
90
+
91
+ @staticmethod
92
+ def _remap_events(z_events):
93
+ """translate zmq.POLLIN/OUT/ERR event masks into IOLoop.READ/WRITE/ERROR"""
94
+ events = 0
95
+ if z_events & POLLIN:
96
+ events |= IOLoop.READ
97
+ if z_events & POLLOUT:
98
+ events |= IOLoop.WRITE
99
+ if z_events & POLLERR:
100
+ events |= IOLoop.ERROR
101
+ return events
102
+
103
+ def register(self, fd, events):
104
+ return self._poller.register(fd, self._map_events(events))
105
+
106
+ def modify(self, fd, events):
107
+ return self._poller.modify(fd, self._map_events(events))
108
+
109
+ def unregister(self, fd):
110
+ return self._poller.unregister(fd)
111
+
112
+ def poll(self, timeout):
113
+ """poll in seconds rather than milliseconds.
114
+
115
+ Event masks will be IOLoop.READ/WRITE/ERROR
116
+ """
117
+ z_events = self._poller.poll(1000 * timeout)
118
+ return [(fd, self._remap_events(evt)) for (fd, evt) in z_events]
119
+
120
+ def close(self):
121
+ pass
122
+
123
+
124
+ class ZMQIOLoop(PollIOLoop):
125
+ """ZMQ subclass of tornado's IOLoop
126
+
127
+ Minor modifications, so that .current/.instance return self
128
+ """
129
+
130
+ _zmq_impl = ZMQPoller
131
+
132
+ def initialize(self, impl=None, **kwargs):
133
+ impl = self._zmq_impl() if impl is None else impl
134
+ super().initialize(impl=impl, **kwargs)
135
+
136
+ @classmethod
137
+ def instance(cls, *args, **kwargs):
138
+ """Returns a global `IOLoop` instance.
139
+
140
+ Most applications have a single, global `IOLoop` running on the
141
+ main thread. Use this method to get this instance from
142
+ another thread. To get the current thread's `IOLoop`, use `current()`.
143
+ """
144
+ # install ZMQIOLoop as the active IOLoop implementation
145
+ # when using tornado 3
146
+ if tornado_version >= (3,):
147
+ PollIOLoop.configure(cls)
148
+ loop = PollIOLoop.instance(*args, **kwargs)
149
+ if not isinstance(loop, cls):
150
+ warnings.warn(
151
+ f"IOLoop.current expected instance of {cls!r}, got {loop!r}",
152
+ RuntimeWarning,
153
+ stacklevel=2,
154
+ )
155
+ return loop
156
+
157
+ @classmethod
158
+ def current(cls, *args, **kwargs):
159
+ """Returns the current thread’s IOLoop."""
160
+ # install ZMQIOLoop as the active IOLoop implementation
161
+ # when using tornado 3
162
+ if tornado_version >= (3,):
163
+ PollIOLoop.configure(cls)
164
+ loop = PollIOLoop.current(*args, **kwargs)
165
+ if not isinstance(loop, cls):
166
+ warnings.warn(
167
+ f"IOLoop.current expected instance of {cls!r}, got {loop!r}",
168
+ RuntimeWarning,
169
+ stacklevel=2,
170
+ )
171
+ return loop
172
+
173
+ def start(self):
174
+ try:
175
+ super().start()
176
+ except ZMQError as e:
177
+ if e.errno == ETERM:
178
+ # quietly return on ETERM
179
+ pass
180
+ else:
181
+ raise
182
+
183
+
184
+ # public API name
185
+ IOLoop = ZMQIOLoop
186
+
187
+
188
+ def install():
189
+ """set the tornado IOLoop instance with the pyzmq IOLoop.
190
+
191
+ After calling this function, tornado's IOLoop.instance() and pyzmq's
192
+ IOLoop.instance() will return the same object.
193
+
194
+ An assertion error will be raised if tornado's IOLoop has been initialized
195
+ prior to calling this function.
196
+ """
197
+ from tornado import ioloop
198
+
199
+ # check if tornado's IOLoop is already initialized to something other
200
+ # than the pyzmq IOLoop instance:
201
+ assert (
202
+ (not ioloop.IOLoop.initialized())
203
+ or ioloop.IOLoop.instance() is IOLoop.instance()
204
+ ), "tornado IOLoop already initialized"
205
+
206
+ if tornado_version >= (3,):
207
+ # tornado 3 has an official API for registering new defaults, yay!
208
+ ioloop.IOLoop.configure(ZMQIOLoop)
209
+ else:
210
+ # we have to set the global instance explicitly
211
+ ioloop.IOLoop._instance = IOLoop.instance()
.venv/lib/python3.11/site-packages/zmq/eventloop/future.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Future-returning APIs for tornado coroutines.
2
+
3
+ .. seealso::
4
+
5
+ :mod:`zmq.asyncio`
6
+
7
+ """
8
+
9
+ # Copyright (c) PyZMQ Developers.
10
+ # Distributed under the terms of the Modified BSD License.
11
+ from __future__ import annotations
12
+
13
+ import asyncio
14
+ import warnings
15
+ from typing import Any
16
+
17
+ from tornado.concurrent import Future
18
+ from tornado.ioloop import IOLoop
19
+
20
+ import zmq as _zmq
21
+ from zmq._future import _AsyncPoller, _AsyncSocket
22
+
23
+
24
+ class CancelledError(Exception):
25
+ pass
26
+
27
+
28
+ class _TornadoFuture(Future):
29
+ """Subclass Tornado Future, reinstating cancellation."""
30
+
31
+ def cancel(self):
32
+ if self.done():
33
+ return False
34
+ self.set_exception(CancelledError())
35
+ return True
36
+
37
+ def cancelled(self):
38
+ return self.done() and isinstance(self.exception(), CancelledError)
39
+
40
+
41
+ class _CancellableTornadoTimeout:
42
+ def __init__(self, loop, timeout):
43
+ self.loop = loop
44
+ self.timeout = timeout
45
+
46
+ def cancel(self):
47
+ self.loop.remove_timeout(self.timeout)
48
+
49
+
50
+ # mixin for tornado/asyncio compatibility
51
+
52
+
53
+ class _AsyncTornado:
54
+ _Future: type[asyncio.Future] = _TornadoFuture
55
+ _READ = IOLoop.READ
56
+ _WRITE = IOLoop.WRITE
57
+
58
+ def _default_loop(self):
59
+ return IOLoop.current()
60
+
61
+ def _call_later(self, delay, callback):
62
+ io_loop = self._get_loop()
63
+ timeout = io_loop.call_later(delay, callback)
64
+ return _CancellableTornadoTimeout(io_loop, timeout)
65
+
66
+
67
+ class Poller(_AsyncTornado, _AsyncPoller):
68
+ def _watch_raw_socket(self, loop, socket, evt, f):
69
+ """Schedule callback for a raw socket"""
70
+ loop.add_handler(socket, lambda *args: f(), evt)
71
+
72
+ def _unwatch_raw_sockets(self, loop, *sockets):
73
+ """Unschedule callback for a raw socket"""
74
+ for socket in sockets:
75
+ loop.remove_handler(socket)
76
+
77
+
78
+ class Socket(_AsyncTornado, _AsyncSocket):
79
+ _poller_class = Poller
80
+
81
+
82
+ Poller._socket_class = Socket
83
+
84
+
85
+ class Context(_zmq.Context[Socket]):
86
+ # avoid sharing instance with base Context class
87
+ _instance = None
88
+
89
+ io_loop = None
90
+
91
+ @staticmethod
92
+ def _socket_class(self, socket_type):
93
+ return Socket(self, socket_type)
94
+
95
+ def __init__(self: Context, *args: Any, **kwargs: Any) -> None:
96
+ io_loop = kwargs.pop('io_loop', None)
97
+ if io_loop is not None:
98
+ warnings.warn(
99
+ f"{self.__class__.__name__}(io_loop) argument is deprecated in pyzmq 22.2."
100
+ " The currently active loop will always be used.",
101
+ DeprecationWarning,
102
+ stacklevel=2,
103
+ )
104
+ super().__init__(*args, **kwargs) # type: ignore
.venv/lib/python3.11/site-packages/zmq/eventloop/ioloop.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """tornado IOLoop API with zmq compatibility
2
+
3
+ This module is deprecated in pyzmq 17.
4
+ To use zmq with tornado,
5
+ eventloop integration is no longer required
6
+ and tornado itself should be used.
7
+ """
8
+
9
+ # Copyright (C) PyZMQ Developers
10
+ # Distributed under the terms of the Modified BSD License.
11
+
12
+ import warnings
13
+
14
+
15
+ def _deprecated():
16
+ warnings.warn(
17
+ "zmq.eventloop.ioloop is deprecated in pyzmq 17."
18
+ " pyzmq now works with default tornado and asyncio eventloops.",
19
+ DeprecationWarning,
20
+ stacklevel=3,
21
+ )
22
+
23
+
24
+ _deprecated()
25
+
26
+ from tornado.ioloop import * # noqa
27
+ from tornado.ioloop import IOLoop
28
+
29
+ ZMQIOLoop = IOLoop
30
+
31
+
32
+ def install():
33
+ """DEPRECATED
34
+
35
+ pyzmq 17 no longer needs any special integration for tornado.
36
+ """
37
+ _deprecated()
.venv/lib/python3.11/site-packages/zmq/eventloop/zmqstream.py ADDED
@@ -0,0 +1,689 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Derived from iostream.py from tornado 1.0, Copyright 2009 Facebook
2
+ # Used under Apache License Version 2.0
3
+ #
4
+ # Modifications are Copyright (C) PyZMQ Developers
5
+ # Distributed under the terms of the Modified BSD License.
6
+ """A utility class for event-based messaging on a zmq socket using tornado.
7
+
8
+ .. seealso::
9
+
10
+ - :mod:`zmq.asyncio`
11
+ - :mod:`zmq.eventloop.future`
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import asyncio
17
+ import pickle
18
+ import warnings
19
+ from queue import Queue
20
+ from typing import Any, Awaitable, Callable, Sequence, cast, overload
21
+
22
+ from tornado.ioloop import IOLoop
23
+ from tornado.log import gen_log
24
+
25
+ import zmq
26
+ import zmq._future
27
+ from zmq import POLLIN, POLLOUT
28
+ from zmq._typing import Literal
29
+ from zmq.utils import jsonapi
30
+
31
+
32
+ class ZMQStream:
33
+ """A utility class to register callbacks when a zmq socket sends and receives
34
+
35
+ For use with tornado IOLoop.
36
+
37
+ There are three main methods
38
+
39
+ Methods:
40
+
41
+ * **on_recv(callback, copy=True):**
42
+ register a callback to be run every time the socket has something to receive
43
+ * **on_send(callback):**
44
+ register a callback to be run every time you call send
45
+ * **send_multipart(self, msg, flags=0, copy=False, callback=None):**
46
+ perform a send that will trigger the callback
47
+ if callback is passed, on_send is also called.
48
+
49
+ There are also send_multipart(), send_json(), send_pyobj()
50
+
51
+ Three other methods for deactivating the callbacks:
52
+
53
+ * **stop_on_recv():**
54
+ turn off the recv callback
55
+ * **stop_on_send():**
56
+ turn off the send callback
57
+
58
+ which simply call ``on_<evt>(None)``.
59
+
60
+ The entire socket interface, excluding direct recv methods, is also
61
+ provided, primarily through direct-linking the methods.
62
+ e.g.
63
+
64
+ >>> stream.bind is stream.socket.bind
65
+ True
66
+
67
+
68
+ .. versionadded:: 25
69
+
70
+ send/recv callbacks can be coroutines.
71
+
72
+ .. versionchanged:: 25
73
+
74
+ ZMQStreams only support base zmq.Socket classes (this has always been true, but not enforced).
75
+ If ZMQStreams are created with e.g. async Socket subclasses,
76
+ a RuntimeWarning will be shown,
77
+ and the socket cast back to the default zmq.Socket
78
+ before connecting events.
79
+
80
+ Previously, using async sockets (or any zmq.Socket subclass) would result in undefined behavior for the
81
+ arguments passed to callback functions.
82
+ Now, the callback functions reliably get the return value of the base `zmq.Socket` send/recv_multipart methods
83
+ (the list of message frames).
84
+ """
85
+
86
+ socket: zmq.Socket
87
+ io_loop: IOLoop
88
+ poller: zmq.Poller
89
+ _send_queue: Queue
90
+ _recv_callback: Callable | None
91
+ _send_callback: Callable | None
92
+ _close_callback: Callable | None
93
+ _state: int = 0
94
+ _flushed: bool = False
95
+ _recv_copy: bool = False
96
+ _fd: int
97
+
98
+ def __init__(self, socket: zmq.Socket, io_loop: IOLoop | None = None):
99
+ if isinstance(socket, zmq._future._AsyncSocket):
100
+ warnings.warn(
101
+ f"""ZMQStream only supports the base zmq.Socket class.
102
+
103
+ Use zmq.Socket(shadow=other_socket)
104
+ or `ctx.socket(zmq.{socket._type_name}, socket_class=zmq.Socket)`
105
+ to create a base zmq.Socket object,
106
+ no matter what other kind of socket your Context creates.
107
+ """,
108
+ RuntimeWarning,
109
+ stacklevel=2,
110
+ )
111
+ # shadow back to base zmq.Socket,
112
+ # otherwise callbacks like `on_recv` will get the wrong types.
113
+ socket = zmq.Socket(shadow=socket)
114
+ self.socket = socket
115
+
116
+ # IOLoop.current() is deprecated if called outside the event loop
117
+ # that means
118
+ self.io_loop = io_loop or IOLoop.current()
119
+ self.poller = zmq.Poller()
120
+ self._fd = cast(int, self.socket.FD)
121
+
122
+ self._send_queue = Queue()
123
+ self._recv_callback = None
124
+ self._send_callback = None
125
+ self._close_callback = None
126
+ self._recv_copy = False
127
+ self._flushed = False
128
+
129
+ self._state = 0
130
+ self._init_io_state()
131
+
132
+ # shortcircuit some socket methods
133
+ self.bind = self.socket.bind
134
+ self.bind_to_random_port = self.socket.bind_to_random_port
135
+ self.connect = self.socket.connect
136
+ self.setsockopt = self.socket.setsockopt
137
+ self.getsockopt = self.socket.getsockopt
138
+ self.setsockopt_string = self.socket.setsockopt_string
139
+ self.getsockopt_string = self.socket.getsockopt_string
140
+ self.setsockopt_unicode = self.socket.setsockopt_unicode
141
+ self.getsockopt_unicode = self.socket.getsockopt_unicode
142
+
143
+ def stop_on_recv(self):
144
+ """Disable callback and automatic receiving."""
145
+ return self.on_recv(None)
146
+
147
+ def stop_on_send(self):
148
+ """Disable callback on sending."""
149
+ return self.on_send(None)
150
+
151
+ def stop_on_err(self):
152
+ """DEPRECATED, does nothing"""
153
+ gen_log.warn("on_err does nothing, and will be removed")
154
+
155
+ def on_err(self, callback: Callable):
156
+ """DEPRECATED, does nothing"""
157
+ gen_log.warn("on_err does nothing, and will be removed")
158
+
159
+ @overload
160
+ def on_recv(
161
+ self,
162
+ callback: Callable[[list[bytes]], Any],
163
+ ) -> None: ...
164
+
165
+ @overload
166
+ def on_recv(
167
+ self,
168
+ callback: Callable[[list[bytes]], Any],
169
+ copy: Literal[True],
170
+ ) -> None: ...
171
+
172
+ @overload
173
+ def on_recv(
174
+ self,
175
+ callback: Callable[[list[zmq.Frame]], Any],
176
+ copy: Literal[False],
177
+ ) -> None: ...
178
+
179
+ @overload
180
+ def on_recv(
181
+ self,
182
+ callback: Callable[[list[zmq.Frame]], Any] | Callable[[list[bytes]], Any],
183
+ copy: bool = ...,
184
+ ): ...
185
+
186
+ def on_recv(
187
+ self,
188
+ callback: Callable[[list[zmq.Frame]], Any] | Callable[[list[bytes]], Any],
189
+ copy: bool = True,
190
+ ) -> None:
191
+ """Register a callback for when a message is ready to recv.
192
+
193
+ There can be only one callback registered at a time, so each
194
+ call to `on_recv` replaces previously registered callbacks.
195
+
196
+ on_recv(None) disables recv event polling.
197
+
198
+ Use on_recv_stream(callback) instead, to register a callback that will receive
199
+ both this ZMQStream and the message, instead of just the message.
200
+
201
+ Parameters
202
+ ----------
203
+
204
+ callback : callable
205
+ callback must take exactly one argument, which will be a
206
+ list, as returned by socket.recv_multipart()
207
+ if callback is None, recv callbacks are disabled.
208
+ copy : bool
209
+ copy is passed directly to recv, so if copy is False,
210
+ callback will receive Message objects. If copy is True,
211
+ then callback will receive bytes/str objects.
212
+
213
+ Returns : None
214
+ """
215
+
216
+ self._check_closed()
217
+ assert callback is None or callable(callback)
218
+ self._recv_callback = callback
219
+ self._recv_copy = copy
220
+ if callback is None:
221
+ self._drop_io_state(zmq.POLLIN)
222
+ else:
223
+ self._add_io_state(zmq.POLLIN)
224
+
225
+ @overload
226
+ def on_recv_stream(
227
+ self,
228
+ callback: Callable[[ZMQStream, list[bytes]], Any],
229
+ ) -> None: ...
230
+
231
+ @overload
232
+ def on_recv_stream(
233
+ self,
234
+ callback: Callable[[ZMQStream, list[bytes]], Any],
235
+ copy: Literal[True],
236
+ ) -> None: ...
237
+
238
+ @overload
239
+ def on_recv_stream(
240
+ self,
241
+ callback: Callable[[ZMQStream, list[zmq.Frame]], Any],
242
+ copy: Literal[False],
243
+ ) -> None: ...
244
+
245
+ @overload
246
+ def on_recv_stream(
247
+ self,
248
+ callback: (
249
+ Callable[[ZMQStream, list[zmq.Frame]], Any]
250
+ | Callable[[ZMQStream, list[bytes]], Any]
251
+ ),
252
+ copy: bool = ...,
253
+ ): ...
254
+
255
+ def on_recv_stream(
256
+ self,
257
+ callback: (
258
+ Callable[[ZMQStream, list[zmq.Frame]], Any]
259
+ | Callable[[ZMQStream, list[bytes]], Any]
260
+ ),
261
+ copy: bool = True,
262
+ ):
263
+ """Same as on_recv, but callback will get this stream as first argument
264
+
265
+ callback must take exactly two arguments, as it will be called as::
266
+
267
+ callback(stream, msg)
268
+
269
+ Useful when a single callback should be used with multiple streams.
270
+ """
271
+ if callback is None:
272
+ self.stop_on_recv()
273
+ else:
274
+
275
+ def stream_callback(msg):
276
+ return callback(self, msg)
277
+
278
+ self.on_recv(stream_callback, copy=copy)
279
+
280
+ def on_send(
281
+ self, callback: Callable[[Sequence[Any], zmq.MessageTracker | None], Any]
282
+ ):
283
+ """Register a callback to be called on each send
284
+
285
+ There will be two arguments::
286
+
287
+ callback(msg, status)
288
+
289
+ * `msg` will be the list of sendable objects that was just sent
290
+ * `status` will be the return result of socket.send_multipart(msg) -
291
+ MessageTracker or None.
292
+
293
+ Non-copying sends return a MessageTracker object whose
294
+ `done` attribute will be True when the send is complete.
295
+ This allows users to track when an object is safe to write to
296
+ again.
297
+
298
+ The second argument will always be None if copy=True
299
+ on the send.
300
+
301
+ Use on_send_stream(callback) to register a callback that will be passed
302
+ this ZMQStream as the first argument, in addition to the other two.
303
+
304
+ on_send(None) disables recv event polling.
305
+
306
+ Parameters
307
+ ----------
308
+
309
+ callback : callable
310
+ callback must take exactly two arguments, which will be
311
+ the message being sent (always a list),
312
+ and the return result of socket.send_multipart(msg) -
313
+ MessageTracker or None.
314
+
315
+ if callback is None, send callbacks are disabled.
316
+ """
317
+
318
+ self._check_closed()
319
+ assert callback is None or callable(callback)
320
+ self._send_callback = callback
321
+
322
+ def on_send_stream(
323
+ self,
324
+ callback: Callable[[ZMQStream, Sequence[Any], zmq.MessageTracker | None], Any],
325
+ ):
326
+ """Same as on_send, but callback will get this stream as first argument
327
+
328
+ Callback will be passed three arguments::
329
+
330
+ callback(stream, msg, status)
331
+
332
+ Useful when a single callback should be used with multiple streams.
333
+ """
334
+ if callback is None:
335
+ self.stop_on_send()
336
+ else:
337
+ self.on_send(lambda msg, status: callback(self, msg, status))
338
+
339
+ def send(self, msg, flags=0, copy=True, track=False, callback=None, **kwargs):
340
+ """Send a message, optionally also register a new callback for sends.
341
+ See zmq.socket.send for details.
342
+ """
343
+ return self.send_multipart(
344
+ [msg], flags=flags, copy=copy, track=track, callback=callback, **kwargs
345
+ )
346
+
347
+ def send_multipart(
348
+ self,
349
+ msg: Sequence[Any],
350
+ flags: int = 0,
351
+ copy: bool = True,
352
+ track: bool = False,
353
+ callback: Callable | None = None,
354
+ **kwargs: Any,
355
+ ) -> None:
356
+ """Send a multipart message, optionally also register a new callback for sends.
357
+ See zmq.socket.send_multipart for details.
358
+ """
359
+ kwargs.update(dict(flags=flags, copy=copy, track=track))
360
+ self._send_queue.put((msg, kwargs))
361
+ callback = callback or self._send_callback
362
+ if callback is not None:
363
+ self.on_send(callback)
364
+ else:
365
+ # noop callback
366
+ self.on_send(lambda *args: None)
367
+ self._add_io_state(zmq.POLLOUT)
368
+
369
+ def send_string(
370
+ self,
371
+ u: str,
372
+ flags: int = 0,
373
+ encoding: str = 'utf-8',
374
+ callback: Callable | None = None,
375
+ **kwargs: Any,
376
+ ):
377
+ """Send a unicode message with an encoding.
378
+ See zmq.socket.send_unicode for details.
379
+ """
380
+ if not isinstance(u, str):
381
+ raise TypeError("unicode/str objects only")
382
+ return self.send(u.encode(encoding), flags=flags, callback=callback, **kwargs)
383
+
384
+ send_unicode = send_string
385
+
386
+ def send_json(
387
+ self,
388
+ obj: Any,
389
+ flags: int = 0,
390
+ callback: Callable | None = None,
391
+ **kwargs: Any,
392
+ ):
393
+ """Send json-serialized version of an object.
394
+ See zmq.socket.send_json for details.
395
+ """
396
+ msg = jsonapi.dumps(obj)
397
+ return self.send(msg, flags=flags, callback=callback, **kwargs)
398
+
399
+ def send_pyobj(
400
+ self,
401
+ obj: Any,
402
+ flags: int = 0,
403
+ protocol: int = -1,
404
+ callback: Callable | None = None,
405
+ **kwargs: Any,
406
+ ):
407
+ """Send a Python object as a message using pickle to serialize.
408
+
409
+ See zmq.socket.send_json for details.
410
+ """
411
+ msg = pickle.dumps(obj, protocol)
412
+ return self.send(msg, flags, callback=callback, **kwargs)
413
+
414
+ def _finish_flush(self):
415
+ """callback for unsetting _flushed flag."""
416
+ self._flushed = False
417
+
418
+ def flush(self, flag: int = zmq.POLLIN | zmq.POLLOUT, limit: int | None = None):
419
+ """Flush pending messages.
420
+
421
+ This method safely handles all pending incoming and/or outgoing messages,
422
+ bypassing the inner loop, passing them to the registered callbacks.
423
+
424
+ A limit can be specified, to prevent blocking under high load.
425
+
426
+ flush will return the first time ANY of these conditions are met:
427
+ * No more events matching the flag are pending.
428
+ * the total number of events handled reaches the limit.
429
+
430
+ Note that if ``flag|POLLIN != 0``, recv events will be flushed even if no callback
431
+ is registered, unlike normal IOLoop operation. This allows flush to be
432
+ used to remove *and ignore* incoming messages.
433
+
434
+ Parameters
435
+ ----------
436
+ flag : int
437
+ default=POLLIN|POLLOUT
438
+ 0MQ poll flags.
439
+ If flag|POLLIN, recv events will be flushed.
440
+ If flag|POLLOUT, send events will be flushed.
441
+ Both flags can be set at once, which is the default.
442
+ limit : None or int, optional
443
+ The maximum number of messages to send or receive.
444
+ Both send and recv count against this limit.
445
+
446
+ Returns
447
+ -------
448
+ int :
449
+ count of events handled (both send and recv)
450
+ """
451
+ self._check_closed()
452
+ # unset self._flushed, so callbacks will execute, in case flush has
453
+ # already been called this iteration
454
+ already_flushed = self._flushed
455
+ self._flushed = False
456
+ # initialize counters
457
+ count = 0
458
+
459
+ def update_flag():
460
+ """Update the poll flag, to prevent registering POLLOUT events
461
+ if we don't have pending sends."""
462
+ return flag & zmq.POLLIN | (self.sending() and flag & zmq.POLLOUT)
463
+
464
+ flag = update_flag()
465
+ if not flag:
466
+ # nothing to do
467
+ return 0
468
+ self.poller.register(self.socket, flag)
469
+ events = self.poller.poll(0)
470
+ while events and (not limit or count < limit):
471
+ s, event = events[0]
472
+ if event & POLLIN: # receiving
473
+ self._handle_recv()
474
+ count += 1
475
+ if self.socket is None:
476
+ # break if socket was closed during callback
477
+ break
478
+ if event & POLLOUT and self.sending():
479
+ self._handle_send()
480
+ count += 1
481
+ if self.socket is None:
482
+ # break if socket was closed during callback
483
+ break
484
+
485
+ flag = update_flag()
486
+ if flag:
487
+ self.poller.register(self.socket, flag)
488
+ events = self.poller.poll(0)
489
+ else:
490
+ events = []
491
+ if count: # only bypass loop if we actually flushed something
492
+ # skip send/recv callbacks this iteration
493
+ self._flushed = True
494
+ # reregister them at the end of the loop
495
+ if not already_flushed: # don't need to do it again
496
+ self.io_loop.add_callback(self._finish_flush)
497
+ elif already_flushed:
498
+ self._flushed = True
499
+
500
+ # update ioloop poll state, which may have changed
501
+ self._rebuild_io_state()
502
+ return count
503
+
504
+ def set_close_callback(self, callback: Callable | None):
505
+ """Call the given callback when the stream is closed."""
506
+ self._close_callback = callback
507
+
508
+ def close(self, linger: int | None = None) -> None:
509
+ """Close this stream."""
510
+ if self.socket is not None:
511
+ if self.socket.closed:
512
+ # fallback on raw fd for closed sockets
513
+ # hopefully this happened promptly after close,
514
+ # otherwise somebody else may have the FD
515
+ warnings.warn(
516
+ f"Unregistering FD {self._fd} after closing socket. "
517
+ "This could result in unregistering handlers for the wrong socket. "
518
+ "Please use stream.close() instead of closing the socket directly.",
519
+ stacklevel=2,
520
+ )
521
+ self.io_loop.remove_handler(self._fd)
522
+ else:
523
+ self.io_loop.remove_handler(self.socket)
524
+ self.socket.close(linger)
525
+ self.socket = None # type: ignore
526
+ if self._close_callback:
527
+ self._run_callback(self._close_callback)
528
+
529
+ def receiving(self) -> bool:
530
+ """Returns True if we are currently receiving from the stream."""
531
+ return self._recv_callback is not None
532
+
533
+ def sending(self) -> bool:
534
+ """Returns True if we are currently sending to the stream."""
535
+ return not self._send_queue.empty()
536
+
537
+ def closed(self) -> bool:
538
+ if self.socket is None:
539
+ return True
540
+ if self.socket.closed:
541
+ # underlying socket has been closed, but not by us!
542
+ # trigger our cleanup
543
+ self.close()
544
+ return True
545
+ return False
546
+
547
+ def _run_callback(self, callback, *args, **kwargs):
548
+ """Wrap running callbacks in try/except to allow us to
549
+ close our socket."""
550
+ try:
551
+ f = callback(*args, **kwargs)
552
+ if isinstance(f, Awaitable):
553
+ f = asyncio.ensure_future(f)
554
+ else:
555
+ f = None
556
+ except Exception:
557
+ gen_log.error("Uncaught exception in ZMQStream callback", exc_info=True)
558
+ # Re-raise the exception so that IOLoop.handle_callback_exception
559
+ # can see it and log the error
560
+ raise
561
+
562
+ if f is not None:
563
+ # handle async callbacks
564
+ def _log_error(f):
565
+ try:
566
+ f.result()
567
+ except Exception:
568
+ gen_log.error(
569
+ "Uncaught exception in ZMQStream callback", exc_info=True
570
+ )
571
+
572
+ f.add_done_callback(_log_error)
573
+
574
+ def _handle_events(self, fd, events):
575
+ """This method is the actual handler for IOLoop, that gets called whenever
576
+ an event on my socket is posted. It dispatches to _handle_recv, etc."""
577
+ if not self.socket:
578
+ gen_log.warning("Got events for closed stream %s", self)
579
+ return
580
+ try:
581
+ zmq_events = self.socket.EVENTS
582
+ except zmq.ContextTerminated:
583
+ gen_log.warning("Got events for stream %s after terminating context", self)
584
+ # trigger close check, this will unregister callbacks
585
+ self.closed()
586
+ return
587
+ except zmq.ZMQError as e:
588
+ # run close check
589
+ # shadow sockets may have been closed elsewhere,
590
+ # which should show up as ENOTSOCK here
591
+ if self.closed():
592
+ gen_log.warning(
593
+ "Got events for stream %s attached to closed socket: %s", self, e
594
+ )
595
+ else:
596
+ gen_log.error("Error getting events for %s: %s", self, e)
597
+ return
598
+ try:
599
+ # dispatch events:
600
+ if zmq_events & zmq.POLLIN and self.receiving():
601
+ self._handle_recv()
602
+ if not self.socket:
603
+ return
604
+ if zmq_events & zmq.POLLOUT and self.sending():
605
+ self._handle_send()
606
+ if not self.socket:
607
+ return
608
+
609
+ # rebuild the poll state
610
+ self._rebuild_io_state()
611
+ except Exception:
612
+ gen_log.error("Uncaught exception in zmqstream callback", exc_info=True)
613
+ raise
614
+
615
+ def _handle_recv(self):
616
+ """Handle a recv event."""
617
+ if self._flushed:
618
+ return
619
+ try:
620
+ msg = self.socket.recv_multipart(zmq.NOBLOCK, copy=self._recv_copy)
621
+ except zmq.ZMQError as e:
622
+ if e.errno == zmq.EAGAIN:
623
+ # state changed since poll event
624
+ pass
625
+ else:
626
+ raise
627
+ else:
628
+ if self._recv_callback:
629
+ callback = self._recv_callback
630
+ self._run_callback(callback, msg)
631
+
632
+ def _handle_send(self):
633
+ """Handle a send event."""
634
+ if self._flushed:
635
+ return
636
+ if not self.sending():
637
+ gen_log.error("Shouldn't have handled a send event")
638
+ return
639
+
640
+ msg, kwargs = self._send_queue.get()
641
+ try:
642
+ status = self.socket.send_multipart(msg, **kwargs)
643
+ except zmq.ZMQError as e:
644
+ gen_log.error("SEND Error: %s", e)
645
+ status = e
646
+ if self._send_callback:
647
+ callback = self._send_callback
648
+ self._run_callback(callback, msg, status)
649
+
650
+ def _check_closed(self):
651
+ if not self.socket:
652
+ raise OSError("Stream is closed")
653
+
654
+ def _rebuild_io_state(self):
655
+ """rebuild io state based on self.sending() and receiving()"""
656
+ if self.socket is None:
657
+ return
658
+ state = 0
659
+ if self.receiving():
660
+ state |= zmq.POLLIN
661
+ if self.sending():
662
+ state |= zmq.POLLOUT
663
+
664
+ self._state = state
665
+ self._update_handler(state)
666
+
667
+ def _add_io_state(self, state):
668
+ """Add io_state to poller."""
669
+ self._state = self._state | state
670
+ self._update_handler(self._state)
671
+
672
+ def _drop_io_state(self, state):
673
+ """Stop poller from watching an io_state."""
674
+ self._state = self._state & (~state)
675
+ self._update_handler(self._state)
676
+
677
+ def _update_handler(self, state):
678
+ """Update IOLoop handler with state."""
679
+ if self.socket is None:
680
+ return
681
+
682
+ if state & self.socket.events:
683
+ # events still exist that haven't been processed
684
+ # explicitly schedule handling to avoid missing events due to edge-triggered FDs
685
+ self.io_loop.add_callback(lambda: self._handle_events(self.socket, 0))
686
+
687
+ def _init_io_state(self):
688
+ """initialize the ioloop event handler"""
689
+ self.io_loop.add_handler(self.socket, self._handle_events, self.io_loop.READ)
.venv/lib/python3.11/site-packages/zmq/green/__init__.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -----------------------------------------------------------------------------
2
+ # Copyright (C) 2011-2012 Travis Cline
3
+ #
4
+ # This file is part of pyzmq
5
+ # It is adapted from upstream project zeromq_gevent under the New BSD License
6
+ #
7
+ # Distributed under the terms of the New BSD License. The full license is in
8
+ # the file LICENSE.BSD, distributed as part of this software.
9
+ # -----------------------------------------------------------------------------
10
+
11
+ """zmq.green - gevent compatibility with zeromq.
12
+
13
+ Usage
14
+ -----
15
+
16
+ Instead of importing zmq directly, do so in the following manner:
17
+
18
+ ..
19
+
20
+ import zmq.green as zmq
21
+
22
+
23
+ Any calls that would have blocked the current thread will now only block the
24
+ current green thread.
25
+
26
+ This compatibility is accomplished by ensuring the nonblocking flag is set
27
+ before any blocking operation and the ØMQ file descriptor is polled internally
28
+ to trigger needed events.
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ from typing import List
34
+
35
+ import zmq as _zmq
36
+ from zmq import *
37
+ from zmq.green.core import _Context, _Socket
38
+ from zmq.green.poll import _Poller
39
+
40
+ Context = _Context # type: ignore
41
+ Socket = _Socket # type: ignore
42
+ Poller = _Poller # type: ignore
43
+
44
+ from zmq.green.device import device # type: ignore
45
+
46
+ __all__: list[str] = []
47
+ # adding `__all__` to __init__.pyi gets mypy all confused
48
+ __all__.extend(_zmq.__all__) # type: ignore
.venv/lib/python3.11/site-packages/zmq/green/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (1.25 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/green/__pycache__/core.cpython-311.pyc ADDED
Binary file (14.5 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/green/__pycache__/device.cpython-311.pyc ADDED
Binary file (1.54 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/green/__pycache__/poll.cpython-311.pyc ADDED
Binary file (4.29 kB). View file
 
.venv/lib/python3.11/site-packages/zmq/green/core.py ADDED
@@ -0,0 +1,317 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -----------------------------------------------------------------------------
2
+ # Copyright (C) 2011-2012 Travis Cline
3
+ #
4
+ # This file is part of pyzmq
5
+ # It is adapted from upstream project zeromq_gevent under the New BSD License
6
+ #
7
+ # Distributed under the terms of the New BSD License. The full license is in
8
+ # the file LICENSE.BSD, distributed as part of this software.
9
+ # -----------------------------------------------------------------------------
10
+
11
+ """This module wraps the :class:`Socket` and :class:`Context` found in :mod:`pyzmq <zmq>` to be non blocking"""
12
+
13
+ from __future__ import annotations
14
+
15
+ import sys
16
+ import time
17
+ import warnings
18
+
19
+ import gevent
20
+ from gevent.event import AsyncResult
21
+ from gevent.hub import get_hub
22
+
23
+ import zmq
24
+ from zmq import Context as _original_Context
25
+ from zmq import Socket as _original_Socket
26
+
27
+ from .poll import _Poller
28
+
29
+ if hasattr(zmq, 'RCVTIMEO'):
30
+ TIMEOS: tuple = (zmq.RCVTIMEO, zmq.SNDTIMEO)
31
+ else:
32
+ TIMEOS = ()
33
+
34
+
35
+ def _stop(evt):
36
+ """simple wrapper for stopping an Event, allowing for method rename in gevent 1.0"""
37
+ try:
38
+ evt.stop()
39
+ except AttributeError:
40
+ # gevent<1.0 compat
41
+ evt.cancel()
42
+
43
+
44
+ class _Socket(_original_Socket):
45
+ """Green version of :class:`zmq.Socket`
46
+
47
+ The following methods are overridden:
48
+
49
+ * send
50
+ * recv
51
+
52
+ To ensure that the ``zmq.NOBLOCK`` flag is set and that sending or receiving
53
+ is deferred to the hub if a ``zmq.EAGAIN`` (retry) error is raised.
54
+
55
+ The `__state_changed` method is triggered when the zmq.FD for the socket is
56
+ marked as readable and triggers the necessary read and write events (which
57
+ are waited for in the recv and send methods).
58
+
59
+ Some double underscore prefixes are used to minimize pollution of
60
+ :class:`zmq.Socket`'s namespace.
61
+ """
62
+
63
+ __in_send_multipart = False
64
+ __in_recv_multipart = False
65
+ __writable = None
66
+ __readable = None
67
+ _state_event = None
68
+ _gevent_bug_timeout = 11.6 # timeout for not trusting gevent
69
+ _debug_gevent = False # turn on if you think gevent is missing events
70
+ _poller_class = _Poller
71
+ _repr_cls = "zmq.green.Socket"
72
+
73
+ def __init__(self, *a, **kw):
74
+ super().__init__(*a, **kw)
75
+ self.__in_send_multipart = False
76
+ self.__in_recv_multipart = False
77
+ self.__setup_events()
78
+
79
+ def __del__(self):
80
+ self.close()
81
+
82
+ def close(self, linger=None):
83
+ super().close(linger)
84
+ self.__cleanup_events()
85
+
86
+ def __cleanup_events(self):
87
+ # close the _state_event event, keeps the number of active file descriptors down
88
+ if getattr(self, '_state_event', None):
89
+ _stop(self._state_event)
90
+ self._state_event = None
91
+ # if the socket has entered a close state resume any waiting greenlets
92
+ self.__writable.set()
93
+ self.__readable.set()
94
+
95
+ def __setup_events(self):
96
+ self.__readable = AsyncResult()
97
+ self.__writable = AsyncResult()
98
+ self.__readable.set()
99
+ self.__writable.set()
100
+
101
+ try:
102
+ self._state_event = get_hub().loop.io(
103
+ self.getsockopt(zmq.FD), 1
104
+ ) # read state watcher
105
+ self._state_event.start(self.__state_changed)
106
+ except AttributeError:
107
+ # for gevent<1.0 compatibility
108
+ from gevent.core import read_event
109
+
110
+ self._state_event = read_event(
111
+ self.getsockopt(zmq.FD), self.__state_changed, persist=True
112
+ )
113
+
114
+ def __state_changed(self, event=None, _evtype=None):
115
+ if self.closed:
116
+ self.__cleanup_events()
117
+ return
118
+ try:
119
+ # avoid triggering __state_changed from inside __state_changed
120
+ events = super().getsockopt(zmq.EVENTS)
121
+ except zmq.ZMQError as exc:
122
+ self.__writable.set_exception(exc)
123
+ self.__readable.set_exception(exc)
124
+ else:
125
+ if events & zmq.POLLOUT:
126
+ self.__writable.set()
127
+ if events & zmq.POLLIN:
128
+ self.__readable.set()
129
+
130
+ def _wait_write(self):
131
+ assert self.__writable.ready(), "Only one greenlet can be waiting on this event"
132
+ self.__writable = AsyncResult()
133
+ # timeout is because libzmq cannot be trusted to properly signal a new send event:
134
+ # this is effectively a maximum poll interval of 1s
135
+ tic = time.time()
136
+ dt = self._gevent_bug_timeout
137
+ if dt:
138
+ timeout = gevent.Timeout(seconds=dt)
139
+ else:
140
+ timeout = None
141
+ try:
142
+ if timeout:
143
+ timeout.start()
144
+ self.__writable.get(block=True)
145
+ except gevent.Timeout as t:
146
+ if t is not timeout:
147
+ raise
148
+ toc = time.time()
149
+ # gevent bug: get can raise timeout even on clean return
150
+ # don't display zmq bug warning for gevent bug (this is getting ridiculous)
151
+ if (
152
+ self._debug_gevent
153
+ and timeout
154
+ and toc - tic > dt
155
+ and self.getsockopt(zmq.EVENTS) & zmq.POLLOUT
156
+ ):
157
+ print(
158
+ f"BUG: gevent may have missed a libzmq send event on {self.FD}!",
159
+ file=sys.stderr,
160
+ )
161
+ finally:
162
+ if timeout:
163
+ timeout.close()
164
+ self.__writable.set()
165
+
166
+ def _wait_read(self):
167
+ assert self.__readable.ready(), "Only one greenlet can be waiting on this event"
168
+ self.__readable = AsyncResult()
169
+ # timeout is because libzmq cannot always be trusted to play nice with libevent.
170
+ # I can only confirm that this actually happens for send, but lets be symmetrical
171
+ # with our dirty hacks.
172
+ # this is effectively a maximum poll interval of 1s
173
+ tic = time.time()
174
+ dt = self._gevent_bug_timeout
175
+ if dt:
176
+ timeout = gevent.Timeout(seconds=dt)
177
+ else:
178
+ timeout = None
179
+ try:
180
+ if timeout:
181
+ timeout.start()
182
+ self.__readable.get(block=True)
183
+ except gevent.Timeout as t:
184
+ if t is not timeout:
185
+ raise
186
+ toc = time.time()
187
+ # gevent bug: get can raise timeout even on clean return
188
+ # don't display zmq bug warning for gevent bug (this is getting ridiculous)
189
+ if (
190
+ self._debug_gevent
191
+ and timeout
192
+ and toc - tic > dt
193
+ and self.getsockopt(zmq.EVENTS) & zmq.POLLIN
194
+ ):
195
+ print(
196
+ f"BUG: gevent may have missed a libzmq recv event on {self.FD}!",
197
+ file=sys.stderr,
198
+ )
199
+ finally:
200
+ if timeout:
201
+ timeout.close()
202
+ self.__readable.set()
203
+
204
+ def send(self, data, flags=0, copy=True, track=False, **kwargs):
205
+ """send, which will only block current greenlet
206
+
207
+ state_changed always fires exactly once (success or fail) at the
208
+ end of this method.
209
+ """
210
+
211
+ # if we're given the NOBLOCK flag act as normal and let the EAGAIN get raised
212
+ if flags & zmq.NOBLOCK:
213
+ try:
214
+ msg = super().send(data, flags, copy, track, **kwargs)
215
+ finally:
216
+ if not self.__in_send_multipart:
217
+ self.__state_changed()
218
+ return msg
219
+ # ensure the zmq.NOBLOCK flag is part of flags
220
+ flags |= zmq.NOBLOCK
221
+ while True: # Attempt to complete this operation indefinitely, blocking the current greenlet
222
+ try:
223
+ # attempt the actual call
224
+ msg = super().send(data, flags, copy, track)
225
+ except zmq.ZMQError as e:
226
+ # if the raised ZMQError is not EAGAIN, reraise
227
+ if e.errno != zmq.EAGAIN:
228
+ if not self.__in_send_multipart:
229
+ self.__state_changed()
230
+ raise
231
+ else:
232
+ if not self.__in_send_multipart:
233
+ self.__state_changed()
234
+ return msg
235
+ # defer to the event loop until we're notified the socket is writable
236
+ self._wait_write()
237
+
238
+ def recv(self, flags=0, copy=True, track=False):
239
+ """recv, which will only block current greenlet
240
+
241
+ state_changed always fires exactly once (success or fail) at the
242
+ end of this method.
243
+ """
244
+ if flags & zmq.NOBLOCK:
245
+ try:
246
+ msg = super().recv(flags, copy, track)
247
+ finally:
248
+ if not self.__in_recv_multipart:
249
+ self.__state_changed()
250
+ return msg
251
+
252
+ flags |= zmq.NOBLOCK
253
+ while True:
254
+ try:
255
+ msg = super().recv(flags, copy, track)
256
+ except zmq.ZMQError as e:
257
+ if e.errno != zmq.EAGAIN:
258
+ if not self.__in_recv_multipart:
259
+ self.__state_changed()
260
+ raise
261
+ else:
262
+ if not self.__in_recv_multipart:
263
+ self.__state_changed()
264
+ return msg
265
+ self._wait_read()
266
+
267
+ def send_multipart(self, *args, **kwargs):
268
+ """wrap send_multipart to prevent state_changed on each partial send"""
269
+ self.__in_send_multipart = True
270
+ try:
271
+ msg = super().send_multipart(*args, **kwargs)
272
+ finally:
273
+ self.__in_send_multipart = False
274
+ self.__state_changed()
275
+ return msg
276
+
277
+ def recv_multipart(self, *args, **kwargs):
278
+ """wrap recv_multipart to prevent state_changed on each partial recv"""
279
+ self.__in_recv_multipart = True
280
+ try:
281
+ msg = super().recv_multipart(*args, **kwargs)
282
+ finally:
283
+ self.__in_recv_multipart = False
284
+ self.__state_changed()
285
+ return msg
286
+
287
+ def get(self, opt):
288
+ """trigger state_changed on getsockopt(EVENTS)"""
289
+ if opt in TIMEOS:
290
+ warnings.warn(
291
+ "TIMEO socket options have no effect in zmq.green", UserWarning
292
+ )
293
+ optval = super().get(opt)
294
+ if opt == zmq.EVENTS:
295
+ self.__state_changed()
296
+ return optval
297
+
298
+ def set(self, opt, val):
299
+ """set socket option"""
300
+ if opt in TIMEOS:
301
+ warnings.warn(
302
+ "TIMEO socket options have no effect in zmq.green", UserWarning
303
+ )
304
+ return super().set(opt, val)
305
+
306
+
307
+ class _Context(_original_Context[_Socket]):
308
+ """Replacement for :class:`zmq.Context`
309
+
310
+ Ensures that the greened Socket above is used in calls to `socket`.
311
+ """
312
+
313
+ _socket_class = _Socket
314
+ _repr_cls = "zmq.green.Context"
315
+
316
+ # avoid sharing instance with base Context class
317
+ _instance = None
.venv/lib/python3.11/site-packages/zmq/green/device.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) PyZMQ Developers
2
+ # Distributed under the terms of the Modified BSD License.
3
+ from __future__ import annotations
4
+
5
+ import zmq
6
+ from zmq.green import Poller
7
+
8
+
9
+ def device(device_type, isocket, osocket):
10
+ """Start a zeromq device (gevent-compatible).
11
+
12
+ Unlike the true zmq.device, this does not release the GIL.
13
+
14
+ Parameters
15
+ ----------
16
+ device_type : (QUEUE, FORWARDER, STREAMER)
17
+ The type of device to start (ignored).
18
+ isocket : Socket
19
+ The Socket instance for the incoming traffic.
20
+ osocket : Socket
21
+ The Socket instance for the outbound traffic.
22
+ """
23
+ p = Poller()
24
+ if osocket == -1:
25
+ osocket = isocket
26
+ p.register(isocket, zmq.POLLIN)
27
+ p.register(osocket, zmq.POLLIN)
28
+
29
+ while True:
30
+ events = dict(p.poll())
31
+ if isocket in events:
32
+ osocket.send_multipart(isocket.recv_multipart())
33
+ if osocket in events:
34
+ isocket.send_multipart(osocket.recv_multipart())