Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +1 -0
- .venv/lib/python3.11/site-packages/fsspec/tests/abstract/__init__.py +289 -0
- .venv/lib/python3.11/site-packages/fsspec/tests/abstract/__pycache__/get.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/fsspec/tests/abstract/__pycache__/pipe.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/fsspec/tests/abstract/__pycache__/put.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/fsspec/tests/abstract/open.py +11 -0
- .venv/lib/python3.11/site-packages/functorch/_C.cpython-311-x86_64-linux-gnu.so +3 -0
- .venv/lib/python3.11/site-packages/zmq/__init__.pxd +1 -0
- .venv/lib/python3.11/site-packages/zmq/__init__.py +94 -0
- .venv/lib/python3.11/site-packages/zmq/__init__.pyi +29 -0
- .venv/lib/python3.11/site-packages/zmq/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/__pycache__/_future.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/__pycache__/_typing.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/__pycache__/asyncio.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/__pycache__/constants.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/__pycache__/decorators.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/__pycache__/error.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/_future.pyi +92 -0
- .venv/lib/python3.11/site-packages/zmq/_typing.py +30 -0
- .venv/lib/python3.11/site-packages/zmq/auth/__init__.py +13 -0
- .venv/lib/python3.11/site-packages/zmq/auth/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/auth/__pycache__/asyncio.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/auth/__pycache__/base.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/auth/__pycache__/certs.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/auth/__pycache__/ioloop.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/auth/__pycache__/thread.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/auth/asyncio.py +66 -0
- .venv/lib/python3.11/site-packages/zmq/auth/base.py +445 -0
- .venv/lib/python3.11/site-packages/zmq/auth/certs.py +140 -0
- .venv/lib/python3.11/site-packages/zmq/auth/ioloop.py +48 -0
- .venv/lib/python3.11/site-packages/zmq/auth/thread.py +139 -0
- .venv/lib/python3.11/site-packages/zmq/constants.py +974 -0
- .venv/lib/python3.11/site-packages/zmq/devices/__init__.py +28 -0
- .venv/lib/python3.11/site-packages/zmq/devices/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/devices/__pycache__/basedevice.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/devices/__pycache__/monitoredqueue.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/devices/__pycache__/monitoredqueuedevice.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/devices/__pycache__/proxydevice.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/devices/__pycache__/proxysteerabledevice.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/devices/basedevice.py +310 -0
- .venv/lib/python3.11/site-packages/zmq/devices/monitoredqueue.py +51 -0
- .venv/lib/python3.11/site-packages/zmq/devices/monitoredqueuedevice.py +60 -0
- .venv/lib/python3.11/site-packages/zmq/devices/proxydevice.py +104 -0
- .venv/lib/python3.11/site-packages/zmq/devices/proxysteerabledevice.py +106 -0
- .venv/lib/python3.11/site-packages/zmq/log/__init__.py +0 -0
- .venv/lib/python3.11/site-packages/zmq/log/__main__.py +135 -0
- .venv/lib/python3.11/site-packages/zmq/log/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/log/__pycache__/__main__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/log/__pycache__/handlers.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/zmq/log/handlers.py +232 -0
.gitattributes
CHANGED
|
@@ -211,3 +211,4 @@ tuning-competition-baseline/.venv/lib/python3.11/site-packages/torch/_inductor/_
|
|
| 211 |
.venv/lib/python3.11/site-packages/watchfiles/_rust_notify.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 212 |
.venv/lib/python3.11/site-packages/frozenlist/_frozenlist.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 213 |
.venv/lib/python3.11/site-packages/uvloop/loop.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 211 |
.venv/lib/python3.11/site-packages/watchfiles/_rust_notify.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 212 |
.venv/lib/python3.11/site-packages/frozenlist/_frozenlist.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 213 |
.venv/lib/python3.11/site-packages/uvloop/loop.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 214 |
+
.venv/lib/python3.11/site-packages/functorch/_C.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
.venv/lib/python3.11/site-packages/fsspec/tests/abstract/__init__.py
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from hashlib import md5
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from fsspec.implementations.local import LocalFileSystem
|
| 7 |
+
from fsspec.tests.abstract.copy import AbstractCopyTests # noqa: F401
|
| 8 |
+
from fsspec.tests.abstract.get import AbstractGetTests # noqa: F401
|
| 9 |
+
from fsspec.tests.abstract.open import AbstractOpenTests # noqa: F401
|
| 10 |
+
from fsspec.tests.abstract.pipe import AbstractPipeTests # noqa: F401
|
| 11 |
+
from fsspec.tests.abstract.put import AbstractPutTests # noqa: F401
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class BaseAbstractFixtures:
|
| 15 |
+
"""
|
| 16 |
+
Abstract base class containing fixtures that are used by but never need to
|
| 17 |
+
be overridden in derived filesystem-specific classes to run the abstract
|
| 18 |
+
tests on such filesystems.
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
@pytest.fixture
|
| 22 |
+
def fs_bulk_operations_scenario_0(self, fs, fs_join, fs_path):
|
| 23 |
+
"""
|
| 24 |
+
Scenario on remote filesystem that is used for many cp/get/put tests.
|
| 25 |
+
|
| 26 |
+
Cleans up at the end of each test it which it is used.
|
| 27 |
+
"""
|
| 28 |
+
source = self._bulk_operations_scenario_0(fs, fs_join, fs_path)
|
| 29 |
+
yield source
|
| 30 |
+
fs.rm(source, recursive=True)
|
| 31 |
+
|
| 32 |
+
@pytest.fixture
|
| 33 |
+
def fs_glob_edge_cases_files(self, fs, fs_join, fs_path):
|
| 34 |
+
"""
|
| 35 |
+
Scenario on remote filesystem that is used for glob edge cases cp/get/put tests.
|
| 36 |
+
|
| 37 |
+
Cleans up at the end of each test it which it is used.
|
| 38 |
+
"""
|
| 39 |
+
source = self._glob_edge_cases_files(fs, fs_join, fs_path)
|
| 40 |
+
yield source
|
| 41 |
+
fs.rm(source, recursive=True)
|
| 42 |
+
|
| 43 |
+
@pytest.fixture
|
| 44 |
+
def fs_dir_and_file_with_same_name_prefix(self, fs, fs_join, fs_path):
|
| 45 |
+
"""
|
| 46 |
+
Scenario on remote filesystem that is used to check cp/get/put on directory
|
| 47 |
+
and file with the same name prefixes.
|
| 48 |
+
|
| 49 |
+
Cleans up at the end of each test it which it is used.
|
| 50 |
+
"""
|
| 51 |
+
source = self._dir_and_file_with_same_name_prefix(fs, fs_join, fs_path)
|
| 52 |
+
yield source
|
| 53 |
+
fs.rm(source, recursive=True)
|
| 54 |
+
|
| 55 |
+
@pytest.fixture
|
| 56 |
+
def fs_10_files_with_hashed_names(self, fs, fs_join, fs_path):
|
| 57 |
+
"""
|
| 58 |
+
Scenario on remote filesystem that is used to check cp/get/put files order
|
| 59 |
+
when source and destination are lists.
|
| 60 |
+
|
| 61 |
+
Cleans up at the end of each test it which it is used.
|
| 62 |
+
"""
|
| 63 |
+
source = self._10_files_with_hashed_names(fs, fs_join, fs_path)
|
| 64 |
+
yield source
|
| 65 |
+
fs.rm(source, recursive=True)
|
| 66 |
+
|
| 67 |
+
@pytest.fixture
|
| 68 |
+
def fs_target(self, fs, fs_join, fs_path):
|
| 69 |
+
"""
|
| 70 |
+
Return name of remote directory that does not yet exist to copy into.
|
| 71 |
+
|
| 72 |
+
Cleans up at the end of each test it which it is used.
|
| 73 |
+
"""
|
| 74 |
+
target = fs_join(fs_path, "target")
|
| 75 |
+
yield target
|
| 76 |
+
if fs.exists(target):
|
| 77 |
+
fs.rm(target, recursive=True)
|
| 78 |
+
|
| 79 |
+
@pytest.fixture
|
| 80 |
+
def local_bulk_operations_scenario_0(self, local_fs, local_join, local_path):
|
| 81 |
+
"""
|
| 82 |
+
Scenario on local filesystem that is used for many cp/get/put tests.
|
| 83 |
+
|
| 84 |
+
Cleans up at the end of each test it which it is used.
|
| 85 |
+
"""
|
| 86 |
+
source = self._bulk_operations_scenario_0(local_fs, local_join, local_path)
|
| 87 |
+
yield source
|
| 88 |
+
local_fs.rm(source, recursive=True)
|
| 89 |
+
|
| 90 |
+
@pytest.fixture
|
| 91 |
+
def local_glob_edge_cases_files(self, local_fs, local_join, local_path):
|
| 92 |
+
"""
|
| 93 |
+
Scenario on local filesystem that is used for glob edge cases cp/get/put tests.
|
| 94 |
+
|
| 95 |
+
Cleans up at the end of each test it which it is used.
|
| 96 |
+
"""
|
| 97 |
+
source = self._glob_edge_cases_files(local_fs, local_join, local_path)
|
| 98 |
+
yield source
|
| 99 |
+
local_fs.rm(source, recursive=True)
|
| 100 |
+
|
| 101 |
+
@pytest.fixture
|
| 102 |
+
def local_dir_and_file_with_same_name_prefix(
|
| 103 |
+
self, local_fs, local_join, local_path
|
| 104 |
+
):
|
| 105 |
+
"""
|
| 106 |
+
Scenario on local filesystem that is used to check cp/get/put on directory
|
| 107 |
+
and file with the same name prefixes.
|
| 108 |
+
|
| 109 |
+
Cleans up at the end of each test it which it is used.
|
| 110 |
+
"""
|
| 111 |
+
source = self._dir_and_file_with_same_name_prefix(
|
| 112 |
+
local_fs, local_join, local_path
|
| 113 |
+
)
|
| 114 |
+
yield source
|
| 115 |
+
local_fs.rm(source, recursive=True)
|
| 116 |
+
|
| 117 |
+
@pytest.fixture
|
| 118 |
+
def local_10_files_with_hashed_names(self, local_fs, local_join, local_path):
|
| 119 |
+
"""
|
| 120 |
+
Scenario on local filesystem that is used to check cp/get/put files order
|
| 121 |
+
when source and destination are lists.
|
| 122 |
+
|
| 123 |
+
Cleans up at the end of each test it which it is used.
|
| 124 |
+
"""
|
| 125 |
+
source = self._10_files_with_hashed_names(local_fs, local_join, local_path)
|
| 126 |
+
yield source
|
| 127 |
+
local_fs.rm(source, recursive=True)
|
| 128 |
+
|
| 129 |
+
@pytest.fixture
|
| 130 |
+
def local_target(self, local_fs, local_join, local_path):
|
| 131 |
+
"""
|
| 132 |
+
Return name of local directory that does not yet exist to copy into.
|
| 133 |
+
|
| 134 |
+
Cleans up at the end of each test it which it is used.
|
| 135 |
+
"""
|
| 136 |
+
target = local_join(local_path, "target")
|
| 137 |
+
yield target
|
| 138 |
+
if local_fs.exists(target):
|
| 139 |
+
local_fs.rm(target, recursive=True)
|
| 140 |
+
|
| 141 |
+
def _glob_edge_cases_files(self, some_fs, some_join, some_path):
|
| 142 |
+
"""
|
| 143 |
+
Scenario that is used for glob edge cases cp/get/put tests.
|
| 144 |
+
Creates the following directory and file structure:
|
| 145 |
+
|
| 146 |
+
📁 source
|
| 147 |
+
├── 📄 file1
|
| 148 |
+
├── 📄 file2
|
| 149 |
+
├── 📁 subdir0
|
| 150 |
+
│ ├── 📄 subfile1
|
| 151 |
+
│ ├── 📄 subfile2
|
| 152 |
+
│ └── 📁 nesteddir
|
| 153 |
+
│ └── 📄 nestedfile
|
| 154 |
+
└── 📁 subdir1
|
| 155 |
+
├── 📄 subfile1
|
| 156 |
+
├── 📄 subfile2
|
| 157 |
+
└── 📁 nesteddir
|
| 158 |
+
└── 📄 nestedfile
|
| 159 |
+
"""
|
| 160 |
+
source = some_join(some_path, "source")
|
| 161 |
+
some_fs.touch(some_join(source, "file1"))
|
| 162 |
+
some_fs.touch(some_join(source, "file2"))
|
| 163 |
+
|
| 164 |
+
for subdir_idx in range(2):
|
| 165 |
+
subdir = some_join(source, f"subdir{subdir_idx}")
|
| 166 |
+
nesteddir = some_join(subdir, "nesteddir")
|
| 167 |
+
some_fs.makedirs(nesteddir)
|
| 168 |
+
some_fs.touch(some_join(subdir, "subfile1"))
|
| 169 |
+
some_fs.touch(some_join(subdir, "subfile2"))
|
| 170 |
+
some_fs.touch(some_join(nesteddir, "nestedfile"))
|
| 171 |
+
|
| 172 |
+
return source
|
| 173 |
+
|
| 174 |
+
def _bulk_operations_scenario_0(self, some_fs, some_join, some_path):
|
| 175 |
+
"""
|
| 176 |
+
Scenario that is used for many cp/get/put tests. Creates the following
|
| 177 |
+
directory and file structure:
|
| 178 |
+
|
| 179 |
+
📁 source
|
| 180 |
+
├── 📄 file1
|
| 181 |
+
├── 📄 file2
|
| 182 |
+
└── 📁 subdir
|
| 183 |
+
├── 📄 subfile1
|
| 184 |
+
├── 📄 subfile2
|
| 185 |
+
└── 📁 nesteddir
|
| 186 |
+
└── 📄 nestedfile
|
| 187 |
+
"""
|
| 188 |
+
source = some_join(some_path, "source")
|
| 189 |
+
subdir = some_join(source, "subdir")
|
| 190 |
+
nesteddir = some_join(subdir, "nesteddir")
|
| 191 |
+
some_fs.makedirs(nesteddir)
|
| 192 |
+
some_fs.touch(some_join(source, "file1"))
|
| 193 |
+
some_fs.touch(some_join(source, "file2"))
|
| 194 |
+
some_fs.touch(some_join(subdir, "subfile1"))
|
| 195 |
+
some_fs.touch(some_join(subdir, "subfile2"))
|
| 196 |
+
some_fs.touch(some_join(nesteddir, "nestedfile"))
|
| 197 |
+
return source
|
| 198 |
+
|
| 199 |
+
def _dir_and_file_with_same_name_prefix(self, some_fs, some_join, some_path):
|
| 200 |
+
"""
|
| 201 |
+
Scenario that is used to check cp/get/put on directory and file with
|
| 202 |
+
the same name prefixes. Creates the following directory and file structure:
|
| 203 |
+
|
| 204 |
+
📁 source
|
| 205 |
+
├── 📄 subdir.txt
|
| 206 |
+
└── 📁 subdir
|
| 207 |
+
└── 📄 subfile.txt
|
| 208 |
+
"""
|
| 209 |
+
source = some_join(some_path, "source")
|
| 210 |
+
subdir = some_join(source, "subdir")
|
| 211 |
+
file = some_join(source, "subdir.txt")
|
| 212 |
+
subfile = some_join(subdir, "subfile.txt")
|
| 213 |
+
some_fs.makedirs(subdir)
|
| 214 |
+
some_fs.touch(file)
|
| 215 |
+
some_fs.touch(subfile)
|
| 216 |
+
return source
|
| 217 |
+
|
| 218 |
+
def _10_files_with_hashed_names(self, some_fs, some_join, some_path):
|
| 219 |
+
"""
|
| 220 |
+
Scenario that is used to check cp/get/put files order when source and
|
| 221 |
+
destination are lists. Creates the following directory and file structure:
|
| 222 |
+
|
| 223 |
+
📁 source
|
| 224 |
+
└── 📄 {hashed([0-9])}.txt
|
| 225 |
+
"""
|
| 226 |
+
source = some_join(some_path, "source")
|
| 227 |
+
for i in range(10):
|
| 228 |
+
hashed_i = md5(str(i).encode("utf-8")).hexdigest()
|
| 229 |
+
path = some_join(source, f"{hashed_i}.txt")
|
| 230 |
+
some_fs.pipe(path=path, value=f"{i}".encode())
|
| 231 |
+
return source
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
class AbstractFixtures(BaseAbstractFixtures):
|
| 235 |
+
"""
|
| 236 |
+
Abstract base class containing fixtures that may be overridden in derived
|
| 237 |
+
filesystem-specific classes to run the abstract tests on such filesystems.
|
| 238 |
+
|
| 239 |
+
For any particular filesystem some of these fixtures must be overridden,
|
| 240 |
+
such as ``fs`` and ``fs_path``, and others may be overridden if the
|
| 241 |
+
default functions here are not appropriate, such as ``fs_join``.
|
| 242 |
+
"""
|
| 243 |
+
|
| 244 |
+
@pytest.fixture
|
| 245 |
+
def fs(self):
|
| 246 |
+
raise NotImplementedError("This function must be overridden in derived classes")
|
| 247 |
+
|
| 248 |
+
@pytest.fixture
|
| 249 |
+
def fs_join(self):
|
| 250 |
+
"""
|
| 251 |
+
Return a function that joins its arguments together into a path.
|
| 252 |
+
|
| 253 |
+
Most fsspec implementations join paths in a platform-dependent way,
|
| 254 |
+
but some will override this to always use a forward slash.
|
| 255 |
+
"""
|
| 256 |
+
return os.path.join
|
| 257 |
+
|
| 258 |
+
@pytest.fixture
|
| 259 |
+
def fs_path(self):
|
| 260 |
+
raise NotImplementedError("This function must be overridden in derived classes")
|
| 261 |
+
|
| 262 |
+
@pytest.fixture(scope="class")
|
| 263 |
+
def local_fs(self):
|
| 264 |
+
# Maybe need an option for auto_mkdir=False? This is only relevant
|
| 265 |
+
# for certain implementations.
|
| 266 |
+
return LocalFileSystem(auto_mkdir=True)
|
| 267 |
+
|
| 268 |
+
@pytest.fixture
|
| 269 |
+
def local_join(self):
|
| 270 |
+
"""
|
| 271 |
+
Return a function that joins its arguments together into a path, on
|
| 272 |
+
the local filesystem.
|
| 273 |
+
"""
|
| 274 |
+
return os.path.join
|
| 275 |
+
|
| 276 |
+
@pytest.fixture
|
| 277 |
+
def local_path(self, tmpdir):
|
| 278 |
+
return tmpdir
|
| 279 |
+
|
| 280 |
+
@pytest.fixture
|
| 281 |
+
def supports_empty_directories(self):
|
| 282 |
+
"""
|
| 283 |
+
Return whether this implementation supports empty directories.
|
| 284 |
+
"""
|
| 285 |
+
return True
|
| 286 |
+
|
| 287 |
+
@pytest.fixture
|
| 288 |
+
def fs_sanitize_path(self):
|
| 289 |
+
return lambda x: x
|
.venv/lib/python3.11/site-packages/fsspec/tests/abstract/__pycache__/get.cpython-311.pyc
ADDED
|
Binary file (26.3 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/fsspec/tests/abstract/__pycache__/pipe.cpython-311.pyc
ADDED
|
Binary file (1.32 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/fsspec/tests/abstract/__pycache__/put.cpython-311.pyc
ADDED
|
Binary file (27.8 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/fsspec/tests/abstract/open.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class AbstractOpenTests:
|
| 5 |
+
def test_open_exclusive(self, fs, fs_target):
|
| 6 |
+
with fs.open(fs_target, "wb") as f:
|
| 7 |
+
f.write(b"data")
|
| 8 |
+
with fs.open(fs_target, "rb") as f:
|
| 9 |
+
assert f.read() == b"data"
|
| 10 |
+
with pytest.raises(FileExistsError):
|
| 11 |
+
fs.open(fs_target, "xb")
|
.venv/lib/python3.11/site-packages/functorch/_C.cpython-311-x86_64-linux-gnu.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:39dc1f80069251db7f97e91763cbde3e2a9b53d8db73007ad0ddf7b041fee1d5
|
| 3 |
+
size 324432
|
.venv/lib/python3.11/site-packages/zmq/__init__.pxd
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
from zmq.backend.cython cimport Context, Frame, Socket, libzmq
|
.venv/lib/python3.11/site-packages/zmq/__init__.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Python bindings for 0MQ"""
|
| 2 |
+
|
| 3 |
+
# Copyright (C) PyZMQ Developers
|
| 4 |
+
# Distributed under the terms of the Modified BSD License.
|
| 5 |
+
|
| 6 |
+
from __future__ import annotations
|
| 7 |
+
|
| 8 |
+
import os
|
| 9 |
+
import sys
|
| 10 |
+
from contextlib import contextmanager
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
@contextmanager
|
| 14 |
+
def _libs_on_path():
|
| 15 |
+
"""context manager for libs directory on $PATH
|
| 16 |
+
|
| 17 |
+
Works around mysterious issue where os.add_dll_directory
|
| 18 |
+
does not resolve imports (conda-forge Python >= 3.8)
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
if not sys.platform.startswith("win"):
|
| 22 |
+
yield
|
| 23 |
+
return
|
| 24 |
+
|
| 25 |
+
libs_dir = os.path.abspath(
|
| 26 |
+
os.path.join(
|
| 27 |
+
os.path.dirname(__file__),
|
| 28 |
+
os.pardir,
|
| 29 |
+
"pyzmq.libs",
|
| 30 |
+
)
|
| 31 |
+
)
|
| 32 |
+
if not os.path.exists(libs_dir):
|
| 33 |
+
# no bundled libs
|
| 34 |
+
yield
|
| 35 |
+
return
|
| 36 |
+
|
| 37 |
+
path_before = os.environ.get("PATH")
|
| 38 |
+
try:
|
| 39 |
+
os.environ["PATH"] = os.pathsep.join([path_before or "", libs_dir])
|
| 40 |
+
yield
|
| 41 |
+
finally:
|
| 42 |
+
if path_before is None:
|
| 43 |
+
os.environ.pop("PATH")
|
| 44 |
+
else:
|
| 45 |
+
os.environ["PATH"] = path_before
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
# zmq top-level imports
|
| 49 |
+
|
| 50 |
+
# workaround for Windows
|
| 51 |
+
with _libs_on_path():
|
| 52 |
+
from zmq import backend
|
| 53 |
+
|
| 54 |
+
from . import constants # noqa
|
| 55 |
+
from .constants import * # noqa
|
| 56 |
+
from zmq.backend import * # noqa
|
| 57 |
+
from zmq import sugar
|
| 58 |
+
from zmq.sugar import * # noqa
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def get_includes():
|
| 62 |
+
"""Return a list of directories to include for linking against pyzmq with cython."""
|
| 63 |
+
from os.path import abspath, dirname, exists, join, pardir
|
| 64 |
+
|
| 65 |
+
base = dirname(__file__)
|
| 66 |
+
parent = abspath(join(base, pardir))
|
| 67 |
+
includes = [parent] + [join(parent, base, subdir) for subdir in ('utils',)]
|
| 68 |
+
if exists(join(parent, base, 'include')):
|
| 69 |
+
includes.append(join(parent, base, 'include'))
|
| 70 |
+
return includes
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def get_library_dirs():
|
| 74 |
+
"""Return a list of directories used to link against pyzmq's bundled libzmq."""
|
| 75 |
+
from os.path import abspath, dirname, join, pardir
|
| 76 |
+
|
| 77 |
+
base = dirname(__file__)
|
| 78 |
+
parent = abspath(join(base, pardir))
|
| 79 |
+
return [join(parent, base)]
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
COPY_THRESHOLD = 65536
|
| 83 |
+
DRAFT_API = backend.has("draft")
|
| 84 |
+
|
| 85 |
+
__all__ = (
|
| 86 |
+
[
|
| 87 |
+
'get_includes',
|
| 88 |
+
'COPY_THRESHOLD',
|
| 89 |
+
'DRAFT_API',
|
| 90 |
+
]
|
| 91 |
+
+ constants.__all__
|
| 92 |
+
+ sugar.__all__
|
| 93 |
+
+ backend.__all__
|
| 94 |
+
)
|
.venv/lib/python3.11/site-packages/zmq/__init__.pyi
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List
|
| 2 |
+
|
| 3 |
+
from . import backend, sugar
|
| 4 |
+
|
| 5 |
+
COPY_THRESHOLD: int
|
| 6 |
+
DRAFT_API: bool
|
| 7 |
+
__version__: str
|
| 8 |
+
|
| 9 |
+
# mypy doesn't like overwriting symbols with * so be explicit
|
| 10 |
+
# about what comes from backend, not from sugar
|
| 11 |
+
# see tools/backend_imports.py to generate this list
|
| 12 |
+
# note: `x as x` is required for re-export
|
| 13 |
+
# see https://github.com/python/mypy/issues/2190
|
| 14 |
+
from .backend import IPC_PATH_MAX_LEN as IPC_PATH_MAX_LEN
|
| 15 |
+
from .backend import curve_keypair as curve_keypair
|
| 16 |
+
from .backend import curve_public as curve_public
|
| 17 |
+
from .backend import device as device
|
| 18 |
+
from .backend import has as has
|
| 19 |
+
from .backend import proxy as proxy
|
| 20 |
+
from .backend import proxy_steerable as proxy_steerable
|
| 21 |
+
from .backend import strerror as strerror
|
| 22 |
+
from .backend import zmq_errno as zmq_errno
|
| 23 |
+
from .backend import zmq_poll as zmq_poll
|
| 24 |
+
from .constants import *
|
| 25 |
+
from .error import *
|
| 26 |
+
from .sugar import *
|
| 27 |
+
|
| 28 |
+
def get_includes() -> list[str]: ...
|
| 29 |
+
def get_library_dirs() -> list[str]: ...
|
.venv/lib/python3.11/site-packages/zmq/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (4.12 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/__pycache__/_future.cpython-311.pyc
ADDED
|
Binary file (32.2 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/__pycache__/_typing.cpython-311.pyc
ADDED
|
Binary file (1.47 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/__pycache__/asyncio.cpython-311.pyc
ADDED
|
Binary file (10.2 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/__pycache__/constants.cpython-311.pyc
ADDED
|
Binary file (30.8 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/__pycache__/decorators.cpython-311.pyc
ADDED
|
Binary file (7.61 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/__pycache__/error.cpython-311.pyc
ADDED
|
Binary file (8.9 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/_future.pyi
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""type annotations for async sockets"""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
from asyncio import Future
|
| 6 |
+
from pickle import DEFAULT_PROTOCOL
|
| 7 |
+
from typing import Any, Awaitable, Literal, Sequence, TypeVar, overload
|
| 8 |
+
|
| 9 |
+
import zmq as _zmq
|
| 10 |
+
|
| 11 |
+
class _AsyncPoller(_zmq.Poller):
|
| 12 |
+
_socket_class: type[_AsyncSocket]
|
| 13 |
+
|
| 14 |
+
def poll(self, timeout=-1) -> Awaitable[list[tuple[Any, int]]]: ... # type: ignore
|
| 15 |
+
|
| 16 |
+
T = TypeVar("T", bound="_AsyncSocket")
|
| 17 |
+
|
| 18 |
+
class _AsyncSocket(_zmq.Socket[Future]):
|
| 19 |
+
@classmethod
|
| 20 |
+
def from_socket(cls: type[T], socket: _zmq.Socket, io_loop: Any = None) -> T: ...
|
| 21 |
+
def send( # type: ignore
|
| 22 |
+
self,
|
| 23 |
+
data: Any,
|
| 24 |
+
flags: int = 0,
|
| 25 |
+
copy: bool = True,
|
| 26 |
+
track: bool = False,
|
| 27 |
+
routing_id: int | None = None,
|
| 28 |
+
group: str | None = None,
|
| 29 |
+
) -> Awaitable[_zmq.MessageTracker | None]: ...
|
| 30 |
+
@overload # type: ignore
|
| 31 |
+
def recv(self, flags: int = 0, *, track: bool = False) -> Awaitable[bytes]: ...
|
| 32 |
+
@overload
|
| 33 |
+
def recv(
|
| 34 |
+
self, flags: int = 0, *, copy: Literal[True], track: bool = False
|
| 35 |
+
) -> Awaitable[bytes]: ...
|
| 36 |
+
@overload
|
| 37 |
+
def recv(
|
| 38 |
+
self, flags: int = 0, *, copy: Literal[False], track: bool = False
|
| 39 |
+
) -> Awaitable[_zmq.Frame]: ...
|
| 40 |
+
@overload
|
| 41 |
+
def recv(
|
| 42 |
+
self, flags: int = 0, copy: bool = True, track: bool = False
|
| 43 |
+
) -> Awaitable[bytes | _zmq.Frame]: ...
|
| 44 |
+
def send_multipart( # type: ignore
|
| 45 |
+
self,
|
| 46 |
+
msg_parts: Sequence,
|
| 47 |
+
flags: int = 0,
|
| 48 |
+
copy: bool = True,
|
| 49 |
+
track: bool = False,
|
| 50 |
+
routing_id: int | None = None,
|
| 51 |
+
group: str | None = None,
|
| 52 |
+
) -> Awaitable[_zmq.MessageTracker | None]: ...
|
| 53 |
+
@overload # type: ignore
|
| 54 |
+
def recv_multipart(
|
| 55 |
+
self, flags: int = 0, *, track: bool = False
|
| 56 |
+
) -> Awaitable[list[bytes]]: ...
|
| 57 |
+
@overload
|
| 58 |
+
def recv_multipart(
|
| 59 |
+
self, flags: int = 0, *, copy: Literal[True], track: bool = False
|
| 60 |
+
) -> Awaitable[list[bytes]]: ...
|
| 61 |
+
@overload
|
| 62 |
+
def recv_multipart(
|
| 63 |
+
self, flags: int = 0, *, copy: Literal[False], track: bool = False
|
| 64 |
+
) -> Awaitable[list[_zmq.Frame]]: ...
|
| 65 |
+
@overload
|
| 66 |
+
def recv_multipart(
|
| 67 |
+
self, flags: int = 0, copy: bool = True, track: bool = False
|
| 68 |
+
) -> Awaitable[list[bytes] | list[_zmq.Frame]]: ...
|
| 69 |
+
|
| 70 |
+
# serialization wrappers
|
| 71 |
+
|
| 72 |
+
def send_string( # type: ignore
|
| 73 |
+
self,
|
| 74 |
+
u: str,
|
| 75 |
+
flags: int = 0,
|
| 76 |
+
copy: bool = True,
|
| 77 |
+
*,
|
| 78 |
+
encoding: str = 'utf-8',
|
| 79 |
+
**kwargs,
|
| 80 |
+
) -> Awaitable[_zmq.Frame | None]: ...
|
| 81 |
+
def recv_string( # type: ignore
|
| 82 |
+
self, flags: int = 0, encoding: str = 'utf-8'
|
| 83 |
+
) -> Awaitable[str]: ...
|
| 84 |
+
def send_pyobj( # type: ignore
|
| 85 |
+
self, obj: Any, flags: int = 0, protocol: int = DEFAULT_PROTOCOL, **kwargs
|
| 86 |
+
) -> Awaitable[_zmq.Frame | None]: ...
|
| 87 |
+
def recv_pyobj(self, flags: int = 0) -> Awaitable[Any]: ... # type: ignore
|
| 88 |
+
def send_json( # type: ignore
|
| 89 |
+
self, obj: Any, flags: int = 0, **kwargs
|
| 90 |
+
) -> Awaitable[_zmq.Frame | None]: ...
|
| 91 |
+
def recv_json(self, flags: int = 0, **kwargs) -> Awaitable[Any]: ... # type: ignore
|
| 92 |
+
def poll(self, timeout=-1) -> Awaitable[list[tuple[Any, int]]]: ... # type: ignore
|
.venv/lib/python3.11/site-packages/zmq/_typing.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import sys
|
| 4 |
+
from typing import Any, Dict
|
| 5 |
+
|
| 6 |
+
if sys.version_info >= (3, 8):
|
| 7 |
+
from typing import Literal, TypedDict
|
| 8 |
+
else:
|
| 9 |
+
# avoid runtime dependency on typing_extensions on py37
|
| 10 |
+
try:
|
| 11 |
+
from typing_extensions import Literal, TypedDict # type: ignore
|
| 12 |
+
except ImportError:
|
| 13 |
+
|
| 14 |
+
class _Literal:
|
| 15 |
+
def __getitem__(self, key):
|
| 16 |
+
return Any
|
| 17 |
+
|
| 18 |
+
Literal = _Literal() # type: ignore
|
| 19 |
+
|
| 20 |
+
class TypedDict(Dict): # type: ignore
|
| 21 |
+
pass
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
if sys.version_info >= (3, 10):
|
| 25 |
+
from typing import TypeAlias
|
| 26 |
+
else:
|
| 27 |
+
try:
|
| 28 |
+
from typing_extensions import TypeAlias
|
| 29 |
+
except ImportError:
|
| 30 |
+
TypeAlias = type # type: ignore
|
.venv/lib/python3.11/site-packages/zmq/auth/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Utilities for ZAP authentication.
|
| 2 |
+
|
| 3 |
+
To run authentication in a background thread, see :mod:`zmq.auth.thread`.
|
| 4 |
+
For integration with the asyncio event loop, see :mod:`zmq.auth.asyncio`.
|
| 5 |
+
|
| 6 |
+
Authentication examples are provided in the pyzmq codebase, under
|
| 7 |
+
`/examples/security/`.
|
| 8 |
+
|
| 9 |
+
.. versionadded:: 14.1
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
from .base import *
|
| 13 |
+
from .certs import *
|
.venv/lib/python3.11/site-packages/zmq/auth/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (564 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/auth/__pycache__/asyncio.cpython-311.pyc
ADDED
|
Binary file (3.68 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/auth/__pycache__/base.cpython-311.pyc
ADDED
|
Binary file (19.1 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/auth/__pycache__/certs.cpython-311.pyc
ADDED
|
Binary file (6.82 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/auth/__pycache__/ioloop.cpython-311.pyc
ADDED
|
Binary file (2.05 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/auth/__pycache__/thread.cpython-311.pyc
ADDED
|
Binary file (8.01 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/auth/asyncio.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""ZAP Authenticator integrated with the asyncio IO loop.
|
| 2 |
+
|
| 3 |
+
.. versionadded:: 15.2
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
# Copyright (C) PyZMQ Developers
|
| 7 |
+
# Distributed under the terms of the Modified BSD License.
|
| 8 |
+
|
| 9 |
+
import asyncio
|
| 10 |
+
import warnings
|
| 11 |
+
from typing import Any, Optional
|
| 12 |
+
|
| 13 |
+
import zmq
|
| 14 |
+
from zmq.asyncio import Poller
|
| 15 |
+
|
| 16 |
+
from .base import Authenticator
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class AsyncioAuthenticator(Authenticator):
|
| 20 |
+
"""ZAP authentication for use in the asyncio IO loop"""
|
| 21 |
+
|
| 22 |
+
__poller: Optional[Poller]
|
| 23 |
+
__task: Any
|
| 24 |
+
|
| 25 |
+
def __init__(
|
| 26 |
+
self,
|
| 27 |
+
context: Optional["zmq.Context"] = None,
|
| 28 |
+
loop: Any = None,
|
| 29 |
+
encoding: str = 'utf-8',
|
| 30 |
+
log: Any = None,
|
| 31 |
+
):
|
| 32 |
+
super().__init__(context, encoding, log)
|
| 33 |
+
if loop is not None:
|
| 34 |
+
warnings.warn(
|
| 35 |
+
f"{self.__class__.__name__}(loop) is deprecated and ignored",
|
| 36 |
+
DeprecationWarning,
|
| 37 |
+
stacklevel=2,
|
| 38 |
+
)
|
| 39 |
+
self.__poller = None
|
| 40 |
+
self.__task = None
|
| 41 |
+
|
| 42 |
+
async def __handle_zap(self) -> None:
|
| 43 |
+
while self.__poller is not None:
|
| 44 |
+
events = await self.__poller.poll()
|
| 45 |
+
if self.zap_socket in dict(events):
|
| 46 |
+
msg = self.zap_socket.recv_multipart()
|
| 47 |
+
await self.handle_zap_message(msg)
|
| 48 |
+
|
| 49 |
+
def start(self) -> None:
|
| 50 |
+
"""Start ZAP authentication"""
|
| 51 |
+
super().start()
|
| 52 |
+
self.__poller = Poller()
|
| 53 |
+
self.__poller.register(self.zap_socket, zmq.POLLIN)
|
| 54 |
+
self.__task = asyncio.ensure_future(self.__handle_zap())
|
| 55 |
+
|
| 56 |
+
def stop(self) -> None:
|
| 57 |
+
"""Stop ZAP authentication"""
|
| 58 |
+
if self.__task:
|
| 59 |
+
self.__task.cancel()
|
| 60 |
+
if self.__poller:
|
| 61 |
+
self.__poller.unregister(self.zap_socket)
|
| 62 |
+
self.__poller = None
|
| 63 |
+
super().stop()
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
__all__ = ["AsyncioAuthenticator"]
|
.venv/lib/python3.11/site-packages/zmq/auth/base.py
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Base implementation of 0MQ authentication."""
|
| 2 |
+
|
| 3 |
+
# Copyright (C) PyZMQ Developers
|
| 4 |
+
# Distributed under the terms of the Modified BSD License.
|
| 5 |
+
|
| 6 |
+
import logging
|
| 7 |
+
import os
|
| 8 |
+
from typing import Any, Awaitable, Dict, List, Optional, Set, Tuple, Union
|
| 9 |
+
|
| 10 |
+
import zmq
|
| 11 |
+
from zmq.error import _check_version
|
| 12 |
+
from zmq.utils import z85
|
| 13 |
+
|
| 14 |
+
from .certs import load_certificates
|
| 15 |
+
|
| 16 |
+
CURVE_ALLOW_ANY = '*'
|
| 17 |
+
VERSION = b'1.0'
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class Authenticator:
|
| 21 |
+
"""Implementation of ZAP authentication for zmq connections.
|
| 22 |
+
|
| 23 |
+
This authenticator class does not register with an event loop. As a result,
|
| 24 |
+
you will need to manually call `handle_zap_message`::
|
| 25 |
+
|
| 26 |
+
auth = zmq.Authenticator()
|
| 27 |
+
auth.allow("127.0.0.1")
|
| 28 |
+
auth.start()
|
| 29 |
+
while True:
|
| 30 |
+
await auth.handle_zap_msg(auth.zap_socket.recv_multipart())
|
| 31 |
+
|
| 32 |
+
Alternatively, you can register `auth.zap_socket` with a poller.
|
| 33 |
+
|
| 34 |
+
Since many users will want to run ZAP in a way that does not block the
|
| 35 |
+
main thread, other authentication classes (such as :mod:`zmq.auth.thread`)
|
| 36 |
+
are provided.
|
| 37 |
+
|
| 38 |
+
Note:
|
| 39 |
+
|
| 40 |
+
- libzmq provides four levels of security: default NULL (which the Authenticator does
|
| 41 |
+
not see), and authenticated NULL, PLAIN, CURVE, and GSSAPI, which the Authenticator can see.
|
| 42 |
+
- until you add policies, all incoming NULL connections are allowed.
|
| 43 |
+
(classic ZeroMQ behavior), and all PLAIN and CURVE connections are denied.
|
| 44 |
+
- GSSAPI requires no configuration.
|
| 45 |
+
"""
|
| 46 |
+
|
| 47 |
+
context: "zmq.Context"
|
| 48 |
+
encoding: str
|
| 49 |
+
allow_any: bool
|
| 50 |
+
credentials_providers: Dict[str, Any]
|
| 51 |
+
zap_socket: "zmq.Socket"
|
| 52 |
+
_allowed: Set[str]
|
| 53 |
+
_denied: Set[str]
|
| 54 |
+
passwords: Dict[str, Dict[str, str]]
|
| 55 |
+
certs: Dict[str, Dict[bytes, Any]]
|
| 56 |
+
log: Any
|
| 57 |
+
|
| 58 |
+
def __init__(
|
| 59 |
+
self,
|
| 60 |
+
context: Optional["zmq.Context"] = None,
|
| 61 |
+
encoding: str = 'utf-8',
|
| 62 |
+
log: Any = None,
|
| 63 |
+
):
|
| 64 |
+
_check_version((4, 0), "security")
|
| 65 |
+
self.context = context or zmq.Context.instance()
|
| 66 |
+
self.encoding = encoding
|
| 67 |
+
self.allow_any = False
|
| 68 |
+
self.credentials_providers = {}
|
| 69 |
+
self.zap_socket = None # type: ignore
|
| 70 |
+
self._allowed = set()
|
| 71 |
+
self._denied = set()
|
| 72 |
+
# passwords is a dict keyed by domain and contains values
|
| 73 |
+
# of dicts with username:password pairs.
|
| 74 |
+
self.passwords = {}
|
| 75 |
+
# certs is dict keyed by domain and contains values
|
| 76 |
+
# of dicts keyed by the public keys from the specified location.
|
| 77 |
+
self.certs = {}
|
| 78 |
+
self.log = log or logging.getLogger('zmq.auth')
|
| 79 |
+
|
| 80 |
+
def start(self) -> None:
|
| 81 |
+
"""Create and bind the ZAP socket"""
|
| 82 |
+
self.zap_socket = self.context.socket(zmq.REP, socket_class=zmq.Socket)
|
| 83 |
+
self.zap_socket.linger = 1
|
| 84 |
+
self.zap_socket.bind("inproc://zeromq.zap.01")
|
| 85 |
+
self.log.debug("Starting")
|
| 86 |
+
|
| 87 |
+
def stop(self) -> None:
|
| 88 |
+
"""Close the ZAP socket"""
|
| 89 |
+
if self.zap_socket:
|
| 90 |
+
self.zap_socket.close()
|
| 91 |
+
self.zap_socket = None # type: ignore
|
| 92 |
+
|
| 93 |
+
def allow(self, *addresses: str) -> None:
|
| 94 |
+
"""Allow IP address(es).
|
| 95 |
+
|
| 96 |
+
Connections from addresses not explicitly allowed will be rejected.
|
| 97 |
+
|
| 98 |
+
- For NULL, all clients from this address will be accepted.
|
| 99 |
+
- For real auth setups, they will be allowed to continue with authentication.
|
| 100 |
+
|
| 101 |
+
allow is mutually exclusive with deny.
|
| 102 |
+
"""
|
| 103 |
+
if self._denied:
|
| 104 |
+
raise ValueError("Only use allow or deny, not both")
|
| 105 |
+
self.log.debug("Allowing %s", ','.join(addresses))
|
| 106 |
+
self._allowed.update(addresses)
|
| 107 |
+
|
| 108 |
+
def deny(self, *addresses: str) -> None:
|
| 109 |
+
"""Deny IP address(es).
|
| 110 |
+
|
| 111 |
+
Addresses not explicitly denied will be allowed to continue with authentication.
|
| 112 |
+
|
| 113 |
+
deny is mutually exclusive with allow.
|
| 114 |
+
"""
|
| 115 |
+
if self._allowed:
|
| 116 |
+
raise ValueError("Only use a allow or deny, not both")
|
| 117 |
+
self.log.debug("Denying %s", ','.join(addresses))
|
| 118 |
+
self._denied.update(addresses)
|
| 119 |
+
|
| 120 |
+
def configure_plain(
|
| 121 |
+
self, domain: str = '*', passwords: Optional[Dict[str, str]] = None
|
| 122 |
+
) -> None:
|
| 123 |
+
"""Configure PLAIN authentication for a given domain.
|
| 124 |
+
|
| 125 |
+
PLAIN authentication uses a plain-text password file.
|
| 126 |
+
To cover all domains, use "*".
|
| 127 |
+
You can modify the password file at any time; it is reloaded automatically.
|
| 128 |
+
"""
|
| 129 |
+
if passwords:
|
| 130 |
+
self.passwords[domain] = passwords
|
| 131 |
+
self.log.debug("Configure plain: %s", domain)
|
| 132 |
+
|
| 133 |
+
def configure_curve(
|
| 134 |
+
self, domain: str = '*', location: Union[str, os.PathLike] = "."
|
| 135 |
+
) -> None:
|
| 136 |
+
"""Configure CURVE authentication for a given domain.
|
| 137 |
+
|
| 138 |
+
CURVE authentication uses a directory that holds all public client certificates,
|
| 139 |
+
i.e. their public keys.
|
| 140 |
+
|
| 141 |
+
To cover all domains, use "*".
|
| 142 |
+
|
| 143 |
+
You can add and remove certificates in that directory at any time. configure_curve must be called
|
| 144 |
+
every time certificates are added or removed, in order to update the Authenticator's state
|
| 145 |
+
|
| 146 |
+
To allow all client keys without checking, specify CURVE_ALLOW_ANY for the location.
|
| 147 |
+
"""
|
| 148 |
+
# If location is CURVE_ALLOW_ANY then allow all clients. Otherwise
|
| 149 |
+
# treat location as a directory that holds the certificates.
|
| 150 |
+
self.log.debug("Configure curve: %s[%s]", domain, location)
|
| 151 |
+
if location == CURVE_ALLOW_ANY:
|
| 152 |
+
self.allow_any = True
|
| 153 |
+
else:
|
| 154 |
+
self.allow_any = False
|
| 155 |
+
try:
|
| 156 |
+
self.certs[domain] = load_certificates(location)
|
| 157 |
+
except Exception as e:
|
| 158 |
+
self.log.error("Failed to load CURVE certs from %s: %s", location, e)
|
| 159 |
+
|
| 160 |
+
def configure_curve_callback(
|
| 161 |
+
self, domain: str = '*', credentials_provider: Any = None
|
| 162 |
+
) -> None:
|
| 163 |
+
"""Configure CURVE authentication for a given domain.
|
| 164 |
+
|
| 165 |
+
CURVE authentication using a callback function validating
|
| 166 |
+
the client public key according to a custom mechanism, e.g. checking the
|
| 167 |
+
key against records in a db. credentials_provider is an object of a class which
|
| 168 |
+
implements a callback method accepting two parameters (domain and key), e.g.::
|
| 169 |
+
|
| 170 |
+
class CredentialsProvider(object):
|
| 171 |
+
|
| 172 |
+
def __init__(self):
|
| 173 |
+
...e.g. db connection
|
| 174 |
+
|
| 175 |
+
def callback(self, domain, key):
|
| 176 |
+
valid = ...lookup key and/or domain in db
|
| 177 |
+
if valid:
|
| 178 |
+
logging.info('Authorizing: {0}, {1}'.format(domain, key))
|
| 179 |
+
return True
|
| 180 |
+
else:
|
| 181 |
+
logging.warning('NOT Authorizing: {0}, {1}'.format(domain, key))
|
| 182 |
+
return False
|
| 183 |
+
|
| 184 |
+
To cover all domains, use "*".
|
| 185 |
+
"""
|
| 186 |
+
|
| 187 |
+
self.allow_any = False
|
| 188 |
+
|
| 189 |
+
if credentials_provider is not None:
|
| 190 |
+
self.credentials_providers[domain] = credentials_provider
|
| 191 |
+
else:
|
| 192 |
+
self.log.error("None credentials_provider provided for domain:%s", domain)
|
| 193 |
+
|
| 194 |
+
def curve_user_id(self, client_public_key: bytes) -> str:
|
| 195 |
+
"""Return the User-Id corresponding to a CURVE client's public key
|
| 196 |
+
|
| 197 |
+
Default implementation uses the z85-encoding of the public key.
|
| 198 |
+
|
| 199 |
+
Override to define a custom mapping of public key : user-id
|
| 200 |
+
|
| 201 |
+
This is only called on successful authentication.
|
| 202 |
+
|
| 203 |
+
Parameters
|
| 204 |
+
----------
|
| 205 |
+
client_public_key: bytes
|
| 206 |
+
The client public key used for the given message
|
| 207 |
+
|
| 208 |
+
Returns
|
| 209 |
+
-------
|
| 210 |
+
user_id: unicode
|
| 211 |
+
The user ID as text
|
| 212 |
+
"""
|
| 213 |
+
return z85.encode(client_public_key).decode('ascii')
|
| 214 |
+
|
| 215 |
+
def configure_gssapi(
|
| 216 |
+
self, domain: str = '*', location: Optional[str] = None
|
| 217 |
+
) -> None:
|
| 218 |
+
"""Configure GSSAPI authentication
|
| 219 |
+
|
| 220 |
+
Currently this is a no-op because there is nothing to configure with GSSAPI.
|
| 221 |
+
"""
|
| 222 |
+
|
| 223 |
+
async def handle_zap_message(self, msg: List[bytes]):
|
| 224 |
+
"""Perform ZAP authentication"""
|
| 225 |
+
if len(msg) < 6:
|
| 226 |
+
self.log.error("Invalid ZAP message, not enough frames: %r", msg)
|
| 227 |
+
if len(msg) < 2:
|
| 228 |
+
self.log.error("Not enough information to reply")
|
| 229 |
+
else:
|
| 230 |
+
self._send_zap_reply(msg[1], b"400", b"Not enough frames")
|
| 231 |
+
return
|
| 232 |
+
|
| 233 |
+
version, request_id, domain, address, identity, mechanism = msg[:6]
|
| 234 |
+
credentials = msg[6:]
|
| 235 |
+
|
| 236 |
+
domain = domain.decode(self.encoding, 'replace')
|
| 237 |
+
address = address.decode(self.encoding, 'replace')
|
| 238 |
+
|
| 239 |
+
if version != VERSION:
|
| 240 |
+
self.log.error("Invalid ZAP version: %r", msg)
|
| 241 |
+
self._send_zap_reply(request_id, b"400", b"Invalid version")
|
| 242 |
+
return
|
| 243 |
+
|
| 244 |
+
self.log.debug(
|
| 245 |
+
"version: %r, request_id: %r, domain: %r,"
|
| 246 |
+
" address: %r, identity: %r, mechanism: %r",
|
| 247 |
+
version,
|
| 248 |
+
request_id,
|
| 249 |
+
domain,
|
| 250 |
+
address,
|
| 251 |
+
identity,
|
| 252 |
+
mechanism,
|
| 253 |
+
)
|
| 254 |
+
|
| 255 |
+
# Is address is explicitly allowed or _denied?
|
| 256 |
+
allowed = False
|
| 257 |
+
denied = False
|
| 258 |
+
reason = b"NO ACCESS"
|
| 259 |
+
|
| 260 |
+
if self._allowed:
|
| 261 |
+
if address in self._allowed:
|
| 262 |
+
allowed = True
|
| 263 |
+
self.log.debug("PASSED (allowed) address=%s", address)
|
| 264 |
+
else:
|
| 265 |
+
denied = True
|
| 266 |
+
reason = b"Address not allowed"
|
| 267 |
+
self.log.debug("DENIED (not allowed) address=%s", address)
|
| 268 |
+
|
| 269 |
+
elif self._denied:
|
| 270 |
+
if address in self._denied:
|
| 271 |
+
denied = True
|
| 272 |
+
reason = b"Address denied"
|
| 273 |
+
self.log.debug("DENIED (denied) address=%s", address)
|
| 274 |
+
else:
|
| 275 |
+
allowed = True
|
| 276 |
+
self.log.debug("PASSED (not denied) address=%s", address)
|
| 277 |
+
|
| 278 |
+
# Perform authentication mechanism-specific checks if necessary
|
| 279 |
+
username = "anonymous"
|
| 280 |
+
if not denied:
|
| 281 |
+
if mechanism == b'NULL' and not allowed:
|
| 282 |
+
# For NULL, we allow if the address wasn't denied
|
| 283 |
+
self.log.debug("ALLOWED (NULL)")
|
| 284 |
+
allowed = True
|
| 285 |
+
|
| 286 |
+
elif mechanism == b'PLAIN':
|
| 287 |
+
# For PLAIN, even a _alloweded address must authenticate
|
| 288 |
+
if len(credentials) != 2:
|
| 289 |
+
self.log.error("Invalid PLAIN credentials: %r", credentials)
|
| 290 |
+
self._send_zap_reply(request_id, b"400", b"Invalid credentials")
|
| 291 |
+
return
|
| 292 |
+
username, password = (
|
| 293 |
+
c.decode(self.encoding, 'replace') for c in credentials
|
| 294 |
+
)
|
| 295 |
+
allowed, reason = self._authenticate_plain(domain, username, password)
|
| 296 |
+
|
| 297 |
+
elif mechanism == b'CURVE':
|
| 298 |
+
# For CURVE, even a _alloweded address must authenticate
|
| 299 |
+
if len(credentials) != 1:
|
| 300 |
+
self.log.error("Invalid CURVE credentials: %r", credentials)
|
| 301 |
+
self._send_zap_reply(request_id, b"400", b"Invalid credentials")
|
| 302 |
+
return
|
| 303 |
+
key = credentials[0]
|
| 304 |
+
allowed, reason = await self._authenticate_curve(domain, key)
|
| 305 |
+
if allowed:
|
| 306 |
+
username = self.curve_user_id(key)
|
| 307 |
+
|
| 308 |
+
elif mechanism == b'GSSAPI':
|
| 309 |
+
if len(credentials) != 1:
|
| 310 |
+
self.log.error("Invalid GSSAPI credentials: %r", credentials)
|
| 311 |
+
self._send_zap_reply(request_id, b"400", b"Invalid credentials")
|
| 312 |
+
return
|
| 313 |
+
# use principal as user-id for now
|
| 314 |
+
principal = credentials[0]
|
| 315 |
+
username = principal.decode("utf8")
|
| 316 |
+
allowed, reason = self._authenticate_gssapi(domain, principal)
|
| 317 |
+
|
| 318 |
+
if allowed:
|
| 319 |
+
self._send_zap_reply(request_id, b"200", b"OK", username)
|
| 320 |
+
else:
|
| 321 |
+
self._send_zap_reply(request_id, b"400", reason)
|
| 322 |
+
|
| 323 |
+
def _authenticate_plain(
|
| 324 |
+
self, domain: str, username: str, password: str
|
| 325 |
+
) -> Tuple[bool, bytes]:
|
| 326 |
+
"""PLAIN ZAP authentication"""
|
| 327 |
+
allowed = False
|
| 328 |
+
reason = b""
|
| 329 |
+
if self.passwords:
|
| 330 |
+
# If no domain is not specified then use the default domain
|
| 331 |
+
if not domain:
|
| 332 |
+
domain = '*'
|
| 333 |
+
|
| 334 |
+
if domain in self.passwords:
|
| 335 |
+
if username in self.passwords[domain]:
|
| 336 |
+
if password == self.passwords[domain][username]:
|
| 337 |
+
allowed = True
|
| 338 |
+
else:
|
| 339 |
+
reason = b"Invalid password"
|
| 340 |
+
else:
|
| 341 |
+
reason = b"Invalid username"
|
| 342 |
+
else:
|
| 343 |
+
reason = b"Invalid domain"
|
| 344 |
+
|
| 345 |
+
if allowed:
|
| 346 |
+
self.log.debug(
|
| 347 |
+
"ALLOWED (PLAIN) domain=%s username=%s password=%s",
|
| 348 |
+
domain,
|
| 349 |
+
username,
|
| 350 |
+
password,
|
| 351 |
+
)
|
| 352 |
+
else:
|
| 353 |
+
self.log.debug("DENIED %s", reason)
|
| 354 |
+
|
| 355 |
+
else:
|
| 356 |
+
reason = b"No passwords defined"
|
| 357 |
+
self.log.debug("DENIED (PLAIN) %s", reason)
|
| 358 |
+
|
| 359 |
+
return allowed, reason
|
| 360 |
+
|
| 361 |
+
async def _authenticate_curve(
|
| 362 |
+
self, domain: str, client_key: bytes
|
| 363 |
+
) -> Tuple[bool, bytes]:
|
| 364 |
+
"""CURVE ZAP authentication"""
|
| 365 |
+
allowed = False
|
| 366 |
+
reason = b""
|
| 367 |
+
if self.allow_any:
|
| 368 |
+
allowed = True
|
| 369 |
+
reason = b"OK"
|
| 370 |
+
self.log.debug("ALLOWED (CURVE allow any client)")
|
| 371 |
+
elif self.credentials_providers != {}:
|
| 372 |
+
# If no explicit domain is specified then use the default domain
|
| 373 |
+
if not domain:
|
| 374 |
+
domain = '*'
|
| 375 |
+
|
| 376 |
+
if domain in self.credentials_providers:
|
| 377 |
+
z85_client_key = z85.encode(client_key)
|
| 378 |
+
# Callback to check if key is Allowed
|
| 379 |
+
r = self.credentials_providers[domain].callback(domain, z85_client_key)
|
| 380 |
+
if isinstance(r, Awaitable):
|
| 381 |
+
r = await r
|
| 382 |
+
if r:
|
| 383 |
+
allowed = True
|
| 384 |
+
reason = b"OK"
|
| 385 |
+
else:
|
| 386 |
+
reason = b"Unknown key"
|
| 387 |
+
|
| 388 |
+
status = "ALLOWED" if allowed else "DENIED"
|
| 389 |
+
self.log.debug(
|
| 390 |
+
"%s (CURVE auth_callback) domain=%s client_key=%s",
|
| 391 |
+
status,
|
| 392 |
+
domain,
|
| 393 |
+
z85_client_key,
|
| 394 |
+
)
|
| 395 |
+
else:
|
| 396 |
+
reason = b"Unknown domain"
|
| 397 |
+
else:
|
| 398 |
+
# If no explicit domain is specified then use the default domain
|
| 399 |
+
if not domain:
|
| 400 |
+
domain = '*'
|
| 401 |
+
|
| 402 |
+
if domain in self.certs:
|
| 403 |
+
# The certs dict stores keys in z85 format, convert binary key to z85 bytes
|
| 404 |
+
z85_client_key = z85.encode(client_key)
|
| 405 |
+
if self.certs[domain].get(z85_client_key):
|
| 406 |
+
allowed = True
|
| 407 |
+
reason = b"OK"
|
| 408 |
+
else:
|
| 409 |
+
reason = b"Unknown key"
|
| 410 |
+
|
| 411 |
+
status = "ALLOWED" if allowed else "DENIED"
|
| 412 |
+
self.log.debug(
|
| 413 |
+
"%s (CURVE) domain=%s client_key=%s",
|
| 414 |
+
status,
|
| 415 |
+
domain,
|
| 416 |
+
z85_client_key,
|
| 417 |
+
)
|
| 418 |
+
else:
|
| 419 |
+
reason = b"Unknown domain"
|
| 420 |
+
|
| 421 |
+
return allowed, reason
|
| 422 |
+
|
| 423 |
+
def _authenticate_gssapi(self, domain: str, principal: bytes) -> Tuple[bool, bytes]:
|
| 424 |
+
"""Nothing to do for GSSAPI, which has already been handled by an external service."""
|
| 425 |
+
self.log.debug("ALLOWED (GSSAPI) domain=%s principal=%s", domain, principal)
|
| 426 |
+
return True, b'OK'
|
| 427 |
+
|
| 428 |
+
def _send_zap_reply(
|
| 429 |
+
self,
|
| 430 |
+
request_id: bytes,
|
| 431 |
+
status_code: bytes,
|
| 432 |
+
status_text: bytes,
|
| 433 |
+
user_id: str = 'anonymous',
|
| 434 |
+
) -> None:
|
| 435 |
+
"""Send a ZAP reply to finish the authentication."""
|
| 436 |
+
user_id = user_id if status_code == b'200' else b''
|
| 437 |
+
if isinstance(user_id, str):
|
| 438 |
+
user_id = user_id.encode(self.encoding, 'replace')
|
| 439 |
+
metadata = b'' # not currently used
|
| 440 |
+
self.log.debug("ZAP reply code=%s text=%s", status_code, status_text)
|
| 441 |
+
reply = [VERSION, request_id, status_code, status_text, user_id, metadata]
|
| 442 |
+
self.zap_socket.send_multipart(reply)
|
| 443 |
+
|
| 444 |
+
|
| 445 |
+
__all__ = ['Authenticator', 'CURVE_ALLOW_ANY']
|
.venv/lib/python3.11/site-packages/zmq/auth/certs.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""0MQ authentication related functions and classes."""
|
| 2 |
+
|
| 3 |
+
# Copyright (C) PyZMQ Developers
|
| 4 |
+
# Distributed under the terms of the Modified BSD License.
|
| 5 |
+
|
| 6 |
+
import datetime
|
| 7 |
+
import glob
|
| 8 |
+
import os
|
| 9 |
+
from typing import Dict, Optional, Tuple, Union
|
| 10 |
+
|
| 11 |
+
import zmq
|
| 12 |
+
|
| 13 |
+
_cert_secret_banner = """# **** Generated on {0} by pyzmq ****
|
| 14 |
+
# ZeroMQ CURVE **Secret** Certificate
|
| 15 |
+
# DO NOT PROVIDE THIS FILE TO OTHER USERS nor change its permissions.
|
| 16 |
+
|
| 17 |
+
"""
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
_cert_public_banner = """# **** Generated on {0} by pyzmq ****
|
| 21 |
+
# ZeroMQ CURVE Public Certificate
|
| 22 |
+
# Exchange securely, or use a secure mechanism to verify the contents
|
| 23 |
+
# of this file after exchange. Store public certificates in your home
|
| 24 |
+
# directory, in the .curve subdirectory.
|
| 25 |
+
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _write_key_file(
|
| 30 |
+
key_filename: Union[str, os.PathLike],
|
| 31 |
+
banner: str,
|
| 32 |
+
public_key: Union[str, bytes],
|
| 33 |
+
secret_key: Optional[Union[str, bytes]] = None,
|
| 34 |
+
metadata: Optional[Dict[str, str]] = None,
|
| 35 |
+
encoding: str = 'utf-8',
|
| 36 |
+
) -> None:
|
| 37 |
+
"""Create a certificate file"""
|
| 38 |
+
if isinstance(public_key, bytes):
|
| 39 |
+
public_key = public_key.decode(encoding)
|
| 40 |
+
if isinstance(secret_key, bytes):
|
| 41 |
+
secret_key = secret_key.decode(encoding)
|
| 42 |
+
with open(key_filename, 'w', encoding='utf8') as f:
|
| 43 |
+
f.write(banner.format(datetime.datetime.now()))
|
| 44 |
+
|
| 45 |
+
f.write('metadata\n')
|
| 46 |
+
if metadata:
|
| 47 |
+
for k, v in metadata.items():
|
| 48 |
+
if isinstance(k, bytes):
|
| 49 |
+
k = k.decode(encoding)
|
| 50 |
+
if isinstance(v, bytes):
|
| 51 |
+
v = v.decode(encoding)
|
| 52 |
+
f.write(f" {k} = {v}\n")
|
| 53 |
+
|
| 54 |
+
f.write('curve\n')
|
| 55 |
+
f.write(f" public-key = \"{public_key}\"\n")
|
| 56 |
+
|
| 57 |
+
if secret_key:
|
| 58 |
+
f.write(f" secret-key = \"{secret_key}\"\n")
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def create_certificates(
|
| 62 |
+
key_dir: Union[str, os.PathLike],
|
| 63 |
+
name: str,
|
| 64 |
+
metadata: Optional[Dict[str, str]] = None,
|
| 65 |
+
) -> Tuple[str, str]:
|
| 66 |
+
"""Create zmq certificates.
|
| 67 |
+
|
| 68 |
+
Returns the file paths to the public and secret certificate files.
|
| 69 |
+
"""
|
| 70 |
+
public_key, secret_key = zmq.curve_keypair()
|
| 71 |
+
base_filename = os.path.join(key_dir, name)
|
| 72 |
+
secret_key_file = f"{base_filename}.key_secret"
|
| 73 |
+
public_key_file = f"{base_filename}.key"
|
| 74 |
+
now = datetime.datetime.now()
|
| 75 |
+
|
| 76 |
+
_write_key_file(public_key_file, _cert_public_banner.format(now), public_key)
|
| 77 |
+
|
| 78 |
+
_write_key_file(
|
| 79 |
+
secret_key_file,
|
| 80 |
+
_cert_secret_banner.format(now),
|
| 81 |
+
public_key,
|
| 82 |
+
secret_key=secret_key,
|
| 83 |
+
metadata=metadata,
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
return public_key_file, secret_key_file
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def load_certificate(
|
| 90 |
+
filename: Union[str, os.PathLike],
|
| 91 |
+
) -> Tuple[bytes, Optional[bytes]]:
|
| 92 |
+
"""Load public and secret key from a zmq certificate.
|
| 93 |
+
|
| 94 |
+
Returns (public_key, secret_key)
|
| 95 |
+
|
| 96 |
+
If the certificate file only contains the public key,
|
| 97 |
+
secret_key will be None.
|
| 98 |
+
|
| 99 |
+
If there is no public key found in the file, ValueError will be raised.
|
| 100 |
+
"""
|
| 101 |
+
public_key = None
|
| 102 |
+
secret_key = None
|
| 103 |
+
if not os.path.exists(filename):
|
| 104 |
+
raise OSError(f"Invalid certificate file: {filename}")
|
| 105 |
+
|
| 106 |
+
with open(filename, 'rb') as f:
|
| 107 |
+
for line in f:
|
| 108 |
+
line = line.strip()
|
| 109 |
+
if line.startswith(b'#'):
|
| 110 |
+
continue
|
| 111 |
+
if line.startswith(b'public-key'):
|
| 112 |
+
public_key = line.split(b"=", 1)[1].strip(b' \t\'"')
|
| 113 |
+
if line.startswith(b'secret-key'):
|
| 114 |
+
secret_key = line.split(b"=", 1)[1].strip(b' \t\'"')
|
| 115 |
+
if public_key and secret_key:
|
| 116 |
+
break
|
| 117 |
+
|
| 118 |
+
if public_key is None:
|
| 119 |
+
raise ValueError(f"No public key found in {filename}")
|
| 120 |
+
|
| 121 |
+
return public_key, secret_key
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def load_certificates(directory: Union[str, os.PathLike] = '.') -> Dict[bytes, bool]:
|
| 125 |
+
"""Load public keys from all certificates in a directory"""
|
| 126 |
+
certs = {}
|
| 127 |
+
if not os.path.isdir(directory):
|
| 128 |
+
raise OSError(f"Invalid certificate directory: {directory}")
|
| 129 |
+
# Follow czmq pattern of public keys stored in *.key files.
|
| 130 |
+
glob_string = os.path.join(directory, "*.key")
|
| 131 |
+
|
| 132 |
+
cert_files = glob.glob(glob_string)
|
| 133 |
+
for cert_file in cert_files:
|
| 134 |
+
public_key, _ = load_certificate(cert_file)
|
| 135 |
+
if public_key:
|
| 136 |
+
certs[public_key] = True
|
| 137 |
+
return certs
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
__all__ = ['create_certificates', 'load_certificate', 'load_certificates']
|
.venv/lib/python3.11/site-packages/zmq/auth/ioloop.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""ZAP Authenticator integrated with the tornado IOLoop.
|
| 2 |
+
|
| 3 |
+
.. versionadded:: 14.1
|
| 4 |
+
.. deprecated:: 25
|
| 5 |
+
Use asyncio.AsyncioAuthenticator instead.
|
| 6 |
+
Since tornado runs on asyncio, the asyncio authenticator
|
| 7 |
+
offers the same functionality in tornado.
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
import warnings
|
| 11 |
+
|
| 12 |
+
# Copyright (C) PyZMQ Developers
|
| 13 |
+
# Distributed under the terms of the Modified BSD License.
|
| 14 |
+
from typing import Any, Optional
|
| 15 |
+
|
| 16 |
+
import zmq
|
| 17 |
+
|
| 18 |
+
from .asyncio import AsyncioAuthenticator
|
| 19 |
+
|
| 20 |
+
warnings.warn(
|
| 21 |
+
"zmq.auth.ioloop.IOLoopAuthenticator is deprecated. Use zmq.auth.asyncio.AsyncioAuthenticator",
|
| 22 |
+
DeprecationWarning,
|
| 23 |
+
stacklevel=2,
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
class IOLoopAuthenticator(AsyncioAuthenticator):
|
| 28 |
+
"""ZAP authentication for use in the tornado IOLoop"""
|
| 29 |
+
|
| 30 |
+
def __init__(
|
| 31 |
+
self,
|
| 32 |
+
context: Optional["zmq.Context"] = None,
|
| 33 |
+
encoding: str = 'utf-8',
|
| 34 |
+
log: Any = None,
|
| 35 |
+
io_loop: Any = None,
|
| 36 |
+
):
|
| 37 |
+
loop = None
|
| 38 |
+
if io_loop is not None:
|
| 39 |
+
warnings.warn(
|
| 40 |
+
f"{self.__class__.__name__}(io_loop) is deprecated and ignored",
|
| 41 |
+
DeprecationWarning,
|
| 42 |
+
stacklevel=2,
|
| 43 |
+
)
|
| 44 |
+
loop = io_loop.asyncio_loop
|
| 45 |
+
super().__init__(context=context, encoding=encoding, log=log, loop=loop)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
__all__ = ['IOLoopAuthenticator']
|
.venv/lib/python3.11/site-packages/zmq/auth/thread.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""ZAP Authenticator in a Python Thread.
|
| 2 |
+
|
| 3 |
+
.. versionadded:: 14.1
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
# Copyright (C) PyZMQ Developers
|
| 7 |
+
# Distributed under the terms of the Modified BSD License.
|
| 8 |
+
|
| 9 |
+
import asyncio
|
| 10 |
+
from threading import Event, Thread
|
| 11 |
+
from typing import Any, List, Optional
|
| 12 |
+
|
| 13 |
+
import zmq
|
| 14 |
+
import zmq.asyncio
|
| 15 |
+
|
| 16 |
+
from .base import Authenticator
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class AuthenticationThread(Thread):
|
| 20 |
+
"""A Thread for running a zmq Authenticator
|
| 21 |
+
|
| 22 |
+
This is run in the background by ThreadAuthenticator
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
pipe: zmq.Socket
|
| 26 |
+
loop: asyncio.AbstractEventLoop
|
| 27 |
+
authenticator: Authenticator
|
| 28 |
+
poller: Optional[zmq.asyncio.Poller] = None
|
| 29 |
+
|
| 30 |
+
def __init__(
|
| 31 |
+
self,
|
| 32 |
+
authenticator: Authenticator,
|
| 33 |
+
pipe: zmq.Socket,
|
| 34 |
+
) -> None:
|
| 35 |
+
super().__init__(daemon=True)
|
| 36 |
+
self.authenticator = authenticator
|
| 37 |
+
self.log = authenticator.log
|
| 38 |
+
self.pipe = pipe
|
| 39 |
+
|
| 40 |
+
self.started = Event()
|
| 41 |
+
|
| 42 |
+
def run(self) -> None:
|
| 43 |
+
"""Start the Authentication Agent thread task"""
|
| 44 |
+
|
| 45 |
+
loop = asyncio.new_event_loop()
|
| 46 |
+
try:
|
| 47 |
+
loop.run_until_complete(self._run())
|
| 48 |
+
finally:
|
| 49 |
+
if self.pipe:
|
| 50 |
+
self.pipe.close()
|
| 51 |
+
self.pipe = None # type: ignore
|
| 52 |
+
|
| 53 |
+
loop.close()
|
| 54 |
+
|
| 55 |
+
async def _run(self):
|
| 56 |
+
self.poller = zmq.asyncio.Poller()
|
| 57 |
+
self.poller.register(self.pipe, zmq.POLLIN)
|
| 58 |
+
self.poller.register(self.authenticator.zap_socket, zmq.POLLIN)
|
| 59 |
+
self.started.set()
|
| 60 |
+
|
| 61 |
+
while True:
|
| 62 |
+
events = dict(await self.poller.poll())
|
| 63 |
+
if self.pipe in events:
|
| 64 |
+
msg = self.pipe.recv_multipart()
|
| 65 |
+
if self._handle_pipe_message(msg):
|
| 66 |
+
return
|
| 67 |
+
if self.authenticator.zap_socket in events:
|
| 68 |
+
msg = self.authenticator.zap_socket.recv_multipart()
|
| 69 |
+
await self.authenticator.handle_zap_message(msg)
|
| 70 |
+
|
| 71 |
+
def _handle_pipe_message(self, msg: List[bytes]) -> bool:
|
| 72 |
+
command = msg[0]
|
| 73 |
+
self.log.debug("auth received API command %r", command)
|
| 74 |
+
|
| 75 |
+
if command == b'TERMINATE':
|
| 76 |
+
return True
|
| 77 |
+
|
| 78 |
+
else:
|
| 79 |
+
self.log.error("Invalid auth command from API: %r", command)
|
| 80 |
+
self.pipe.send(b'ERROR')
|
| 81 |
+
|
| 82 |
+
return False
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
class ThreadAuthenticator(Authenticator):
|
| 86 |
+
"""Run ZAP authentication in a background thread"""
|
| 87 |
+
|
| 88 |
+
pipe: "zmq.Socket"
|
| 89 |
+
pipe_endpoint: str = ''
|
| 90 |
+
thread: AuthenticationThread
|
| 91 |
+
|
| 92 |
+
def __init__(
|
| 93 |
+
self,
|
| 94 |
+
context: Optional["zmq.Context"] = None,
|
| 95 |
+
encoding: str = 'utf-8',
|
| 96 |
+
log: Any = None,
|
| 97 |
+
):
|
| 98 |
+
super().__init__(context=context, encoding=encoding, log=log)
|
| 99 |
+
self.pipe = None # type: ignore
|
| 100 |
+
self.pipe_endpoint = f"inproc://{id(self)}.inproc"
|
| 101 |
+
self.thread = None # type: ignore
|
| 102 |
+
|
| 103 |
+
def start(self) -> None:
|
| 104 |
+
"""Start the authentication thread"""
|
| 105 |
+
# start the Authenticator
|
| 106 |
+
super().start()
|
| 107 |
+
|
| 108 |
+
# create a socket pair to communicate with auth thread.
|
| 109 |
+
self.pipe = self.context.socket(zmq.PAIR, socket_class=zmq.Socket)
|
| 110 |
+
self.pipe.linger = 1
|
| 111 |
+
self.pipe.bind(self.pipe_endpoint)
|
| 112 |
+
thread_pipe = self.context.socket(zmq.PAIR, socket_class=zmq.Socket)
|
| 113 |
+
thread_pipe.linger = 1
|
| 114 |
+
thread_pipe.connect(self.pipe_endpoint)
|
| 115 |
+
self.thread = AuthenticationThread(authenticator=self, pipe=thread_pipe)
|
| 116 |
+
self.thread.start()
|
| 117 |
+
if not self.thread.started.wait(timeout=10):
|
| 118 |
+
raise RuntimeError("Authenticator thread failed to start")
|
| 119 |
+
|
| 120 |
+
def stop(self) -> None:
|
| 121 |
+
"""Stop the authentication thread"""
|
| 122 |
+
if self.pipe:
|
| 123 |
+
self.pipe.send(b'TERMINATE')
|
| 124 |
+
if self.is_alive():
|
| 125 |
+
self.thread.join()
|
| 126 |
+
self.thread = None # type: ignore
|
| 127 |
+
self.pipe.close()
|
| 128 |
+
self.pipe = None # type: ignore
|
| 129 |
+
super().stop()
|
| 130 |
+
|
| 131 |
+
def is_alive(self) -> bool:
|
| 132 |
+
"""Is the ZAP thread currently running?"""
|
| 133 |
+
return bool(self.thread and self.thread.is_alive())
|
| 134 |
+
|
| 135 |
+
def __del__(self) -> None:
|
| 136 |
+
self.stop()
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
__all__ = ['ThreadAuthenticator']
|
.venv/lib/python3.11/site-packages/zmq/constants.py
ADDED
|
@@ -0,0 +1,974 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""zmq constants as enums"""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import errno
|
| 6 |
+
import sys
|
| 7 |
+
from enum import Enum, IntEnum, IntFlag
|
| 8 |
+
|
| 9 |
+
_HAUSNUMERO = 156384712
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class Errno(IntEnum):
|
| 13 |
+
"""libzmq error codes
|
| 14 |
+
|
| 15 |
+
.. versionadded:: 23
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
EAGAIN = errno.EAGAIN
|
| 19 |
+
EFAULT = errno.EFAULT
|
| 20 |
+
EINVAL = errno.EINVAL
|
| 21 |
+
|
| 22 |
+
if sys.platform.startswith("win"):
|
| 23 |
+
# Windows: libzmq uses errno.h
|
| 24 |
+
# while Python errno prefers WSA* variants
|
| 25 |
+
# many of these were introduced to errno.h in vs2010
|
| 26 |
+
# ref: https://github.com/python/cpython/blob/3.9/Modules/errnomodule.c#L10-L37
|
| 27 |
+
# source: https://docs.microsoft.com/en-us/cpp/c-runtime-library/errno-constants
|
| 28 |
+
ENOTSUP = 129
|
| 29 |
+
EPROTONOSUPPORT = 135
|
| 30 |
+
ENOBUFS = 119
|
| 31 |
+
ENETDOWN = 116
|
| 32 |
+
EADDRINUSE = 100
|
| 33 |
+
EADDRNOTAVAIL = 101
|
| 34 |
+
ECONNREFUSED = 107
|
| 35 |
+
EINPROGRESS = 112
|
| 36 |
+
ENOTSOCK = 128
|
| 37 |
+
EMSGSIZE = 115
|
| 38 |
+
EAFNOSUPPORT = 102
|
| 39 |
+
ENETUNREACH = 118
|
| 40 |
+
ECONNABORTED = 106
|
| 41 |
+
ECONNRESET = 108
|
| 42 |
+
ENOTCONN = 126
|
| 43 |
+
ETIMEDOUT = 138
|
| 44 |
+
EHOSTUNREACH = 110
|
| 45 |
+
ENETRESET = 117
|
| 46 |
+
|
| 47 |
+
else:
|
| 48 |
+
ENOTSUP = getattr(errno, "ENOTSUP", _HAUSNUMERO + 1)
|
| 49 |
+
EPROTONOSUPPORT = getattr(errno, "EPROTONOSUPPORT", _HAUSNUMERO + 2)
|
| 50 |
+
ENOBUFS = getattr(errno, "ENOBUFS", _HAUSNUMERO + 3)
|
| 51 |
+
ENETDOWN = getattr(errno, "ENETDOWN", _HAUSNUMERO + 4)
|
| 52 |
+
EADDRINUSE = getattr(errno, "EADDRINUSE", _HAUSNUMERO + 5)
|
| 53 |
+
EADDRNOTAVAIL = getattr(errno, "EADDRNOTAVAIL", _HAUSNUMERO + 6)
|
| 54 |
+
ECONNREFUSED = getattr(errno, "ECONNREFUSED", _HAUSNUMERO + 7)
|
| 55 |
+
EINPROGRESS = getattr(errno, "EINPROGRESS", _HAUSNUMERO + 8)
|
| 56 |
+
ENOTSOCK = getattr(errno, "ENOTSOCK", _HAUSNUMERO + 9)
|
| 57 |
+
EMSGSIZE = getattr(errno, "EMSGSIZE", _HAUSNUMERO + 10)
|
| 58 |
+
EAFNOSUPPORT = getattr(errno, "EAFNOSUPPORT", _HAUSNUMERO + 11)
|
| 59 |
+
ENETUNREACH = getattr(errno, "ENETUNREACH", _HAUSNUMERO + 12)
|
| 60 |
+
ECONNABORTED = getattr(errno, "ECONNABORTED", _HAUSNUMERO + 13)
|
| 61 |
+
ECONNRESET = getattr(errno, "ECONNRESET", _HAUSNUMERO + 14)
|
| 62 |
+
ENOTCONN = getattr(errno, "ENOTCONN", _HAUSNUMERO + 15)
|
| 63 |
+
ETIMEDOUT = getattr(errno, "ETIMEDOUT", _HAUSNUMERO + 16)
|
| 64 |
+
EHOSTUNREACH = getattr(errno, "EHOSTUNREACH", _HAUSNUMERO + 17)
|
| 65 |
+
ENETRESET = getattr(errno, "ENETRESET", _HAUSNUMERO + 18)
|
| 66 |
+
|
| 67 |
+
# Native 0MQ error codes
|
| 68 |
+
EFSM = _HAUSNUMERO + 51
|
| 69 |
+
ENOCOMPATPROTO = _HAUSNUMERO + 52
|
| 70 |
+
ETERM = _HAUSNUMERO + 53
|
| 71 |
+
EMTHREAD = _HAUSNUMERO + 54
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
class ContextOption(IntEnum):
|
| 75 |
+
"""Options for Context.get/set
|
| 76 |
+
|
| 77 |
+
.. versionadded:: 23
|
| 78 |
+
"""
|
| 79 |
+
|
| 80 |
+
IO_THREADS = 1
|
| 81 |
+
MAX_SOCKETS = 2
|
| 82 |
+
SOCKET_LIMIT = 3
|
| 83 |
+
THREAD_PRIORITY = 3
|
| 84 |
+
THREAD_SCHED_POLICY = 4
|
| 85 |
+
MAX_MSGSZ = 5
|
| 86 |
+
MSG_T_SIZE = 6
|
| 87 |
+
THREAD_AFFINITY_CPU_ADD = 7
|
| 88 |
+
THREAD_AFFINITY_CPU_REMOVE = 8
|
| 89 |
+
THREAD_NAME_PREFIX = 9
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
class SocketType(IntEnum):
|
| 93 |
+
"""zmq socket types
|
| 94 |
+
|
| 95 |
+
.. versionadded:: 23
|
| 96 |
+
"""
|
| 97 |
+
|
| 98 |
+
PAIR = 0
|
| 99 |
+
PUB = 1
|
| 100 |
+
SUB = 2
|
| 101 |
+
REQ = 3
|
| 102 |
+
REP = 4
|
| 103 |
+
DEALER = 5
|
| 104 |
+
ROUTER = 6
|
| 105 |
+
PULL = 7
|
| 106 |
+
PUSH = 8
|
| 107 |
+
XPUB = 9
|
| 108 |
+
XSUB = 10
|
| 109 |
+
STREAM = 11
|
| 110 |
+
|
| 111 |
+
# deprecated aliases
|
| 112 |
+
XREQ = DEALER
|
| 113 |
+
XREP = ROUTER
|
| 114 |
+
|
| 115 |
+
# DRAFT socket types
|
| 116 |
+
SERVER = 12
|
| 117 |
+
CLIENT = 13
|
| 118 |
+
RADIO = 14
|
| 119 |
+
DISH = 15
|
| 120 |
+
GATHER = 16
|
| 121 |
+
SCATTER = 17
|
| 122 |
+
DGRAM = 18
|
| 123 |
+
PEER = 19
|
| 124 |
+
CHANNEL = 20
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
class _OptType(Enum):
|
| 128 |
+
int = 'int'
|
| 129 |
+
int64 = 'int64'
|
| 130 |
+
bytes = 'bytes'
|
| 131 |
+
fd = 'fd'
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
class SocketOption(IntEnum):
|
| 135 |
+
"""Options for Socket.get/set
|
| 136 |
+
|
| 137 |
+
.. versionadded:: 23
|
| 138 |
+
"""
|
| 139 |
+
|
| 140 |
+
_opt_type: _OptType
|
| 141 |
+
|
| 142 |
+
def __new__(cls, value: int, opt_type: _OptType = _OptType.int):
|
| 143 |
+
"""Attach option type as `._opt_type`"""
|
| 144 |
+
obj = int.__new__(cls, value)
|
| 145 |
+
obj._value_ = value
|
| 146 |
+
obj._opt_type = opt_type
|
| 147 |
+
return obj
|
| 148 |
+
|
| 149 |
+
HWM = 1
|
| 150 |
+
AFFINITY = 4, _OptType.int64
|
| 151 |
+
ROUTING_ID = 5, _OptType.bytes
|
| 152 |
+
SUBSCRIBE = 6, _OptType.bytes
|
| 153 |
+
UNSUBSCRIBE = 7, _OptType.bytes
|
| 154 |
+
RATE = 8
|
| 155 |
+
RECOVERY_IVL = 9
|
| 156 |
+
SNDBUF = 11
|
| 157 |
+
RCVBUF = 12
|
| 158 |
+
RCVMORE = 13
|
| 159 |
+
FD = 14, _OptType.fd
|
| 160 |
+
EVENTS = 15
|
| 161 |
+
TYPE = 16
|
| 162 |
+
LINGER = 17
|
| 163 |
+
RECONNECT_IVL = 18
|
| 164 |
+
BACKLOG = 19
|
| 165 |
+
RECONNECT_IVL_MAX = 21
|
| 166 |
+
MAXMSGSIZE = 22, _OptType.int64
|
| 167 |
+
SNDHWM = 23
|
| 168 |
+
RCVHWM = 24
|
| 169 |
+
MULTICAST_HOPS = 25
|
| 170 |
+
RCVTIMEO = 27
|
| 171 |
+
SNDTIMEO = 28
|
| 172 |
+
LAST_ENDPOINT = 32, _OptType.bytes
|
| 173 |
+
ROUTER_MANDATORY = 33
|
| 174 |
+
TCP_KEEPALIVE = 34
|
| 175 |
+
TCP_KEEPALIVE_CNT = 35
|
| 176 |
+
TCP_KEEPALIVE_IDLE = 36
|
| 177 |
+
TCP_KEEPALIVE_INTVL = 37
|
| 178 |
+
IMMEDIATE = 39
|
| 179 |
+
XPUB_VERBOSE = 40
|
| 180 |
+
ROUTER_RAW = 41
|
| 181 |
+
IPV6 = 42
|
| 182 |
+
MECHANISM = 43
|
| 183 |
+
PLAIN_SERVER = 44
|
| 184 |
+
PLAIN_USERNAME = 45, _OptType.bytes
|
| 185 |
+
PLAIN_PASSWORD = 46, _OptType.bytes
|
| 186 |
+
CURVE_SERVER = 47
|
| 187 |
+
CURVE_PUBLICKEY = 48, _OptType.bytes
|
| 188 |
+
CURVE_SECRETKEY = 49, _OptType.bytes
|
| 189 |
+
CURVE_SERVERKEY = 50, _OptType.bytes
|
| 190 |
+
PROBE_ROUTER = 51
|
| 191 |
+
REQ_CORRELATE = 52
|
| 192 |
+
REQ_RELAXED = 53
|
| 193 |
+
CONFLATE = 54
|
| 194 |
+
ZAP_DOMAIN = 55, _OptType.bytes
|
| 195 |
+
ROUTER_HANDOVER = 56
|
| 196 |
+
TOS = 57
|
| 197 |
+
CONNECT_ROUTING_ID = 61, _OptType.bytes
|
| 198 |
+
GSSAPI_SERVER = 62
|
| 199 |
+
GSSAPI_PRINCIPAL = 63, _OptType.bytes
|
| 200 |
+
GSSAPI_SERVICE_PRINCIPAL = 64, _OptType.bytes
|
| 201 |
+
GSSAPI_PLAINTEXT = 65
|
| 202 |
+
HANDSHAKE_IVL = 66
|
| 203 |
+
SOCKS_PROXY = 68, _OptType.bytes
|
| 204 |
+
XPUB_NODROP = 69
|
| 205 |
+
BLOCKY = 70
|
| 206 |
+
XPUB_MANUAL = 71
|
| 207 |
+
XPUB_WELCOME_MSG = 72, _OptType.bytes
|
| 208 |
+
STREAM_NOTIFY = 73
|
| 209 |
+
INVERT_MATCHING = 74
|
| 210 |
+
HEARTBEAT_IVL = 75
|
| 211 |
+
HEARTBEAT_TTL = 76
|
| 212 |
+
HEARTBEAT_TIMEOUT = 77
|
| 213 |
+
XPUB_VERBOSER = 78
|
| 214 |
+
CONNECT_TIMEOUT = 79
|
| 215 |
+
TCP_MAXRT = 80
|
| 216 |
+
THREAD_SAFE = 81
|
| 217 |
+
MULTICAST_MAXTPDU = 84
|
| 218 |
+
VMCI_BUFFER_SIZE = 85, _OptType.int64
|
| 219 |
+
VMCI_BUFFER_MIN_SIZE = 86, _OptType.int64
|
| 220 |
+
VMCI_BUFFER_MAX_SIZE = 87, _OptType.int64
|
| 221 |
+
VMCI_CONNECT_TIMEOUT = 88
|
| 222 |
+
USE_FD = 89
|
| 223 |
+
GSSAPI_PRINCIPAL_NAMETYPE = 90
|
| 224 |
+
GSSAPI_SERVICE_PRINCIPAL_NAMETYPE = 91
|
| 225 |
+
BINDTODEVICE = 92, _OptType.bytes
|
| 226 |
+
|
| 227 |
+
# Deprecated options and aliases
|
| 228 |
+
# must not use name-assignment, must have the same value
|
| 229 |
+
IDENTITY = ROUTING_ID
|
| 230 |
+
CONNECT_RID = CONNECT_ROUTING_ID
|
| 231 |
+
TCP_ACCEPT_FILTER = 38, _OptType.bytes
|
| 232 |
+
IPC_FILTER_PID = 58
|
| 233 |
+
IPC_FILTER_UID = 59
|
| 234 |
+
IPC_FILTER_GID = 60
|
| 235 |
+
IPV4ONLY = 31
|
| 236 |
+
DELAY_ATTACH_ON_CONNECT = IMMEDIATE
|
| 237 |
+
FAIL_UNROUTABLE = ROUTER_MANDATORY
|
| 238 |
+
ROUTER_BEHAVIOR = ROUTER_MANDATORY
|
| 239 |
+
|
| 240 |
+
# Draft socket options
|
| 241 |
+
ZAP_ENFORCE_DOMAIN = 93
|
| 242 |
+
LOOPBACK_FASTPATH = 94
|
| 243 |
+
METADATA = 95, _OptType.bytes
|
| 244 |
+
MULTICAST_LOOP = 96
|
| 245 |
+
ROUTER_NOTIFY = 97
|
| 246 |
+
XPUB_MANUAL_LAST_VALUE = 98
|
| 247 |
+
SOCKS_USERNAME = 99, _OptType.bytes
|
| 248 |
+
SOCKS_PASSWORD = 100, _OptType.bytes
|
| 249 |
+
IN_BATCH_SIZE = 101
|
| 250 |
+
OUT_BATCH_SIZE = 102
|
| 251 |
+
WSS_KEY_PEM = 103, _OptType.bytes
|
| 252 |
+
WSS_CERT_PEM = 104, _OptType.bytes
|
| 253 |
+
WSS_TRUST_PEM = 105, _OptType.bytes
|
| 254 |
+
WSS_HOSTNAME = 106, _OptType.bytes
|
| 255 |
+
WSS_TRUST_SYSTEM = 107
|
| 256 |
+
ONLY_FIRST_SUBSCRIBE = 108
|
| 257 |
+
RECONNECT_STOP = 109
|
| 258 |
+
HELLO_MSG = 110, _OptType.bytes
|
| 259 |
+
DISCONNECT_MSG = 111, _OptType.bytes
|
| 260 |
+
PRIORITY = 112
|
| 261 |
+
# 4.3.5
|
| 262 |
+
BUSY_POLL = 113
|
| 263 |
+
HICCUP_MSG = 114, _OptType.bytes
|
| 264 |
+
XSUB_VERBOSE_UNSUBSCRIBE = 115
|
| 265 |
+
TOPICS_COUNT = 116
|
| 266 |
+
NORM_MODE = 117
|
| 267 |
+
NORM_UNICAST_NACK = 118
|
| 268 |
+
NORM_BUFFER_SIZE = 119
|
| 269 |
+
NORM_SEGMENT_SIZE = 120
|
| 270 |
+
NORM_BLOCK_SIZE = 121
|
| 271 |
+
NORM_NUM_PARITY = 122
|
| 272 |
+
NORM_NUM_AUTOPARITY = 123
|
| 273 |
+
NORM_PUSH = 124
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
class MessageOption(IntEnum):
|
| 277 |
+
"""Options on zmq.Frame objects
|
| 278 |
+
|
| 279 |
+
.. versionadded:: 23
|
| 280 |
+
"""
|
| 281 |
+
|
| 282 |
+
MORE = 1
|
| 283 |
+
SHARED = 3
|
| 284 |
+
# Deprecated message options
|
| 285 |
+
SRCFD = 2
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
class Flag(IntFlag):
|
| 289 |
+
"""Send/recv flags
|
| 290 |
+
|
| 291 |
+
.. versionadded:: 23
|
| 292 |
+
"""
|
| 293 |
+
|
| 294 |
+
DONTWAIT = 1
|
| 295 |
+
SNDMORE = 2
|
| 296 |
+
NOBLOCK = DONTWAIT
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
class RouterNotify(IntEnum):
|
| 300 |
+
"""Values for zmq.ROUTER_NOTIFY socket option
|
| 301 |
+
|
| 302 |
+
.. versionadded:: 26
|
| 303 |
+
.. versionadded:: libzmq-4.3.0 (draft)
|
| 304 |
+
"""
|
| 305 |
+
|
| 306 |
+
@staticmethod
|
| 307 |
+
def _global_name(name):
|
| 308 |
+
return f"NOTIFY_{name}"
|
| 309 |
+
|
| 310 |
+
CONNECT = 1
|
| 311 |
+
DISCONNECT = 2
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
class NormMode(IntEnum):
|
| 315 |
+
"""Values for zmq.NORM_MODE socket option
|
| 316 |
+
|
| 317 |
+
.. versionadded:: 26
|
| 318 |
+
.. versionadded:: libzmq-4.3.5 (draft)
|
| 319 |
+
"""
|
| 320 |
+
|
| 321 |
+
@staticmethod
|
| 322 |
+
def _global_name(name):
|
| 323 |
+
return f"NORM_{name}"
|
| 324 |
+
|
| 325 |
+
FIXED = 0
|
| 326 |
+
CC = 1
|
| 327 |
+
CCL = 2
|
| 328 |
+
CCE = 3
|
| 329 |
+
CCE_ECNONLY = 4
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
class SecurityMechanism(IntEnum):
|
| 333 |
+
"""Security mechanisms (as returned by ``socket.get(zmq.MECHANISM)``)
|
| 334 |
+
|
| 335 |
+
.. versionadded:: 23
|
| 336 |
+
"""
|
| 337 |
+
|
| 338 |
+
NULL = 0
|
| 339 |
+
PLAIN = 1
|
| 340 |
+
CURVE = 2
|
| 341 |
+
GSSAPI = 3
|
| 342 |
+
|
| 343 |
+
|
| 344 |
+
class ReconnectStop(IntEnum):
|
| 345 |
+
"""Select behavior for socket.reconnect_stop
|
| 346 |
+
|
| 347 |
+
.. versionadded:: 25
|
| 348 |
+
"""
|
| 349 |
+
|
| 350 |
+
@staticmethod
|
| 351 |
+
def _global_name(name):
|
| 352 |
+
return f"RECONNECT_STOP_{name}"
|
| 353 |
+
|
| 354 |
+
CONN_REFUSED = 0x1
|
| 355 |
+
HANDSHAKE_FAILED = 0x2
|
| 356 |
+
AFTER_DISCONNECT = 0x4
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
class Event(IntFlag):
|
| 360 |
+
"""Socket monitoring events
|
| 361 |
+
|
| 362 |
+
.. versionadded:: 23
|
| 363 |
+
"""
|
| 364 |
+
|
| 365 |
+
@staticmethod
|
| 366 |
+
def _global_name(name):
|
| 367 |
+
if name.startswith("PROTOCOL_ERROR_"):
|
| 368 |
+
return name
|
| 369 |
+
else:
|
| 370 |
+
# add EVENT_ prefix
|
| 371 |
+
return "EVENT_" + name
|
| 372 |
+
|
| 373 |
+
PROTOCOL_ERROR_WS_UNSPECIFIED = 0x30000000
|
| 374 |
+
PROTOCOL_ERROR_ZMTP_UNSPECIFIED = 0x10000000
|
| 375 |
+
PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND = 0x10000001
|
| 376 |
+
PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE = 0x10000002
|
| 377 |
+
PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE = 0x10000003
|
| 378 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED = 0x10000011
|
| 379 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE = 0x10000012
|
| 380 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO = 0x10000013
|
| 381 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE = 0x10000014
|
| 382 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR = 0x10000015
|
| 383 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY = 0x10000016
|
| 384 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME = 0x10000017
|
| 385 |
+
PROTOCOL_ERROR_ZMTP_INVALID_METADATA = 0x10000018
|
| 386 |
+
|
| 387 |
+
PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC = 0x11000001
|
| 388 |
+
PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH = 0x11000002
|
| 389 |
+
PROTOCOL_ERROR_ZAP_UNSPECIFIED = 0x20000000
|
| 390 |
+
PROTOCOL_ERROR_ZAP_MALFORMED_REPLY = 0x20000001
|
| 391 |
+
PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID = 0x20000002
|
| 392 |
+
PROTOCOL_ERROR_ZAP_BAD_VERSION = 0x20000003
|
| 393 |
+
PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE = 0x20000004
|
| 394 |
+
PROTOCOL_ERROR_ZAP_INVALID_METADATA = 0x20000005
|
| 395 |
+
|
| 396 |
+
# define event types _after_ overlapping protocol error masks
|
| 397 |
+
CONNECTED = 0x0001
|
| 398 |
+
CONNECT_DELAYED = 0x0002
|
| 399 |
+
CONNECT_RETRIED = 0x0004
|
| 400 |
+
LISTENING = 0x0008
|
| 401 |
+
BIND_FAILED = 0x0010
|
| 402 |
+
ACCEPTED = 0x0020
|
| 403 |
+
ACCEPT_FAILED = 0x0040
|
| 404 |
+
CLOSED = 0x0080
|
| 405 |
+
CLOSE_FAILED = 0x0100
|
| 406 |
+
DISCONNECTED = 0x0200
|
| 407 |
+
MONITOR_STOPPED = 0x0400
|
| 408 |
+
|
| 409 |
+
HANDSHAKE_FAILED_NO_DETAIL = 0x0800
|
| 410 |
+
HANDSHAKE_SUCCEEDED = 0x1000
|
| 411 |
+
HANDSHAKE_FAILED_PROTOCOL = 0x2000
|
| 412 |
+
HANDSHAKE_FAILED_AUTH = 0x4000
|
| 413 |
+
|
| 414 |
+
ALL_V1 = 0xFFFF
|
| 415 |
+
ALL = ALL_V1
|
| 416 |
+
|
| 417 |
+
# DRAFT Socket monitoring events
|
| 418 |
+
PIPES_STATS = 0x10000
|
| 419 |
+
ALL_V2 = ALL_V1 | PIPES_STATS
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
class PollEvent(IntFlag):
|
| 423 |
+
"""Which events to poll for in poll methods
|
| 424 |
+
|
| 425 |
+
.. versionadded: 23
|
| 426 |
+
"""
|
| 427 |
+
|
| 428 |
+
POLLIN = 1
|
| 429 |
+
POLLOUT = 2
|
| 430 |
+
POLLERR = 4
|
| 431 |
+
POLLPRI = 8
|
| 432 |
+
|
| 433 |
+
|
| 434 |
+
class DeviceType(IntEnum):
|
| 435 |
+
"""Device type constants for zmq.device
|
| 436 |
+
|
| 437 |
+
.. versionadded: 23
|
| 438 |
+
"""
|
| 439 |
+
|
| 440 |
+
STREAMER = 1
|
| 441 |
+
FORWARDER = 2
|
| 442 |
+
QUEUE = 3
|
| 443 |
+
|
| 444 |
+
|
| 445 |
+
# AUTOGENERATED_BELOW_HERE
|
| 446 |
+
|
| 447 |
+
|
| 448 |
+
IO_THREADS: int = ContextOption.IO_THREADS
|
| 449 |
+
MAX_SOCKETS: int = ContextOption.MAX_SOCKETS
|
| 450 |
+
SOCKET_LIMIT: int = ContextOption.SOCKET_LIMIT
|
| 451 |
+
THREAD_PRIORITY: int = ContextOption.THREAD_PRIORITY
|
| 452 |
+
THREAD_SCHED_POLICY: int = ContextOption.THREAD_SCHED_POLICY
|
| 453 |
+
MAX_MSGSZ: int = ContextOption.MAX_MSGSZ
|
| 454 |
+
MSG_T_SIZE: int = ContextOption.MSG_T_SIZE
|
| 455 |
+
THREAD_AFFINITY_CPU_ADD: int = ContextOption.THREAD_AFFINITY_CPU_ADD
|
| 456 |
+
THREAD_AFFINITY_CPU_REMOVE: int = ContextOption.THREAD_AFFINITY_CPU_REMOVE
|
| 457 |
+
THREAD_NAME_PREFIX: int = ContextOption.THREAD_NAME_PREFIX
|
| 458 |
+
STREAMER: int = DeviceType.STREAMER
|
| 459 |
+
FORWARDER: int = DeviceType.FORWARDER
|
| 460 |
+
QUEUE: int = DeviceType.QUEUE
|
| 461 |
+
EAGAIN: int = Errno.EAGAIN
|
| 462 |
+
EFAULT: int = Errno.EFAULT
|
| 463 |
+
EINVAL: int = Errno.EINVAL
|
| 464 |
+
ENOTSUP: int = Errno.ENOTSUP
|
| 465 |
+
EPROTONOSUPPORT: int = Errno.EPROTONOSUPPORT
|
| 466 |
+
ENOBUFS: int = Errno.ENOBUFS
|
| 467 |
+
ENETDOWN: int = Errno.ENETDOWN
|
| 468 |
+
EADDRINUSE: int = Errno.EADDRINUSE
|
| 469 |
+
EADDRNOTAVAIL: int = Errno.EADDRNOTAVAIL
|
| 470 |
+
ECONNREFUSED: int = Errno.ECONNREFUSED
|
| 471 |
+
EINPROGRESS: int = Errno.EINPROGRESS
|
| 472 |
+
ENOTSOCK: int = Errno.ENOTSOCK
|
| 473 |
+
EMSGSIZE: int = Errno.EMSGSIZE
|
| 474 |
+
EAFNOSUPPORT: int = Errno.EAFNOSUPPORT
|
| 475 |
+
ENETUNREACH: int = Errno.ENETUNREACH
|
| 476 |
+
ECONNABORTED: int = Errno.ECONNABORTED
|
| 477 |
+
ECONNRESET: int = Errno.ECONNRESET
|
| 478 |
+
ENOTCONN: int = Errno.ENOTCONN
|
| 479 |
+
ETIMEDOUT: int = Errno.ETIMEDOUT
|
| 480 |
+
EHOSTUNREACH: int = Errno.EHOSTUNREACH
|
| 481 |
+
ENETRESET: int = Errno.ENETRESET
|
| 482 |
+
EFSM: int = Errno.EFSM
|
| 483 |
+
ENOCOMPATPROTO: int = Errno.ENOCOMPATPROTO
|
| 484 |
+
ETERM: int = Errno.ETERM
|
| 485 |
+
EMTHREAD: int = Errno.EMTHREAD
|
| 486 |
+
PROTOCOL_ERROR_WS_UNSPECIFIED: int = Event.PROTOCOL_ERROR_WS_UNSPECIFIED
|
| 487 |
+
PROTOCOL_ERROR_ZMTP_UNSPECIFIED: int = Event.PROTOCOL_ERROR_ZMTP_UNSPECIFIED
|
| 488 |
+
PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND: int = (
|
| 489 |
+
Event.PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
|
| 490 |
+
)
|
| 491 |
+
PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE: int = Event.PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE
|
| 492 |
+
PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE: int = Event.PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE
|
| 493 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED: int = (
|
| 494 |
+
Event.PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED
|
| 495 |
+
)
|
| 496 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE: int = (
|
| 497 |
+
Event.PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE
|
| 498 |
+
)
|
| 499 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO: int = (
|
| 500 |
+
Event.PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO
|
| 501 |
+
)
|
| 502 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE: int = (
|
| 503 |
+
Event.PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE
|
| 504 |
+
)
|
| 505 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR: int = (
|
| 506 |
+
Event.PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR
|
| 507 |
+
)
|
| 508 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY: int = (
|
| 509 |
+
Event.PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY
|
| 510 |
+
)
|
| 511 |
+
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME: int = (
|
| 512 |
+
Event.PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME
|
| 513 |
+
)
|
| 514 |
+
PROTOCOL_ERROR_ZMTP_INVALID_METADATA: int = Event.PROTOCOL_ERROR_ZMTP_INVALID_METADATA
|
| 515 |
+
PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC: int = Event.PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
|
| 516 |
+
PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH: int = (
|
| 517 |
+
Event.PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH
|
| 518 |
+
)
|
| 519 |
+
PROTOCOL_ERROR_ZAP_UNSPECIFIED: int = Event.PROTOCOL_ERROR_ZAP_UNSPECIFIED
|
| 520 |
+
PROTOCOL_ERROR_ZAP_MALFORMED_REPLY: int = Event.PROTOCOL_ERROR_ZAP_MALFORMED_REPLY
|
| 521 |
+
PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID: int = Event.PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID
|
| 522 |
+
PROTOCOL_ERROR_ZAP_BAD_VERSION: int = Event.PROTOCOL_ERROR_ZAP_BAD_VERSION
|
| 523 |
+
PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE: int = (
|
| 524 |
+
Event.PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE
|
| 525 |
+
)
|
| 526 |
+
PROTOCOL_ERROR_ZAP_INVALID_METADATA: int = Event.PROTOCOL_ERROR_ZAP_INVALID_METADATA
|
| 527 |
+
EVENT_CONNECTED: int = Event.CONNECTED
|
| 528 |
+
EVENT_CONNECT_DELAYED: int = Event.CONNECT_DELAYED
|
| 529 |
+
EVENT_CONNECT_RETRIED: int = Event.CONNECT_RETRIED
|
| 530 |
+
EVENT_LISTENING: int = Event.LISTENING
|
| 531 |
+
EVENT_BIND_FAILED: int = Event.BIND_FAILED
|
| 532 |
+
EVENT_ACCEPTED: int = Event.ACCEPTED
|
| 533 |
+
EVENT_ACCEPT_FAILED: int = Event.ACCEPT_FAILED
|
| 534 |
+
EVENT_CLOSED: int = Event.CLOSED
|
| 535 |
+
EVENT_CLOSE_FAILED: int = Event.CLOSE_FAILED
|
| 536 |
+
EVENT_DISCONNECTED: int = Event.DISCONNECTED
|
| 537 |
+
EVENT_MONITOR_STOPPED: int = Event.MONITOR_STOPPED
|
| 538 |
+
EVENT_HANDSHAKE_FAILED_NO_DETAIL: int = Event.HANDSHAKE_FAILED_NO_DETAIL
|
| 539 |
+
EVENT_HANDSHAKE_SUCCEEDED: int = Event.HANDSHAKE_SUCCEEDED
|
| 540 |
+
EVENT_HANDSHAKE_FAILED_PROTOCOL: int = Event.HANDSHAKE_FAILED_PROTOCOL
|
| 541 |
+
EVENT_HANDSHAKE_FAILED_AUTH: int = Event.HANDSHAKE_FAILED_AUTH
|
| 542 |
+
EVENT_ALL_V1: int = Event.ALL_V1
|
| 543 |
+
EVENT_ALL: int = Event.ALL
|
| 544 |
+
EVENT_PIPES_STATS: int = Event.PIPES_STATS
|
| 545 |
+
EVENT_ALL_V2: int = Event.ALL_V2
|
| 546 |
+
DONTWAIT: int = Flag.DONTWAIT
|
| 547 |
+
SNDMORE: int = Flag.SNDMORE
|
| 548 |
+
NOBLOCK: int = Flag.NOBLOCK
|
| 549 |
+
MORE: int = MessageOption.MORE
|
| 550 |
+
SHARED: int = MessageOption.SHARED
|
| 551 |
+
SRCFD: int = MessageOption.SRCFD
|
| 552 |
+
NORM_FIXED: int = NormMode.FIXED
|
| 553 |
+
NORM_CC: int = NormMode.CC
|
| 554 |
+
NORM_CCL: int = NormMode.CCL
|
| 555 |
+
NORM_CCE: int = NormMode.CCE
|
| 556 |
+
NORM_CCE_ECNONLY: int = NormMode.CCE_ECNONLY
|
| 557 |
+
POLLIN: int = PollEvent.POLLIN
|
| 558 |
+
POLLOUT: int = PollEvent.POLLOUT
|
| 559 |
+
POLLERR: int = PollEvent.POLLERR
|
| 560 |
+
POLLPRI: int = PollEvent.POLLPRI
|
| 561 |
+
RECONNECT_STOP_CONN_REFUSED: int = ReconnectStop.CONN_REFUSED
|
| 562 |
+
RECONNECT_STOP_HANDSHAKE_FAILED: int = ReconnectStop.HANDSHAKE_FAILED
|
| 563 |
+
RECONNECT_STOP_AFTER_DISCONNECT: int = ReconnectStop.AFTER_DISCONNECT
|
| 564 |
+
NOTIFY_CONNECT: int = RouterNotify.CONNECT
|
| 565 |
+
NOTIFY_DISCONNECT: int = RouterNotify.DISCONNECT
|
| 566 |
+
NULL: int = SecurityMechanism.NULL
|
| 567 |
+
PLAIN: int = SecurityMechanism.PLAIN
|
| 568 |
+
CURVE: int = SecurityMechanism.CURVE
|
| 569 |
+
GSSAPI: int = SecurityMechanism.GSSAPI
|
| 570 |
+
HWM: int = SocketOption.HWM
|
| 571 |
+
AFFINITY: int = SocketOption.AFFINITY
|
| 572 |
+
ROUTING_ID: int = SocketOption.ROUTING_ID
|
| 573 |
+
SUBSCRIBE: int = SocketOption.SUBSCRIBE
|
| 574 |
+
UNSUBSCRIBE: int = SocketOption.UNSUBSCRIBE
|
| 575 |
+
RATE: int = SocketOption.RATE
|
| 576 |
+
RECOVERY_IVL: int = SocketOption.RECOVERY_IVL
|
| 577 |
+
SNDBUF: int = SocketOption.SNDBUF
|
| 578 |
+
RCVBUF: int = SocketOption.RCVBUF
|
| 579 |
+
RCVMORE: int = SocketOption.RCVMORE
|
| 580 |
+
FD: int = SocketOption.FD
|
| 581 |
+
EVENTS: int = SocketOption.EVENTS
|
| 582 |
+
TYPE: int = SocketOption.TYPE
|
| 583 |
+
LINGER: int = SocketOption.LINGER
|
| 584 |
+
RECONNECT_IVL: int = SocketOption.RECONNECT_IVL
|
| 585 |
+
BACKLOG: int = SocketOption.BACKLOG
|
| 586 |
+
RECONNECT_IVL_MAX: int = SocketOption.RECONNECT_IVL_MAX
|
| 587 |
+
MAXMSGSIZE: int = SocketOption.MAXMSGSIZE
|
| 588 |
+
SNDHWM: int = SocketOption.SNDHWM
|
| 589 |
+
RCVHWM: int = SocketOption.RCVHWM
|
| 590 |
+
MULTICAST_HOPS: int = SocketOption.MULTICAST_HOPS
|
| 591 |
+
RCVTIMEO: int = SocketOption.RCVTIMEO
|
| 592 |
+
SNDTIMEO: int = SocketOption.SNDTIMEO
|
| 593 |
+
LAST_ENDPOINT: int = SocketOption.LAST_ENDPOINT
|
| 594 |
+
ROUTER_MANDATORY: int = SocketOption.ROUTER_MANDATORY
|
| 595 |
+
TCP_KEEPALIVE: int = SocketOption.TCP_KEEPALIVE
|
| 596 |
+
TCP_KEEPALIVE_CNT: int = SocketOption.TCP_KEEPALIVE_CNT
|
| 597 |
+
TCP_KEEPALIVE_IDLE: int = SocketOption.TCP_KEEPALIVE_IDLE
|
| 598 |
+
TCP_KEEPALIVE_INTVL: int = SocketOption.TCP_KEEPALIVE_INTVL
|
| 599 |
+
IMMEDIATE: int = SocketOption.IMMEDIATE
|
| 600 |
+
XPUB_VERBOSE: int = SocketOption.XPUB_VERBOSE
|
| 601 |
+
ROUTER_RAW: int = SocketOption.ROUTER_RAW
|
| 602 |
+
IPV6: int = SocketOption.IPV6
|
| 603 |
+
MECHANISM: int = SocketOption.MECHANISM
|
| 604 |
+
PLAIN_SERVER: int = SocketOption.PLAIN_SERVER
|
| 605 |
+
PLAIN_USERNAME: int = SocketOption.PLAIN_USERNAME
|
| 606 |
+
PLAIN_PASSWORD: int = SocketOption.PLAIN_PASSWORD
|
| 607 |
+
CURVE_SERVER: int = SocketOption.CURVE_SERVER
|
| 608 |
+
CURVE_PUBLICKEY: int = SocketOption.CURVE_PUBLICKEY
|
| 609 |
+
CURVE_SECRETKEY: int = SocketOption.CURVE_SECRETKEY
|
| 610 |
+
CURVE_SERVERKEY: int = SocketOption.CURVE_SERVERKEY
|
| 611 |
+
PROBE_ROUTER: int = SocketOption.PROBE_ROUTER
|
| 612 |
+
REQ_CORRELATE: int = SocketOption.REQ_CORRELATE
|
| 613 |
+
REQ_RELAXED: int = SocketOption.REQ_RELAXED
|
| 614 |
+
CONFLATE: int = SocketOption.CONFLATE
|
| 615 |
+
ZAP_DOMAIN: int = SocketOption.ZAP_DOMAIN
|
| 616 |
+
ROUTER_HANDOVER: int = SocketOption.ROUTER_HANDOVER
|
| 617 |
+
TOS: int = SocketOption.TOS
|
| 618 |
+
CONNECT_ROUTING_ID: int = SocketOption.CONNECT_ROUTING_ID
|
| 619 |
+
GSSAPI_SERVER: int = SocketOption.GSSAPI_SERVER
|
| 620 |
+
GSSAPI_PRINCIPAL: int = SocketOption.GSSAPI_PRINCIPAL
|
| 621 |
+
GSSAPI_SERVICE_PRINCIPAL: int = SocketOption.GSSAPI_SERVICE_PRINCIPAL
|
| 622 |
+
GSSAPI_PLAINTEXT: int = SocketOption.GSSAPI_PLAINTEXT
|
| 623 |
+
HANDSHAKE_IVL: int = SocketOption.HANDSHAKE_IVL
|
| 624 |
+
SOCKS_PROXY: int = SocketOption.SOCKS_PROXY
|
| 625 |
+
XPUB_NODROP: int = SocketOption.XPUB_NODROP
|
| 626 |
+
BLOCKY: int = SocketOption.BLOCKY
|
| 627 |
+
XPUB_MANUAL: int = SocketOption.XPUB_MANUAL
|
| 628 |
+
XPUB_WELCOME_MSG: int = SocketOption.XPUB_WELCOME_MSG
|
| 629 |
+
STREAM_NOTIFY: int = SocketOption.STREAM_NOTIFY
|
| 630 |
+
INVERT_MATCHING: int = SocketOption.INVERT_MATCHING
|
| 631 |
+
HEARTBEAT_IVL: int = SocketOption.HEARTBEAT_IVL
|
| 632 |
+
HEARTBEAT_TTL: int = SocketOption.HEARTBEAT_TTL
|
| 633 |
+
HEARTBEAT_TIMEOUT: int = SocketOption.HEARTBEAT_TIMEOUT
|
| 634 |
+
XPUB_VERBOSER: int = SocketOption.XPUB_VERBOSER
|
| 635 |
+
CONNECT_TIMEOUT: int = SocketOption.CONNECT_TIMEOUT
|
| 636 |
+
TCP_MAXRT: int = SocketOption.TCP_MAXRT
|
| 637 |
+
THREAD_SAFE: int = SocketOption.THREAD_SAFE
|
| 638 |
+
MULTICAST_MAXTPDU: int = SocketOption.MULTICAST_MAXTPDU
|
| 639 |
+
VMCI_BUFFER_SIZE: int = SocketOption.VMCI_BUFFER_SIZE
|
| 640 |
+
VMCI_BUFFER_MIN_SIZE: int = SocketOption.VMCI_BUFFER_MIN_SIZE
|
| 641 |
+
VMCI_BUFFER_MAX_SIZE: int = SocketOption.VMCI_BUFFER_MAX_SIZE
|
| 642 |
+
VMCI_CONNECT_TIMEOUT: int = SocketOption.VMCI_CONNECT_TIMEOUT
|
| 643 |
+
USE_FD: int = SocketOption.USE_FD
|
| 644 |
+
GSSAPI_PRINCIPAL_NAMETYPE: int = SocketOption.GSSAPI_PRINCIPAL_NAMETYPE
|
| 645 |
+
GSSAPI_SERVICE_PRINCIPAL_NAMETYPE: int = SocketOption.GSSAPI_SERVICE_PRINCIPAL_NAMETYPE
|
| 646 |
+
BINDTODEVICE: int = SocketOption.BINDTODEVICE
|
| 647 |
+
IDENTITY: int = SocketOption.IDENTITY
|
| 648 |
+
CONNECT_RID: int = SocketOption.CONNECT_RID
|
| 649 |
+
TCP_ACCEPT_FILTER: int = SocketOption.TCP_ACCEPT_FILTER
|
| 650 |
+
IPC_FILTER_PID: int = SocketOption.IPC_FILTER_PID
|
| 651 |
+
IPC_FILTER_UID: int = SocketOption.IPC_FILTER_UID
|
| 652 |
+
IPC_FILTER_GID: int = SocketOption.IPC_FILTER_GID
|
| 653 |
+
IPV4ONLY: int = SocketOption.IPV4ONLY
|
| 654 |
+
DELAY_ATTACH_ON_CONNECT: int = SocketOption.DELAY_ATTACH_ON_CONNECT
|
| 655 |
+
FAIL_UNROUTABLE: int = SocketOption.FAIL_UNROUTABLE
|
| 656 |
+
ROUTER_BEHAVIOR: int = SocketOption.ROUTER_BEHAVIOR
|
| 657 |
+
ZAP_ENFORCE_DOMAIN: int = SocketOption.ZAP_ENFORCE_DOMAIN
|
| 658 |
+
LOOPBACK_FASTPATH: int = SocketOption.LOOPBACK_FASTPATH
|
| 659 |
+
METADATA: int = SocketOption.METADATA
|
| 660 |
+
MULTICAST_LOOP: int = SocketOption.MULTICAST_LOOP
|
| 661 |
+
ROUTER_NOTIFY: int = SocketOption.ROUTER_NOTIFY
|
| 662 |
+
XPUB_MANUAL_LAST_VALUE: int = SocketOption.XPUB_MANUAL_LAST_VALUE
|
| 663 |
+
SOCKS_USERNAME: int = SocketOption.SOCKS_USERNAME
|
| 664 |
+
SOCKS_PASSWORD: int = SocketOption.SOCKS_PASSWORD
|
| 665 |
+
IN_BATCH_SIZE: int = SocketOption.IN_BATCH_SIZE
|
| 666 |
+
OUT_BATCH_SIZE: int = SocketOption.OUT_BATCH_SIZE
|
| 667 |
+
WSS_KEY_PEM: int = SocketOption.WSS_KEY_PEM
|
| 668 |
+
WSS_CERT_PEM: int = SocketOption.WSS_CERT_PEM
|
| 669 |
+
WSS_TRUST_PEM: int = SocketOption.WSS_TRUST_PEM
|
| 670 |
+
WSS_HOSTNAME: int = SocketOption.WSS_HOSTNAME
|
| 671 |
+
WSS_TRUST_SYSTEM: int = SocketOption.WSS_TRUST_SYSTEM
|
| 672 |
+
ONLY_FIRST_SUBSCRIBE: int = SocketOption.ONLY_FIRST_SUBSCRIBE
|
| 673 |
+
RECONNECT_STOP: int = SocketOption.RECONNECT_STOP
|
| 674 |
+
HELLO_MSG: int = SocketOption.HELLO_MSG
|
| 675 |
+
DISCONNECT_MSG: int = SocketOption.DISCONNECT_MSG
|
| 676 |
+
PRIORITY: int = SocketOption.PRIORITY
|
| 677 |
+
BUSY_POLL: int = SocketOption.BUSY_POLL
|
| 678 |
+
HICCUP_MSG: int = SocketOption.HICCUP_MSG
|
| 679 |
+
XSUB_VERBOSE_UNSUBSCRIBE: int = SocketOption.XSUB_VERBOSE_UNSUBSCRIBE
|
| 680 |
+
TOPICS_COUNT: int = SocketOption.TOPICS_COUNT
|
| 681 |
+
NORM_MODE: int = SocketOption.NORM_MODE
|
| 682 |
+
NORM_UNICAST_NACK: int = SocketOption.NORM_UNICAST_NACK
|
| 683 |
+
NORM_BUFFER_SIZE: int = SocketOption.NORM_BUFFER_SIZE
|
| 684 |
+
NORM_SEGMENT_SIZE: int = SocketOption.NORM_SEGMENT_SIZE
|
| 685 |
+
NORM_BLOCK_SIZE: int = SocketOption.NORM_BLOCK_SIZE
|
| 686 |
+
NORM_NUM_PARITY: int = SocketOption.NORM_NUM_PARITY
|
| 687 |
+
NORM_NUM_AUTOPARITY: int = SocketOption.NORM_NUM_AUTOPARITY
|
| 688 |
+
NORM_PUSH: int = SocketOption.NORM_PUSH
|
| 689 |
+
PAIR: int = SocketType.PAIR
|
| 690 |
+
PUB: int = SocketType.PUB
|
| 691 |
+
SUB: int = SocketType.SUB
|
| 692 |
+
REQ: int = SocketType.REQ
|
| 693 |
+
REP: int = SocketType.REP
|
| 694 |
+
DEALER: int = SocketType.DEALER
|
| 695 |
+
ROUTER: int = SocketType.ROUTER
|
| 696 |
+
PULL: int = SocketType.PULL
|
| 697 |
+
PUSH: int = SocketType.PUSH
|
| 698 |
+
XPUB: int = SocketType.XPUB
|
| 699 |
+
XSUB: int = SocketType.XSUB
|
| 700 |
+
STREAM: int = SocketType.STREAM
|
| 701 |
+
XREQ: int = SocketType.XREQ
|
| 702 |
+
XREP: int = SocketType.XREP
|
| 703 |
+
SERVER: int = SocketType.SERVER
|
| 704 |
+
CLIENT: int = SocketType.CLIENT
|
| 705 |
+
RADIO: int = SocketType.RADIO
|
| 706 |
+
DISH: int = SocketType.DISH
|
| 707 |
+
GATHER: int = SocketType.GATHER
|
| 708 |
+
SCATTER: int = SocketType.SCATTER
|
| 709 |
+
DGRAM: int = SocketType.DGRAM
|
| 710 |
+
PEER: int = SocketType.PEER
|
| 711 |
+
CHANNEL: int = SocketType.CHANNEL
|
| 712 |
+
|
| 713 |
+
__all__: list[str] = [
|
| 714 |
+
"ContextOption",
|
| 715 |
+
"IO_THREADS",
|
| 716 |
+
"MAX_SOCKETS",
|
| 717 |
+
"SOCKET_LIMIT",
|
| 718 |
+
"THREAD_PRIORITY",
|
| 719 |
+
"THREAD_SCHED_POLICY",
|
| 720 |
+
"MAX_MSGSZ",
|
| 721 |
+
"MSG_T_SIZE",
|
| 722 |
+
"THREAD_AFFINITY_CPU_ADD",
|
| 723 |
+
"THREAD_AFFINITY_CPU_REMOVE",
|
| 724 |
+
"THREAD_NAME_PREFIX",
|
| 725 |
+
"DeviceType",
|
| 726 |
+
"STREAMER",
|
| 727 |
+
"FORWARDER",
|
| 728 |
+
"QUEUE",
|
| 729 |
+
"Enum",
|
| 730 |
+
"Errno",
|
| 731 |
+
"EAGAIN",
|
| 732 |
+
"EFAULT",
|
| 733 |
+
"EINVAL",
|
| 734 |
+
"ENOTSUP",
|
| 735 |
+
"EPROTONOSUPPORT",
|
| 736 |
+
"ENOBUFS",
|
| 737 |
+
"ENETDOWN",
|
| 738 |
+
"EADDRINUSE",
|
| 739 |
+
"EADDRNOTAVAIL",
|
| 740 |
+
"ECONNREFUSED",
|
| 741 |
+
"EINPROGRESS",
|
| 742 |
+
"ENOTSOCK",
|
| 743 |
+
"EMSGSIZE",
|
| 744 |
+
"EAFNOSUPPORT",
|
| 745 |
+
"ENETUNREACH",
|
| 746 |
+
"ECONNABORTED",
|
| 747 |
+
"ECONNRESET",
|
| 748 |
+
"ENOTCONN",
|
| 749 |
+
"ETIMEDOUT",
|
| 750 |
+
"EHOSTUNREACH",
|
| 751 |
+
"ENETRESET",
|
| 752 |
+
"EFSM",
|
| 753 |
+
"ENOCOMPATPROTO",
|
| 754 |
+
"ETERM",
|
| 755 |
+
"EMTHREAD",
|
| 756 |
+
"Event",
|
| 757 |
+
"PROTOCOL_ERROR_WS_UNSPECIFIED",
|
| 758 |
+
"PROTOCOL_ERROR_ZMTP_UNSPECIFIED",
|
| 759 |
+
"PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND",
|
| 760 |
+
"PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE",
|
| 761 |
+
"PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE",
|
| 762 |
+
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED",
|
| 763 |
+
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE",
|
| 764 |
+
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO",
|
| 765 |
+
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE",
|
| 766 |
+
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR",
|
| 767 |
+
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY",
|
| 768 |
+
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME",
|
| 769 |
+
"PROTOCOL_ERROR_ZMTP_INVALID_METADATA",
|
| 770 |
+
"PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC",
|
| 771 |
+
"PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH",
|
| 772 |
+
"PROTOCOL_ERROR_ZAP_UNSPECIFIED",
|
| 773 |
+
"PROTOCOL_ERROR_ZAP_MALFORMED_REPLY",
|
| 774 |
+
"PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID",
|
| 775 |
+
"PROTOCOL_ERROR_ZAP_BAD_VERSION",
|
| 776 |
+
"PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE",
|
| 777 |
+
"PROTOCOL_ERROR_ZAP_INVALID_METADATA",
|
| 778 |
+
"EVENT_CONNECTED",
|
| 779 |
+
"EVENT_CONNECT_DELAYED",
|
| 780 |
+
"EVENT_CONNECT_RETRIED",
|
| 781 |
+
"EVENT_LISTENING",
|
| 782 |
+
"EVENT_BIND_FAILED",
|
| 783 |
+
"EVENT_ACCEPTED",
|
| 784 |
+
"EVENT_ACCEPT_FAILED",
|
| 785 |
+
"EVENT_CLOSED",
|
| 786 |
+
"EVENT_CLOSE_FAILED",
|
| 787 |
+
"EVENT_DISCONNECTED",
|
| 788 |
+
"EVENT_MONITOR_STOPPED",
|
| 789 |
+
"EVENT_HANDSHAKE_FAILED_NO_DETAIL",
|
| 790 |
+
"EVENT_HANDSHAKE_SUCCEEDED",
|
| 791 |
+
"EVENT_HANDSHAKE_FAILED_PROTOCOL",
|
| 792 |
+
"EVENT_HANDSHAKE_FAILED_AUTH",
|
| 793 |
+
"EVENT_ALL_V1",
|
| 794 |
+
"EVENT_ALL",
|
| 795 |
+
"EVENT_PIPES_STATS",
|
| 796 |
+
"EVENT_ALL_V2",
|
| 797 |
+
"Flag",
|
| 798 |
+
"DONTWAIT",
|
| 799 |
+
"SNDMORE",
|
| 800 |
+
"NOBLOCK",
|
| 801 |
+
"IntEnum",
|
| 802 |
+
"IntFlag",
|
| 803 |
+
"MessageOption",
|
| 804 |
+
"MORE",
|
| 805 |
+
"SHARED",
|
| 806 |
+
"SRCFD",
|
| 807 |
+
"NormMode",
|
| 808 |
+
"NORM_FIXED",
|
| 809 |
+
"NORM_CC",
|
| 810 |
+
"NORM_CCL",
|
| 811 |
+
"NORM_CCE",
|
| 812 |
+
"NORM_CCE_ECNONLY",
|
| 813 |
+
"PollEvent",
|
| 814 |
+
"POLLIN",
|
| 815 |
+
"POLLOUT",
|
| 816 |
+
"POLLERR",
|
| 817 |
+
"POLLPRI",
|
| 818 |
+
"ReconnectStop",
|
| 819 |
+
"RECONNECT_STOP_CONN_REFUSED",
|
| 820 |
+
"RECONNECT_STOP_HANDSHAKE_FAILED",
|
| 821 |
+
"RECONNECT_STOP_AFTER_DISCONNECT",
|
| 822 |
+
"RouterNotify",
|
| 823 |
+
"NOTIFY_CONNECT",
|
| 824 |
+
"NOTIFY_DISCONNECT",
|
| 825 |
+
"SecurityMechanism",
|
| 826 |
+
"NULL",
|
| 827 |
+
"PLAIN",
|
| 828 |
+
"CURVE",
|
| 829 |
+
"GSSAPI",
|
| 830 |
+
"SocketOption",
|
| 831 |
+
"HWM",
|
| 832 |
+
"AFFINITY",
|
| 833 |
+
"ROUTING_ID",
|
| 834 |
+
"SUBSCRIBE",
|
| 835 |
+
"UNSUBSCRIBE",
|
| 836 |
+
"RATE",
|
| 837 |
+
"RECOVERY_IVL",
|
| 838 |
+
"SNDBUF",
|
| 839 |
+
"RCVBUF",
|
| 840 |
+
"RCVMORE",
|
| 841 |
+
"FD",
|
| 842 |
+
"EVENTS",
|
| 843 |
+
"TYPE",
|
| 844 |
+
"LINGER",
|
| 845 |
+
"RECONNECT_IVL",
|
| 846 |
+
"BACKLOG",
|
| 847 |
+
"RECONNECT_IVL_MAX",
|
| 848 |
+
"MAXMSGSIZE",
|
| 849 |
+
"SNDHWM",
|
| 850 |
+
"RCVHWM",
|
| 851 |
+
"MULTICAST_HOPS",
|
| 852 |
+
"RCVTIMEO",
|
| 853 |
+
"SNDTIMEO",
|
| 854 |
+
"LAST_ENDPOINT",
|
| 855 |
+
"ROUTER_MANDATORY",
|
| 856 |
+
"TCP_KEEPALIVE",
|
| 857 |
+
"TCP_KEEPALIVE_CNT",
|
| 858 |
+
"TCP_KEEPALIVE_IDLE",
|
| 859 |
+
"TCP_KEEPALIVE_INTVL",
|
| 860 |
+
"IMMEDIATE",
|
| 861 |
+
"XPUB_VERBOSE",
|
| 862 |
+
"ROUTER_RAW",
|
| 863 |
+
"IPV6",
|
| 864 |
+
"MECHANISM",
|
| 865 |
+
"PLAIN_SERVER",
|
| 866 |
+
"PLAIN_USERNAME",
|
| 867 |
+
"PLAIN_PASSWORD",
|
| 868 |
+
"CURVE_SERVER",
|
| 869 |
+
"CURVE_PUBLICKEY",
|
| 870 |
+
"CURVE_SECRETKEY",
|
| 871 |
+
"CURVE_SERVERKEY",
|
| 872 |
+
"PROBE_ROUTER",
|
| 873 |
+
"REQ_CORRELATE",
|
| 874 |
+
"REQ_RELAXED",
|
| 875 |
+
"CONFLATE",
|
| 876 |
+
"ZAP_DOMAIN",
|
| 877 |
+
"ROUTER_HANDOVER",
|
| 878 |
+
"TOS",
|
| 879 |
+
"CONNECT_ROUTING_ID",
|
| 880 |
+
"GSSAPI_SERVER",
|
| 881 |
+
"GSSAPI_PRINCIPAL",
|
| 882 |
+
"GSSAPI_SERVICE_PRINCIPAL",
|
| 883 |
+
"GSSAPI_PLAINTEXT",
|
| 884 |
+
"HANDSHAKE_IVL",
|
| 885 |
+
"SOCKS_PROXY",
|
| 886 |
+
"XPUB_NODROP",
|
| 887 |
+
"BLOCKY",
|
| 888 |
+
"XPUB_MANUAL",
|
| 889 |
+
"XPUB_WELCOME_MSG",
|
| 890 |
+
"STREAM_NOTIFY",
|
| 891 |
+
"INVERT_MATCHING",
|
| 892 |
+
"HEARTBEAT_IVL",
|
| 893 |
+
"HEARTBEAT_TTL",
|
| 894 |
+
"HEARTBEAT_TIMEOUT",
|
| 895 |
+
"XPUB_VERBOSER",
|
| 896 |
+
"CONNECT_TIMEOUT",
|
| 897 |
+
"TCP_MAXRT",
|
| 898 |
+
"THREAD_SAFE",
|
| 899 |
+
"MULTICAST_MAXTPDU",
|
| 900 |
+
"VMCI_BUFFER_SIZE",
|
| 901 |
+
"VMCI_BUFFER_MIN_SIZE",
|
| 902 |
+
"VMCI_BUFFER_MAX_SIZE",
|
| 903 |
+
"VMCI_CONNECT_TIMEOUT",
|
| 904 |
+
"USE_FD",
|
| 905 |
+
"GSSAPI_PRINCIPAL_NAMETYPE",
|
| 906 |
+
"GSSAPI_SERVICE_PRINCIPAL_NAMETYPE",
|
| 907 |
+
"BINDTODEVICE",
|
| 908 |
+
"IDENTITY",
|
| 909 |
+
"CONNECT_RID",
|
| 910 |
+
"TCP_ACCEPT_FILTER",
|
| 911 |
+
"IPC_FILTER_PID",
|
| 912 |
+
"IPC_FILTER_UID",
|
| 913 |
+
"IPC_FILTER_GID",
|
| 914 |
+
"IPV4ONLY",
|
| 915 |
+
"DELAY_ATTACH_ON_CONNECT",
|
| 916 |
+
"FAIL_UNROUTABLE",
|
| 917 |
+
"ROUTER_BEHAVIOR",
|
| 918 |
+
"ZAP_ENFORCE_DOMAIN",
|
| 919 |
+
"LOOPBACK_FASTPATH",
|
| 920 |
+
"METADATA",
|
| 921 |
+
"MULTICAST_LOOP",
|
| 922 |
+
"ROUTER_NOTIFY",
|
| 923 |
+
"XPUB_MANUAL_LAST_VALUE",
|
| 924 |
+
"SOCKS_USERNAME",
|
| 925 |
+
"SOCKS_PASSWORD",
|
| 926 |
+
"IN_BATCH_SIZE",
|
| 927 |
+
"OUT_BATCH_SIZE",
|
| 928 |
+
"WSS_KEY_PEM",
|
| 929 |
+
"WSS_CERT_PEM",
|
| 930 |
+
"WSS_TRUST_PEM",
|
| 931 |
+
"WSS_HOSTNAME",
|
| 932 |
+
"WSS_TRUST_SYSTEM",
|
| 933 |
+
"ONLY_FIRST_SUBSCRIBE",
|
| 934 |
+
"RECONNECT_STOP",
|
| 935 |
+
"HELLO_MSG",
|
| 936 |
+
"DISCONNECT_MSG",
|
| 937 |
+
"PRIORITY",
|
| 938 |
+
"BUSY_POLL",
|
| 939 |
+
"HICCUP_MSG",
|
| 940 |
+
"XSUB_VERBOSE_UNSUBSCRIBE",
|
| 941 |
+
"TOPICS_COUNT",
|
| 942 |
+
"NORM_MODE",
|
| 943 |
+
"NORM_UNICAST_NACK",
|
| 944 |
+
"NORM_BUFFER_SIZE",
|
| 945 |
+
"NORM_SEGMENT_SIZE",
|
| 946 |
+
"NORM_BLOCK_SIZE",
|
| 947 |
+
"NORM_NUM_PARITY",
|
| 948 |
+
"NORM_NUM_AUTOPARITY",
|
| 949 |
+
"NORM_PUSH",
|
| 950 |
+
"SocketType",
|
| 951 |
+
"PAIR",
|
| 952 |
+
"PUB",
|
| 953 |
+
"SUB",
|
| 954 |
+
"REQ",
|
| 955 |
+
"REP",
|
| 956 |
+
"DEALER",
|
| 957 |
+
"ROUTER",
|
| 958 |
+
"PULL",
|
| 959 |
+
"PUSH",
|
| 960 |
+
"XPUB",
|
| 961 |
+
"XSUB",
|
| 962 |
+
"STREAM",
|
| 963 |
+
"XREQ",
|
| 964 |
+
"XREP",
|
| 965 |
+
"SERVER",
|
| 966 |
+
"CLIENT",
|
| 967 |
+
"RADIO",
|
| 968 |
+
"DISH",
|
| 969 |
+
"GATHER",
|
| 970 |
+
"SCATTER",
|
| 971 |
+
"DGRAM",
|
| 972 |
+
"PEER",
|
| 973 |
+
"CHANNEL",
|
| 974 |
+
]
|
.venv/lib/python3.11/site-packages/zmq/devices/__init__.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""0MQ Device classes for running in background threads or processes."""
|
| 2 |
+
|
| 3 |
+
# Copyright (C) PyZMQ Developers
|
| 4 |
+
# Distributed under the terms of the Modified BSD License.
|
| 5 |
+
|
| 6 |
+
from zmq import device
|
| 7 |
+
from zmq.devices import (
|
| 8 |
+
basedevice,
|
| 9 |
+
monitoredqueue,
|
| 10 |
+
monitoredqueuedevice,
|
| 11 |
+
proxydevice,
|
| 12 |
+
proxysteerabledevice,
|
| 13 |
+
)
|
| 14 |
+
from zmq.devices.basedevice import *
|
| 15 |
+
from zmq.devices.monitoredqueue import *
|
| 16 |
+
from zmq.devices.monitoredqueuedevice import *
|
| 17 |
+
from zmq.devices.proxydevice import *
|
| 18 |
+
from zmq.devices.proxysteerabledevice import *
|
| 19 |
+
|
| 20 |
+
__all__ = ['device']
|
| 21 |
+
for submod in (
|
| 22 |
+
basedevice,
|
| 23 |
+
proxydevice,
|
| 24 |
+
proxysteerabledevice,
|
| 25 |
+
monitoredqueue,
|
| 26 |
+
monitoredqueuedevice,
|
| 27 |
+
):
|
| 28 |
+
__all__.extend(submod.__all__) # type: ignore
|
.venv/lib/python3.11/site-packages/zmq/devices/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (972 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/devices/__pycache__/basedevice.cpython-311.pyc
ADDED
|
Binary file (14.4 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/devices/__pycache__/monitoredqueue.cpython-311.pyc
ADDED
|
Binary file (1.99 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/devices/__pycache__/monitoredqueuedevice.cpython-311.pyc
ADDED
|
Binary file (3.15 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/devices/__pycache__/proxydevice.cpython-311.pyc
ADDED
|
Binary file (5.03 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/devices/__pycache__/proxysteerabledevice.cpython-311.pyc
ADDED
|
Binary file (5.64 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/devices/basedevice.py
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Classes for running 0MQ Devices in the background."""
|
| 2 |
+
|
| 3 |
+
# Copyright (C) PyZMQ Developers
|
| 4 |
+
# Distributed under the terms of the Modified BSD License.
|
| 5 |
+
|
| 6 |
+
import time
|
| 7 |
+
from multiprocessing import Process
|
| 8 |
+
from threading import Thread
|
| 9 |
+
from typing import Any, Callable, List, Optional, Tuple
|
| 10 |
+
|
| 11 |
+
import zmq
|
| 12 |
+
from zmq import ENOTSOCK, ETERM, PUSH, QUEUE, Context, ZMQBindError, ZMQError, device
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class Device:
|
| 16 |
+
"""A 0MQ Device to be run in the background.
|
| 17 |
+
|
| 18 |
+
You do not pass Socket instances to this, but rather Socket types::
|
| 19 |
+
|
| 20 |
+
Device(device_type, in_socket_type, out_socket_type)
|
| 21 |
+
|
| 22 |
+
For instance::
|
| 23 |
+
|
| 24 |
+
dev = Device(zmq.QUEUE, zmq.DEALER, zmq.ROUTER)
|
| 25 |
+
|
| 26 |
+
Similar to zmq.device, but socket types instead of sockets themselves are
|
| 27 |
+
passed, and the sockets are created in the work thread, to avoid issues
|
| 28 |
+
with thread safety. As a result, additional bind_{in|out} and
|
| 29 |
+
connect_{in|out} methods and setsockopt_{in|out} allow users to specify
|
| 30 |
+
connections for the sockets.
|
| 31 |
+
|
| 32 |
+
Parameters
|
| 33 |
+
----------
|
| 34 |
+
device_type : int
|
| 35 |
+
The 0MQ Device type
|
| 36 |
+
{in|out}_type : int
|
| 37 |
+
zmq socket types, to be passed later to context.socket(). e.g.
|
| 38 |
+
zmq.PUB, zmq.SUB, zmq.REQ. If out_type is < 0, then in_socket is used
|
| 39 |
+
for both in_socket and out_socket.
|
| 40 |
+
|
| 41 |
+
Methods
|
| 42 |
+
-------
|
| 43 |
+
bind_{in_out}(iface)
|
| 44 |
+
passthrough for ``{in|out}_socket.bind(iface)``, to be called in the thread
|
| 45 |
+
connect_{in_out}(iface)
|
| 46 |
+
passthrough for ``{in|out}_socket.connect(iface)``, to be called in the
|
| 47 |
+
thread
|
| 48 |
+
setsockopt_{in_out}(opt,value)
|
| 49 |
+
passthrough for ``{in|out}_socket.setsockopt(opt, value)``, to be called in
|
| 50 |
+
the thread
|
| 51 |
+
|
| 52 |
+
Attributes
|
| 53 |
+
----------
|
| 54 |
+
daemon : bool
|
| 55 |
+
sets whether the thread should be run as a daemon
|
| 56 |
+
Default is true, because if it is false, the thread will not
|
| 57 |
+
exit unless it is killed
|
| 58 |
+
context_factory : callable
|
| 59 |
+
This is a class attribute.
|
| 60 |
+
Function for creating the Context. This will be Context.instance
|
| 61 |
+
in ThreadDevices, and Context in ProcessDevices. The only reason
|
| 62 |
+
it is not instance() in ProcessDevices is that there may be a stale
|
| 63 |
+
Context instance already initialized, and the forked environment
|
| 64 |
+
should *never* try to use it.
|
| 65 |
+
"""
|
| 66 |
+
|
| 67 |
+
context_factory: Callable[[], zmq.Context] = Context.instance
|
| 68 |
+
"""Callable that returns a context. Typically either Context.instance or Context,
|
| 69 |
+
depending on whether the device should share the global instance or not.
|
| 70 |
+
"""
|
| 71 |
+
|
| 72 |
+
daemon: bool
|
| 73 |
+
device_type: int
|
| 74 |
+
in_type: int
|
| 75 |
+
out_type: int
|
| 76 |
+
|
| 77 |
+
_in_binds: List[str]
|
| 78 |
+
_in_connects: List[str]
|
| 79 |
+
_in_sockopts: List[Tuple[int, Any]]
|
| 80 |
+
_out_binds: List[str]
|
| 81 |
+
_out_connects: List[str]
|
| 82 |
+
_out_sockopts: List[Tuple[int, Any]]
|
| 83 |
+
_random_addrs: List[str]
|
| 84 |
+
_sockets: List[zmq.Socket]
|
| 85 |
+
|
| 86 |
+
def __init__(
|
| 87 |
+
self,
|
| 88 |
+
device_type: int = QUEUE,
|
| 89 |
+
in_type: Optional[int] = None,
|
| 90 |
+
out_type: Optional[int] = None,
|
| 91 |
+
) -> None:
|
| 92 |
+
self.device_type = device_type
|
| 93 |
+
if in_type is None:
|
| 94 |
+
raise TypeError("in_type must be specified")
|
| 95 |
+
if out_type is None:
|
| 96 |
+
raise TypeError("out_type must be specified")
|
| 97 |
+
self.in_type = in_type
|
| 98 |
+
self.out_type = out_type
|
| 99 |
+
self._in_binds = []
|
| 100 |
+
self._in_connects = []
|
| 101 |
+
self._in_sockopts = []
|
| 102 |
+
self._out_binds = []
|
| 103 |
+
self._out_connects = []
|
| 104 |
+
self._out_sockopts = []
|
| 105 |
+
self._random_addrs = []
|
| 106 |
+
self.daemon = True
|
| 107 |
+
self.done = False
|
| 108 |
+
self._sockets = []
|
| 109 |
+
|
| 110 |
+
def bind_in(self, addr: str) -> None:
|
| 111 |
+
"""Enqueue ZMQ address for binding on in_socket.
|
| 112 |
+
|
| 113 |
+
See zmq.Socket.bind for details.
|
| 114 |
+
"""
|
| 115 |
+
self._in_binds.append(addr)
|
| 116 |
+
|
| 117 |
+
def bind_in_to_random_port(self, addr: str, *args, **kwargs) -> int:
|
| 118 |
+
"""Enqueue a random port on the given interface for binding on
|
| 119 |
+
in_socket.
|
| 120 |
+
|
| 121 |
+
See zmq.Socket.bind_to_random_port for details.
|
| 122 |
+
|
| 123 |
+
.. versionadded:: 18.0
|
| 124 |
+
"""
|
| 125 |
+
port = self._reserve_random_port(addr, *args, **kwargs)
|
| 126 |
+
|
| 127 |
+
self.bind_in(f'{addr}:{port}')
|
| 128 |
+
|
| 129 |
+
return port
|
| 130 |
+
|
| 131 |
+
def connect_in(self, addr: str) -> None:
|
| 132 |
+
"""Enqueue ZMQ address for connecting on in_socket.
|
| 133 |
+
|
| 134 |
+
See zmq.Socket.connect for details.
|
| 135 |
+
"""
|
| 136 |
+
self._in_connects.append(addr)
|
| 137 |
+
|
| 138 |
+
def setsockopt_in(self, opt: int, value: Any) -> None:
|
| 139 |
+
"""Enqueue setsockopt(opt, value) for in_socket
|
| 140 |
+
|
| 141 |
+
See zmq.Socket.setsockopt for details.
|
| 142 |
+
"""
|
| 143 |
+
self._in_sockopts.append((opt, value))
|
| 144 |
+
|
| 145 |
+
def bind_out(self, addr: str) -> None:
|
| 146 |
+
"""Enqueue ZMQ address for binding on out_socket.
|
| 147 |
+
|
| 148 |
+
See zmq.Socket.bind for details.
|
| 149 |
+
"""
|
| 150 |
+
self._out_binds.append(addr)
|
| 151 |
+
|
| 152 |
+
def bind_out_to_random_port(self, addr: str, *args, **kwargs) -> int:
|
| 153 |
+
"""Enqueue a random port on the given interface for binding on
|
| 154 |
+
out_socket.
|
| 155 |
+
|
| 156 |
+
See zmq.Socket.bind_to_random_port for details.
|
| 157 |
+
|
| 158 |
+
.. versionadded:: 18.0
|
| 159 |
+
"""
|
| 160 |
+
port = self._reserve_random_port(addr, *args, **kwargs)
|
| 161 |
+
|
| 162 |
+
self.bind_out(f'{addr}:{port}')
|
| 163 |
+
|
| 164 |
+
return port
|
| 165 |
+
|
| 166 |
+
def connect_out(self, addr: str):
|
| 167 |
+
"""Enqueue ZMQ address for connecting on out_socket.
|
| 168 |
+
|
| 169 |
+
See zmq.Socket.connect for details.
|
| 170 |
+
"""
|
| 171 |
+
self._out_connects.append(addr)
|
| 172 |
+
|
| 173 |
+
def setsockopt_out(self, opt: int, value: Any):
|
| 174 |
+
"""Enqueue setsockopt(opt, value) for out_socket
|
| 175 |
+
|
| 176 |
+
See zmq.Socket.setsockopt for details.
|
| 177 |
+
"""
|
| 178 |
+
self._out_sockopts.append((opt, value))
|
| 179 |
+
|
| 180 |
+
def _reserve_random_port(self, addr: str, *args, **kwargs) -> int:
|
| 181 |
+
with Context() as ctx:
|
| 182 |
+
with ctx.socket(PUSH) as binder:
|
| 183 |
+
for i in range(5):
|
| 184 |
+
port = binder.bind_to_random_port(addr, *args, **kwargs)
|
| 185 |
+
|
| 186 |
+
new_addr = f'{addr}:{port}'
|
| 187 |
+
|
| 188 |
+
if new_addr in self._random_addrs:
|
| 189 |
+
continue
|
| 190 |
+
else:
|
| 191 |
+
break
|
| 192 |
+
else:
|
| 193 |
+
raise ZMQBindError("Could not reserve random port.")
|
| 194 |
+
|
| 195 |
+
self._random_addrs.append(new_addr)
|
| 196 |
+
|
| 197 |
+
return port
|
| 198 |
+
|
| 199 |
+
def _setup_sockets(self) -> Tuple[zmq.Socket, zmq.Socket]:
|
| 200 |
+
ctx: zmq.Context[zmq.Socket] = self.context_factory() # type: ignore
|
| 201 |
+
self._context = ctx
|
| 202 |
+
|
| 203 |
+
# create the sockets
|
| 204 |
+
ins = ctx.socket(self.in_type)
|
| 205 |
+
self._sockets.append(ins)
|
| 206 |
+
if self.out_type < 0:
|
| 207 |
+
outs = ins
|
| 208 |
+
else:
|
| 209 |
+
outs = ctx.socket(self.out_type)
|
| 210 |
+
self._sockets.append(outs)
|
| 211 |
+
|
| 212 |
+
# set sockopts (must be done first, in case of zmq.IDENTITY)
|
| 213 |
+
for opt, value in self._in_sockopts:
|
| 214 |
+
ins.setsockopt(opt, value)
|
| 215 |
+
for opt, value in self._out_sockopts:
|
| 216 |
+
outs.setsockopt(opt, value)
|
| 217 |
+
|
| 218 |
+
for iface in self._in_binds:
|
| 219 |
+
ins.bind(iface)
|
| 220 |
+
for iface in self._out_binds:
|
| 221 |
+
outs.bind(iface)
|
| 222 |
+
|
| 223 |
+
for iface in self._in_connects:
|
| 224 |
+
ins.connect(iface)
|
| 225 |
+
for iface in self._out_connects:
|
| 226 |
+
outs.connect(iface)
|
| 227 |
+
|
| 228 |
+
return ins, outs
|
| 229 |
+
|
| 230 |
+
def run_device(self) -> None:
|
| 231 |
+
"""The runner method.
|
| 232 |
+
|
| 233 |
+
Do not call me directly, instead call ``self.start()``, just like a Thread.
|
| 234 |
+
"""
|
| 235 |
+
ins, outs = self._setup_sockets()
|
| 236 |
+
device(self.device_type, ins, outs)
|
| 237 |
+
|
| 238 |
+
def _close_sockets(self):
|
| 239 |
+
"""Cleanup sockets we created"""
|
| 240 |
+
for s in self._sockets:
|
| 241 |
+
if s and not s.closed:
|
| 242 |
+
s.close()
|
| 243 |
+
|
| 244 |
+
def run(self) -> None:
|
| 245 |
+
"""wrap run_device in try/catch ETERM"""
|
| 246 |
+
try:
|
| 247 |
+
self.run_device()
|
| 248 |
+
except ZMQError as e:
|
| 249 |
+
if e.errno in {ETERM, ENOTSOCK}:
|
| 250 |
+
# silence TERM, ENOTSOCK errors, because this should be a clean shutdown
|
| 251 |
+
pass
|
| 252 |
+
else:
|
| 253 |
+
raise
|
| 254 |
+
finally:
|
| 255 |
+
self.done = True
|
| 256 |
+
self._close_sockets()
|
| 257 |
+
|
| 258 |
+
def start(self) -> None:
|
| 259 |
+
"""Start the device. Override me in subclass for other launchers."""
|
| 260 |
+
return self.run()
|
| 261 |
+
|
| 262 |
+
def join(self, timeout: Optional[float] = None) -> None:
|
| 263 |
+
"""wait for me to finish, like Thread.join.
|
| 264 |
+
|
| 265 |
+
Reimplemented appropriately by subclasses."""
|
| 266 |
+
tic = time.monotonic()
|
| 267 |
+
toc = tic
|
| 268 |
+
while not self.done and not (timeout is not None and toc - tic > timeout):
|
| 269 |
+
time.sleep(0.001)
|
| 270 |
+
toc = time.monotonic()
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
class BackgroundDevice(Device):
|
| 274 |
+
"""Base class for launching Devices in background processes and threads."""
|
| 275 |
+
|
| 276 |
+
launcher: Any = None
|
| 277 |
+
_launch_class: Any = None
|
| 278 |
+
|
| 279 |
+
def start(self) -> None:
|
| 280 |
+
self.launcher = self._launch_class(target=self.run)
|
| 281 |
+
self.launcher.daemon = self.daemon
|
| 282 |
+
return self.launcher.start()
|
| 283 |
+
|
| 284 |
+
def join(self, timeout: Optional[float] = None) -> None:
|
| 285 |
+
return self.launcher.join(timeout=timeout)
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
class ThreadDevice(BackgroundDevice):
|
| 289 |
+
"""A Device that will be run in a background Thread.
|
| 290 |
+
|
| 291 |
+
See Device for details.
|
| 292 |
+
"""
|
| 293 |
+
|
| 294 |
+
_launch_class = Thread
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
class ProcessDevice(BackgroundDevice):
|
| 298 |
+
"""A Device that will be run in a background Process.
|
| 299 |
+
|
| 300 |
+
See Device for details.
|
| 301 |
+
"""
|
| 302 |
+
|
| 303 |
+
_launch_class = Process
|
| 304 |
+
context_factory = Context
|
| 305 |
+
"""Callable that returns a context. Typically either Context.instance or Context,
|
| 306 |
+
depending on whether the device should share the global instance or not.
|
| 307 |
+
"""
|
| 308 |
+
|
| 309 |
+
|
| 310 |
+
__all__ = ['Device', 'ThreadDevice', 'ProcessDevice']
|
.venv/lib/python3.11/site-packages/zmq/devices/monitoredqueue.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""pure Python monitored_queue function
|
| 2 |
+
|
| 3 |
+
For use when Cython extension is unavailable (PyPy).
|
| 4 |
+
|
| 5 |
+
Authors
|
| 6 |
+
-------
|
| 7 |
+
* MinRK
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
# Copyright (C) PyZMQ Developers
|
| 11 |
+
# Distributed under the terms of the Modified BSD License.
|
| 12 |
+
|
| 13 |
+
from typing import Callable
|
| 14 |
+
|
| 15 |
+
import zmq
|
| 16 |
+
from zmq.backend import monitored_queue as _backend_mq
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def _relay(ins, outs, sides, prefix, swap_ids):
|
| 20 |
+
msg = ins.recv_multipart()
|
| 21 |
+
if swap_ids:
|
| 22 |
+
msg[:2] = msg[:2][::-1]
|
| 23 |
+
outs.send_multipart(msg)
|
| 24 |
+
sides.send_multipart([prefix] + msg)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def _monitored_queue(
|
| 28 |
+
in_socket, out_socket, mon_socket, in_prefix=b'in', out_prefix=b'out'
|
| 29 |
+
):
|
| 30 |
+
swap_ids = in_socket.type == zmq.ROUTER and out_socket.type == zmq.ROUTER
|
| 31 |
+
|
| 32 |
+
poller = zmq.Poller()
|
| 33 |
+
poller.register(in_socket, zmq.POLLIN)
|
| 34 |
+
poller.register(out_socket, zmq.POLLIN)
|
| 35 |
+
while True:
|
| 36 |
+
events = dict(poller.poll())
|
| 37 |
+
if in_socket in events:
|
| 38 |
+
_relay(in_socket, out_socket, mon_socket, in_prefix, swap_ids)
|
| 39 |
+
if out_socket in events:
|
| 40 |
+
_relay(out_socket, in_socket, mon_socket, out_prefix, swap_ids)
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
monitored_queue: Callable
|
| 44 |
+
if _backend_mq is not None:
|
| 45 |
+
monitored_queue = _backend_mq # type: ignore
|
| 46 |
+
else:
|
| 47 |
+
# backend has no monitored_queue
|
| 48 |
+
monitored_queue = _monitored_queue
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
__all__ = ['monitored_queue']
|
.venv/lib/python3.11/site-packages/zmq/devices/monitoredqueuedevice.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""MonitoredQueue classes and functions."""
|
| 2 |
+
|
| 3 |
+
# Copyright (C) PyZMQ Developers
|
| 4 |
+
# Distributed under the terms of the Modified BSD License.
|
| 5 |
+
|
| 6 |
+
from zmq import PUB
|
| 7 |
+
from zmq.devices.monitoredqueue import monitored_queue
|
| 8 |
+
from zmq.devices.proxydevice import ProcessProxy, Proxy, ProxyBase, ThreadProxy
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class MonitoredQueueBase(ProxyBase):
|
| 12 |
+
"""Base class for overriding methods."""
|
| 13 |
+
|
| 14 |
+
_in_prefix = b''
|
| 15 |
+
_out_prefix = b''
|
| 16 |
+
|
| 17 |
+
def __init__(
|
| 18 |
+
self, in_type, out_type, mon_type=PUB, in_prefix=b'in', out_prefix=b'out'
|
| 19 |
+
):
|
| 20 |
+
ProxyBase.__init__(self, in_type=in_type, out_type=out_type, mon_type=mon_type)
|
| 21 |
+
|
| 22 |
+
self._in_prefix = in_prefix
|
| 23 |
+
self._out_prefix = out_prefix
|
| 24 |
+
|
| 25 |
+
def run_device(self):
|
| 26 |
+
ins, outs, mons = self._setup_sockets()
|
| 27 |
+
monitored_queue(ins, outs, mons, self._in_prefix, self._out_prefix)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class MonitoredQueue(MonitoredQueueBase, Proxy):
|
| 31 |
+
"""Class for running monitored_queue in the background.
|
| 32 |
+
|
| 33 |
+
See zmq.devices.Device for most of the spec. MonitoredQueue differs from Proxy,
|
| 34 |
+
only in that it adds a ``prefix`` to messages sent on the monitor socket,
|
| 35 |
+
with a different prefix for each direction.
|
| 36 |
+
|
| 37 |
+
MQ also supports ROUTER on both sides, which zmq.proxy does not.
|
| 38 |
+
|
| 39 |
+
If a message arrives on `in_sock`, it will be prefixed with `in_prefix` on the monitor socket.
|
| 40 |
+
If it arrives on out_sock, it will be prefixed with `out_prefix`.
|
| 41 |
+
|
| 42 |
+
A PUB socket is the most logical choice for the mon_socket, but it is not required.
|
| 43 |
+
"""
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class ThreadMonitoredQueue(MonitoredQueueBase, ThreadProxy):
|
| 47 |
+
"""Run zmq.monitored_queue in a background thread.
|
| 48 |
+
|
| 49 |
+
See MonitoredQueue and Proxy for details.
|
| 50 |
+
"""
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class ProcessMonitoredQueue(MonitoredQueueBase, ProcessProxy):
|
| 54 |
+
"""Run zmq.monitored_queue in a separate process.
|
| 55 |
+
|
| 56 |
+
See MonitoredQueue and Proxy for details.
|
| 57 |
+
"""
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
__all__ = ['MonitoredQueue', 'ThreadMonitoredQueue', 'ProcessMonitoredQueue']
|
.venv/lib/python3.11/site-packages/zmq/devices/proxydevice.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Proxy classes and functions."""
|
| 2 |
+
|
| 3 |
+
# Copyright (C) PyZMQ Developers
|
| 4 |
+
# Distributed under the terms of the Modified BSD License.
|
| 5 |
+
|
| 6 |
+
import zmq
|
| 7 |
+
from zmq.devices.basedevice import Device, ProcessDevice, ThreadDevice
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class ProxyBase:
|
| 11 |
+
"""Base class for overriding methods."""
|
| 12 |
+
|
| 13 |
+
def __init__(self, in_type, out_type, mon_type=zmq.PUB):
|
| 14 |
+
Device.__init__(self, in_type=in_type, out_type=out_type)
|
| 15 |
+
self.mon_type = mon_type
|
| 16 |
+
self._mon_binds = []
|
| 17 |
+
self._mon_connects = []
|
| 18 |
+
self._mon_sockopts = []
|
| 19 |
+
|
| 20 |
+
def bind_mon(self, addr):
|
| 21 |
+
"""Enqueue ZMQ address for binding on mon_socket.
|
| 22 |
+
|
| 23 |
+
See zmq.Socket.bind for details.
|
| 24 |
+
"""
|
| 25 |
+
self._mon_binds.append(addr)
|
| 26 |
+
|
| 27 |
+
def bind_mon_to_random_port(self, addr, *args, **kwargs):
|
| 28 |
+
"""Enqueue a random port on the given interface for binding on
|
| 29 |
+
mon_socket.
|
| 30 |
+
|
| 31 |
+
See zmq.Socket.bind_to_random_port for details.
|
| 32 |
+
|
| 33 |
+
.. versionadded:: 18.0
|
| 34 |
+
"""
|
| 35 |
+
port = self._reserve_random_port(addr, *args, **kwargs)
|
| 36 |
+
|
| 37 |
+
self.bind_mon(f'{addr}:{port}')
|
| 38 |
+
|
| 39 |
+
return port
|
| 40 |
+
|
| 41 |
+
def connect_mon(self, addr):
|
| 42 |
+
"""Enqueue ZMQ address for connecting on mon_socket.
|
| 43 |
+
|
| 44 |
+
See zmq.Socket.connect for details.
|
| 45 |
+
"""
|
| 46 |
+
self._mon_connects.append(addr)
|
| 47 |
+
|
| 48 |
+
def setsockopt_mon(self, opt, value):
|
| 49 |
+
"""Enqueue setsockopt(opt, value) for mon_socket
|
| 50 |
+
|
| 51 |
+
See zmq.Socket.setsockopt for details.
|
| 52 |
+
"""
|
| 53 |
+
self._mon_sockopts.append((opt, value))
|
| 54 |
+
|
| 55 |
+
def _setup_sockets(self):
|
| 56 |
+
ins, outs = Device._setup_sockets(self)
|
| 57 |
+
ctx = self._context
|
| 58 |
+
mons = ctx.socket(self.mon_type)
|
| 59 |
+
self._sockets.append(mons)
|
| 60 |
+
|
| 61 |
+
# set sockopts (must be done first, in case of zmq.IDENTITY)
|
| 62 |
+
for opt, value in self._mon_sockopts:
|
| 63 |
+
mons.setsockopt(opt, value)
|
| 64 |
+
|
| 65 |
+
for iface in self._mon_binds:
|
| 66 |
+
mons.bind(iface)
|
| 67 |
+
|
| 68 |
+
for iface in self._mon_connects:
|
| 69 |
+
mons.connect(iface)
|
| 70 |
+
|
| 71 |
+
return ins, outs, mons
|
| 72 |
+
|
| 73 |
+
def run_device(self):
|
| 74 |
+
ins, outs, mons = self._setup_sockets()
|
| 75 |
+
zmq.proxy(ins, outs, mons)
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
class Proxy(ProxyBase, Device):
|
| 79 |
+
"""Threadsafe Proxy object.
|
| 80 |
+
|
| 81 |
+
See zmq.devices.Device for most of the spec. This subclass adds a
|
| 82 |
+
<method>_mon version of each <method>_{in|out} method, for configuring the
|
| 83 |
+
monitor socket.
|
| 84 |
+
|
| 85 |
+
A Proxy is a 3-socket ZMQ Device that functions just like a
|
| 86 |
+
QUEUE, except each message is also sent out on the monitor socket.
|
| 87 |
+
|
| 88 |
+
A PUB socket is the most logical choice for the mon_socket, but it is not required.
|
| 89 |
+
"""
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
class ThreadProxy(ProxyBase, ThreadDevice):
|
| 93 |
+
"""Proxy in a Thread. See Proxy for more."""
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
class ProcessProxy(ProxyBase, ProcessDevice):
|
| 97 |
+
"""Proxy in a Process. See Proxy for more."""
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
__all__ = [
|
| 101 |
+
'Proxy',
|
| 102 |
+
'ThreadProxy',
|
| 103 |
+
'ProcessProxy',
|
| 104 |
+
]
|
.venv/lib/python3.11/site-packages/zmq/devices/proxysteerabledevice.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Classes for running a steerable ZMQ proxy"""
|
| 2 |
+
|
| 3 |
+
# Copyright (C) PyZMQ Developers
|
| 4 |
+
# Distributed under the terms of the Modified BSD License.
|
| 5 |
+
|
| 6 |
+
import zmq
|
| 7 |
+
from zmq.devices.proxydevice import ProcessProxy, Proxy, ThreadProxy
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class ProxySteerableBase:
|
| 11 |
+
"""Base class for overriding methods."""
|
| 12 |
+
|
| 13 |
+
def __init__(self, in_type, out_type, mon_type=zmq.PUB, ctrl_type=None):
|
| 14 |
+
super().__init__(in_type=in_type, out_type=out_type, mon_type=mon_type)
|
| 15 |
+
self.ctrl_type = ctrl_type
|
| 16 |
+
self._ctrl_binds = []
|
| 17 |
+
self._ctrl_connects = []
|
| 18 |
+
self._ctrl_sockopts = []
|
| 19 |
+
|
| 20 |
+
def bind_ctrl(self, addr):
|
| 21 |
+
"""Enqueue ZMQ address for binding on ctrl_socket.
|
| 22 |
+
|
| 23 |
+
See zmq.Socket.bind for details.
|
| 24 |
+
"""
|
| 25 |
+
self._ctrl_binds.append(addr)
|
| 26 |
+
|
| 27 |
+
def bind_ctrl_to_random_port(self, addr, *args, **kwargs):
|
| 28 |
+
"""Enqueue a random port on the given interface for binding on
|
| 29 |
+
ctrl_socket.
|
| 30 |
+
|
| 31 |
+
See zmq.Socket.bind_to_random_port for details.
|
| 32 |
+
"""
|
| 33 |
+
port = self._reserve_random_port(addr, *args, **kwargs)
|
| 34 |
+
|
| 35 |
+
self.bind_ctrl(f'{addr}:{port}')
|
| 36 |
+
|
| 37 |
+
return port
|
| 38 |
+
|
| 39 |
+
def connect_ctrl(self, addr):
|
| 40 |
+
"""Enqueue ZMQ address for connecting on ctrl_socket.
|
| 41 |
+
|
| 42 |
+
See zmq.Socket.connect for details.
|
| 43 |
+
"""
|
| 44 |
+
self._ctrl_connects.append(addr)
|
| 45 |
+
|
| 46 |
+
def setsockopt_ctrl(self, opt, value):
|
| 47 |
+
"""Enqueue setsockopt(opt, value) for ctrl_socket
|
| 48 |
+
|
| 49 |
+
See zmq.Socket.setsockopt for details.
|
| 50 |
+
"""
|
| 51 |
+
self._ctrl_sockopts.append((opt, value))
|
| 52 |
+
|
| 53 |
+
def _setup_sockets(self):
|
| 54 |
+
ins, outs, mons = super()._setup_sockets()
|
| 55 |
+
ctx = self._context
|
| 56 |
+
ctrls = ctx.socket(self.ctrl_type)
|
| 57 |
+
self._sockets.append(ctrls)
|
| 58 |
+
|
| 59 |
+
for opt, value in self._ctrl_sockopts:
|
| 60 |
+
ctrls.setsockopt(opt, value)
|
| 61 |
+
|
| 62 |
+
for iface in self._ctrl_binds:
|
| 63 |
+
ctrls.bind(iface)
|
| 64 |
+
|
| 65 |
+
for iface in self._ctrl_connects:
|
| 66 |
+
ctrls.connect(iface)
|
| 67 |
+
|
| 68 |
+
return ins, outs, mons, ctrls
|
| 69 |
+
|
| 70 |
+
def run_device(self):
|
| 71 |
+
ins, outs, mons, ctrls = self._setup_sockets()
|
| 72 |
+
zmq.proxy_steerable(ins, outs, mons, ctrls)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class ProxySteerable(ProxySteerableBase, Proxy):
|
| 76 |
+
"""Class for running a steerable proxy in the background.
|
| 77 |
+
|
| 78 |
+
See zmq.devices.Proxy for most of the spec. If the control socket is not
|
| 79 |
+
NULL, the proxy supports control flow, provided by the socket.
|
| 80 |
+
|
| 81 |
+
If PAUSE is received on this socket, the proxy suspends its activities. If
|
| 82 |
+
RESUME is received, it goes on. If TERMINATE is received, it terminates
|
| 83 |
+
smoothly. If the control socket is NULL, the proxy behave exactly as if
|
| 84 |
+
zmq.devices.Proxy had been used.
|
| 85 |
+
|
| 86 |
+
This subclass adds a <method>_ctrl version of each <method>_{in|out}
|
| 87 |
+
method, for configuring the control socket.
|
| 88 |
+
|
| 89 |
+
.. versionadded:: libzmq-4.1
|
| 90 |
+
.. versionadded:: 18.0
|
| 91 |
+
"""
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
class ThreadProxySteerable(ProxySteerableBase, ThreadProxy):
|
| 95 |
+
"""ProxySteerable in a Thread. See ProxySteerable for details."""
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
class ProcessProxySteerable(ProxySteerableBase, ProcessProxy):
|
| 99 |
+
"""ProxySteerable in a Process. See ProxySteerable for details."""
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
__all__ = [
|
| 103 |
+
'ProxySteerable',
|
| 104 |
+
'ThreadProxySteerable',
|
| 105 |
+
'ProcessProxySteerable',
|
| 106 |
+
]
|
.venv/lib/python3.11/site-packages/zmq/log/__init__.py
ADDED
|
File without changes
|
.venv/lib/python3.11/site-packages/zmq/log/__main__.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""pyzmq log watcher.
|
| 2 |
+
|
| 3 |
+
Easily view log messages published by the PUBHandler in zmq.log.handlers
|
| 4 |
+
|
| 5 |
+
Designed to be run as an executable module - try this to see options:
|
| 6 |
+
python -m zmq.log -h
|
| 7 |
+
|
| 8 |
+
Subscribes to the '' (empty string) topic by default which means it will work
|
| 9 |
+
out-of-the-box with a PUBHandler object instantiated with default settings.
|
| 10 |
+
If you change the root topic with PUBHandler.setRootTopic() you must pass
|
| 11 |
+
the value to this script with the --topic argument.
|
| 12 |
+
|
| 13 |
+
Note that the default formats for the PUBHandler object selectively include
|
| 14 |
+
the log level in the message. This creates redundancy in this script as it
|
| 15 |
+
always prints the topic of the message, which includes the log level.
|
| 16 |
+
Consider overriding the default formats with PUBHandler.setFormat() to
|
| 17 |
+
avoid this issue.
|
| 18 |
+
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
# encoding: utf-8
|
| 22 |
+
|
| 23 |
+
# Copyright (C) PyZMQ Developers
|
| 24 |
+
# Distributed under the terms of the Modified BSD License.
|
| 25 |
+
|
| 26 |
+
import argparse
|
| 27 |
+
from datetime import datetime
|
| 28 |
+
from typing import Dict
|
| 29 |
+
|
| 30 |
+
import zmq
|
| 31 |
+
|
| 32 |
+
parser = argparse.ArgumentParser('ZMQ Log Watcher')
|
| 33 |
+
parser.add_argument('zmq_pub_url', type=str, help='URL to a ZMQ publisher socket.')
|
| 34 |
+
parser.add_argument(
|
| 35 |
+
'-t',
|
| 36 |
+
'--topic',
|
| 37 |
+
type=str,
|
| 38 |
+
default='',
|
| 39 |
+
help='Only receive messages that start with this topic.',
|
| 40 |
+
)
|
| 41 |
+
parser.add_argument(
|
| 42 |
+
'--timestamp', action='store_true', help='Append local time to the log messages.'
|
| 43 |
+
)
|
| 44 |
+
parser.add_argument(
|
| 45 |
+
'--separator',
|
| 46 |
+
type=str,
|
| 47 |
+
default=' | ',
|
| 48 |
+
help='String to print between topic and message.',
|
| 49 |
+
)
|
| 50 |
+
parser.add_argument(
|
| 51 |
+
'--dateformat',
|
| 52 |
+
type=str,
|
| 53 |
+
default='%Y-%d-%m %H:%M',
|
| 54 |
+
help='Set alternative date format for use with --timestamp.',
|
| 55 |
+
)
|
| 56 |
+
parser.add_argument(
|
| 57 |
+
'--align',
|
| 58 |
+
action='store_true',
|
| 59 |
+
default=False,
|
| 60 |
+
help='Try to align messages by the width of their topics.',
|
| 61 |
+
)
|
| 62 |
+
parser.add_argument(
|
| 63 |
+
'--color',
|
| 64 |
+
action='store_true',
|
| 65 |
+
default=False,
|
| 66 |
+
help='Color the output based on the error level. Requires the colorama module.',
|
| 67 |
+
)
|
| 68 |
+
args = parser.parse_args()
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
if args.color:
|
| 72 |
+
import colorama
|
| 73 |
+
|
| 74 |
+
colorama.init()
|
| 75 |
+
colors = {
|
| 76 |
+
'DEBUG': colorama.Fore.LIGHTCYAN_EX,
|
| 77 |
+
'INFO': colorama.Fore.LIGHTWHITE_EX,
|
| 78 |
+
'WARNING': colorama.Fore.YELLOW,
|
| 79 |
+
'ERROR': colorama.Fore.LIGHTRED_EX,
|
| 80 |
+
'CRITICAL': colorama.Fore.LIGHTRED_EX,
|
| 81 |
+
'__RESET__': colorama.Fore.RESET,
|
| 82 |
+
}
|
| 83 |
+
else:
|
| 84 |
+
colors = {}
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
ctx = zmq.Context()
|
| 88 |
+
sub = ctx.socket(zmq.SUB)
|
| 89 |
+
sub.subscribe(args.topic.encode("utf8"))
|
| 90 |
+
sub.connect(args.zmq_pub_url)
|
| 91 |
+
|
| 92 |
+
topic_widths: Dict[int, int] = {}
|
| 93 |
+
|
| 94 |
+
while True:
|
| 95 |
+
try:
|
| 96 |
+
if sub.poll(10, zmq.POLLIN):
|
| 97 |
+
topic, msg = sub.recv_multipart()
|
| 98 |
+
topics = topic.decode('utf8').strip().split('.')
|
| 99 |
+
|
| 100 |
+
if args.align:
|
| 101 |
+
topics.extend(' ' for extra in range(len(topics), len(topic_widths)))
|
| 102 |
+
aligned_parts = []
|
| 103 |
+
for key, part in enumerate(topics):
|
| 104 |
+
topic_widths[key] = max(len(part), topic_widths.get(key, 0))
|
| 105 |
+
fmt = ''.join(('{:<', str(topic_widths[key]), '}'))
|
| 106 |
+
aligned_parts.append(fmt.format(part))
|
| 107 |
+
|
| 108 |
+
if len(topics) == 1:
|
| 109 |
+
level = topics[0]
|
| 110 |
+
else:
|
| 111 |
+
level = topics[1]
|
| 112 |
+
|
| 113 |
+
fields = {
|
| 114 |
+
'msg': msg.decode('utf8').strip(),
|
| 115 |
+
'ts': (
|
| 116 |
+
datetime.now().strftime(args.dateformat) + ' '
|
| 117 |
+
if args.timestamp
|
| 118 |
+
else ''
|
| 119 |
+
),
|
| 120 |
+
'aligned': (
|
| 121 |
+
'.'.join(aligned_parts)
|
| 122 |
+
if args.align
|
| 123 |
+
else topic.decode('utf8').strip()
|
| 124 |
+
),
|
| 125 |
+
'color': colors.get(level, ''),
|
| 126 |
+
'color_rst': colors.get('__RESET__', ''),
|
| 127 |
+
'sep': args.separator,
|
| 128 |
+
}
|
| 129 |
+
print('{ts}{color}{aligned}{sep}{msg}{color_rst}'.format(**fields))
|
| 130 |
+
except KeyboardInterrupt:
|
| 131 |
+
break
|
| 132 |
+
|
| 133 |
+
sub.disconnect(args.zmq_pub_url)
|
| 134 |
+
if args.color:
|
| 135 |
+
print(colorama.Fore.RESET)
|
.venv/lib/python3.11/site-packages/zmq/log/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (180 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/log/__pycache__/__main__.cpython-311.pyc
ADDED
|
Binary file (5.98 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/log/__pycache__/handlers.cpython-311.pyc
ADDED
|
Binary file (9.73 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/zmq/log/handlers.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""pyzmq logging handlers.
|
| 2 |
+
|
| 3 |
+
This mainly defines the PUBHandler object for publishing logging messages over
|
| 4 |
+
a zmq.PUB socket.
|
| 5 |
+
|
| 6 |
+
The PUBHandler can be used with the regular logging module, as in::
|
| 7 |
+
|
| 8 |
+
>>> import logging
|
| 9 |
+
>>> handler = PUBHandler('tcp://127.0.0.1:12345')
|
| 10 |
+
>>> handler.root_topic = 'foo'
|
| 11 |
+
>>> logger = logging.getLogger('foobar')
|
| 12 |
+
>>> logger.setLevel(logging.DEBUG)
|
| 13 |
+
>>> logger.addHandler(handler)
|
| 14 |
+
|
| 15 |
+
Or using ``dictConfig``, as in::
|
| 16 |
+
|
| 17 |
+
>>> from logging.config import dictConfig
|
| 18 |
+
>>> socket = Context.instance().socket(PUB)
|
| 19 |
+
>>> socket.connect('tcp://127.0.0.1:12345')
|
| 20 |
+
>>> dictConfig({
|
| 21 |
+
>>> 'version': 1,
|
| 22 |
+
>>> 'handlers': {
|
| 23 |
+
>>> 'zmq': {
|
| 24 |
+
>>> 'class': 'zmq.log.handlers.PUBHandler',
|
| 25 |
+
>>> 'level': logging.DEBUG,
|
| 26 |
+
>>> 'root_topic': 'foo',
|
| 27 |
+
>>> 'interface_or_socket': socket
|
| 28 |
+
>>> }
|
| 29 |
+
>>> },
|
| 30 |
+
>>> 'root': {
|
| 31 |
+
>>> 'level': 'DEBUG',
|
| 32 |
+
>>> 'handlers': ['zmq'],
|
| 33 |
+
>>> }
|
| 34 |
+
>>> })
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
After this point, all messages logged by ``logger`` will be published on the
|
| 38 |
+
PUB socket.
|
| 39 |
+
|
| 40 |
+
Code adapted from StarCluster:
|
| 41 |
+
|
| 42 |
+
https://github.com/jtriley/StarCluster/blob/StarCluster-0.91/starcluster/logger.py
|
| 43 |
+
"""
|
| 44 |
+
|
| 45 |
+
from __future__ import annotations
|
| 46 |
+
|
| 47 |
+
import logging
|
| 48 |
+
from copy import copy
|
| 49 |
+
|
| 50 |
+
import zmq
|
| 51 |
+
|
| 52 |
+
# Copyright (C) PyZMQ Developers
|
| 53 |
+
# Distributed under the terms of the Modified BSD License.
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
TOPIC_DELIM = "::" # delimiter for splitting topics on the receiving end.
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class PUBHandler(logging.Handler):
|
| 60 |
+
"""A basic logging handler that emits log messages through a PUB socket.
|
| 61 |
+
|
| 62 |
+
Takes a PUB socket already bound to interfaces or an interface to bind to.
|
| 63 |
+
|
| 64 |
+
Example::
|
| 65 |
+
|
| 66 |
+
sock = context.socket(zmq.PUB)
|
| 67 |
+
sock.bind('inproc://log')
|
| 68 |
+
handler = PUBHandler(sock)
|
| 69 |
+
|
| 70 |
+
Or::
|
| 71 |
+
|
| 72 |
+
handler = PUBHandler('inproc://loc')
|
| 73 |
+
|
| 74 |
+
These are equivalent.
|
| 75 |
+
|
| 76 |
+
Log messages handled by this handler are broadcast with ZMQ topics
|
| 77 |
+
``this.root_topic`` comes first, followed by the log level
|
| 78 |
+
(DEBUG,INFO,etc.), followed by any additional subtopics specified in the
|
| 79 |
+
message by: log.debug("subtopic.subsub::the real message")
|
| 80 |
+
"""
|
| 81 |
+
|
| 82 |
+
ctx: zmq.Context
|
| 83 |
+
socket: zmq.Socket
|
| 84 |
+
|
| 85 |
+
def __init__(
|
| 86 |
+
self,
|
| 87 |
+
interface_or_socket: str | zmq.Socket,
|
| 88 |
+
context: zmq.Context | None = None,
|
| 89 |
+
root_topic: str = '',
|
| 90 |
+
) -> None:
|
| 91 |
+
logging.Handler.__init__(self)
|
| 92 |
+
self.root_topic = root_topic
|
| 93 |
+
self.formatters = {
|
| 94 |
+
logging.DEBUG: logging.Formatter(
|
| 95 |
+
"%(levelname)s %(filename)s:%(lineno)d - %(message)s\n"
|
| 96 |
+
),
|
| 97 |
+
logging.INFO: logging.Formatter("%(message)s\n"),
|
| 98 |
+
logging.WARN: logging.Formatter(
|
| 99 |
+
"%(levelname)s %(filename)s:%(lineno)d - %(message)s\n"
|
| 100 |
+
),
|
| 101 |
+
logging.ERROR: logging.Formatter(
|
| 102 |
+
"%(levelname)s %(filename)s:%(lineno)d - %(message)s - %(exc_info)s\n"
|
| 103 |
+
),
|
| 104 |
+
logging.CRITICAL: logging.Formatter(
|
| 105 |
+
"%(levelname)s %(filename)s:%(lineno)d - %(message)s\n"
|
| 106 |
+
),
|
| 107 |
+
}
|
| 108 |
+
if isinstance(interface_or_socket, zmq.Socket):
|
| 109 |
+
self.socket = interface_or_socket
|
| 110 |
+
self.ctx = self.socket.context
|
| 111 |
+
else:
|
| 112 |
+
self.ctx = context or zmq.Context()
|
| 113 |
+
self.socket = self.ctx.socket(zmq.PUB)
|
| 114 |
+
self.socket.bind(interface_or_socket)
|
| 115 |
+
|
| 116 |
+
@property
|
| 117 |
+
def root_topic(self) -> str:
|
| 118 |
+
return self._root_topic
|
| 119 |
+
|
| 120 |
+
@root_topic.setter
|
| 121 |
+
def root_topic(self, value: str):
|
| 122 |
+
self.setRootTopic(value)
|
| 123 |
+
|
| 124 |
+
def setRootTopic(self, root_topic: str):
|
| 125 |
+
"""Set the root topic for this handler.
|
| 126 |
+
|
| 127 |
+
This value is prepended to all messages published by this handler, and it
|
| 128 |
+
defaults to the empty string ''. When you subscribe to this socket, you must
|
| 129 |
+
set your subscription to an empty string, or to at least the first letter of
|
| 130 |
+
the binary representation of this string to ensure you receive any messages
|
| 131 |
+
from this handler.
|
| 132 |
+
|
| 133 |
+
If you use the default empty string root topic, messages will begin with
|
| 134 |
+
the binary representation of the log level string (INFO, WARN, etc.).
|
| 135 |
+
Note that ZMQ SUB sockets can have multiple subscriptions.
|
| 136 |
+
"""
|
| 137 |
+
if isinstance(root_topic, bytes):
|
| 138 |
+
root_topic = root_topic.decode("utf8")
|
| 139 |
+
self._root_topic = root_topic
|
| 140 |
+
|
| 141 |
+
def setFormatter(self, fmt, level=logging.NOTSET):
|
| 142 |
+
"""Set the Formatter for this handler.
|
| 143 |
+
|
| 144 |
+
If no level is provided, the same format is used for all levels. This
|
| 145 |
+
will overwrite all selective formatters set in the object constructor.
|
| 146 |
+
"""
|
| 147 |
+
if level == logging.NOTSET:
|
| 148 |
+
for fmt_level in self.formatters.keys():
|
| 149 |
+
self.formatters[fmt_level] = fmt
|
| 150 |
+
else:
|
| 151 |
+
self.formatters[level] = fmt
|
| 152 |
+
|
| 153 |
+
def format(self, record):
|
| 154 |
+
"""Format a record."""
|
| 155 |
+
return self.formatters[record.levelno].format(record)
|
| 156 |
+
|
| 157 |
+
def emit(self, record):
|
| 158 |
+
"""Emit a log message on my socket."""
|
| 159 |
+
|
| 160 |
+
# LogRecord.getMessage explicitly allows msg to be anything _castable_ to a str
|
| 161 |
+
try:
|
| 162 |
+
topic, msg = str(record.msg).split(TOPIC_DELIM, 1)
|
| 163 |
+
except ValueError:
|
| 164 |
+
topic = ""
|
| 165 |
+
else:
|
| 166 |
+
# copy to avoid mutating LogRecord in-place
|
| 167 |
+
record = copy(record)
|
| 168 |
+
record.msg = msg
|
| 169 |
+
|
| 170 |
+
try:
|
| 171 |
+
bmsg = self.format(record).encode("utf8")
|
| 172 |
+
except Exception:
|
| 173 |
+
self.handleError(record)
|
| 174 |
+
return
|
| 175 |
+
|
| 176 |
+
topic_list = []
|
| 177 |
+
|
| 178 |
+
if self.root_topic:
|
| 179 |
+
topic_list.append(self.root_topic)
|
| 180 |
+
|
| 181 |
+
topic_list.append(record.levelname)
|
| 182 |
+
|
| 183 |
+
if topic:
|
| 184 |
+
topic_list.append(topic)
|
| 185 |
+
|
| 186 |
+
btopic = '.'.join(topic_list).encode("utf8", "replace")
|
| 187 |
+
|
| 188 |
+
self.socket.send_multipart([btopic, bmsg])
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
class TopicLogger(logging.Logger):
|
| 192 |
+
"""A simple wrapper that takes an additional argument to log methods.
|
| 193 |
+
|
| 194 |
+
All the regular methods exist, but instead of one msg argument, two
|
| 195 |
+
arguments: topic, msg are passed.
|
| 196 |
+
|
| 197 |
+
That is::
|
| 198 |
+
|
| 199 |
+
logger.debug('msg')
|
| 200 |
+
|
| 201 |
+
Would become::
|
| 202 |
+
|
| 203 |
+
logger.debug('topic.sub', 'msg')
|
| 204 |
+
"""
|
| 205 |
+
|
| 206 |
+
def log(self, level, topic, msg, *args, **kwargs):
|
| 207 |
+
"""Log 'msg % args' with level and topic.
|
| 208 |
+
|
| 209 |
+
To pass exception information, use the keyword argument exc_info
|
| 210 |
+
with a True value::
|
| 211 |
+
|
| 212 |
+
logger.log(level, "zmq.fun", "We have a %s",
|
| 213 |
+
"mysterious problem", exc_info=1)
|
| 214 |
+
"""
|
| 215 |
+
logging.Logger.log(self, level, f'{topic}{TOPIC_DELIM}{msg}', *args, **kwargs)
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
# Generate the methods of TopicLogger, since they are just adding a
|
| 219 |
+
# topic prefix to a message.
|
| 220 |
+
for name in "debug warn warning error critical fatal".split():
|
| 221 |
+
try:
|
| 222 |
+
meth = getattr(logging.Logger, name)
|
| 223 |
+
except AttributeError:
|
| 224 |
+
# some methods are missing, e.g. Logger.warn was removed from Python 3.13
|
| 225 |
+
continue
|
| 226 |
+
setattr(
|
| 227 |
+
TopicLogger,
|
| 228 |
+
name,
|
| 229 |
+
lambda self, level, topic, msg, *args, **kwargs: meth(
|
| 230 |
+
self, level, topic + TOPIC_DELIM + msg, *args, **kwargs
|
| 231 |
+
),
|
| 232 |
+
)
|