first comit

This commit is contained in:
2024-02-23 10:30:02 +00:00
commit ddeb07d0ba
12482 changed files with 1857507 additions and 0 deletions

View File

@@ -0,0 +1,234 @@
"""Python version-independent methods for C/Python buffers.
This file was copied and adapted from mpi4py.
Authors
-------
* MinRK
"""
#-----------------------------------------------------------------------------
# Copyright (c) 2010 Lisandro Dalcin
# All rights reserved.
# Used under BSD License: http://www.opensource.org/licenses/bsd-license.php
#
# Retrieval:
# Jul 23, 2010 18:00 PST (r539)
# http://code.google.com/p/mpi4py/source/browse/trunk/src/MPI/asbuffer.pxi
#
# Modifications from original:
# Copyright (c) 2010-2012 Brian Granger, Min Ragan-Kelley
#
# Distributed under the terms of the New BSD License. The full license is in
# the file LICENSE.BSD, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Python includes.
#-----------------------------------------------------------------------------
# get version-independent aliases:
cdef extern from "pyversion_compat.h":
pass
# Python 3 buffer interface (PEP 3118)
cdef extern from "Python.h":
int PY_MAJOR_VERSION
int PY_MINOR_VERSION
ctypedef int Py_ssize_t
ctypedef struct PyMemoryViewObject:
pass
ctypedef struct Py_buffer:
void *buf
Py_ssize_t len
int readonly
char *format
int ndim
Py_ssize_t *shape
Py_ssize_t *strides
Py_ssize_t *suboffsets
Py_ssize_t itemsize
void *internal
cdef enum:
PyBUF_SIMPLE
PyBUF_WRITABLE
PyBUF_FORMAT
PyBUF_ANY_CONTIGUOUS
int PyObject_CheckBuffer(object)
int PyObject_GetBuffer(object, Py_buffer *, int) except -1
void PyBuffer_Release(Py_buffer *)
int PyBuffer_FillInfo(Py_buffer *view, object obj, void *buf,
Py_ssize_t len, int readonly, int infoflags) except -1
object PyMemoryView_FromBuffer(Py_buffer *info)
object PyMemoryView_FromObject(object)
#-----------------------------------------------------------------------------
# asbuffer: C buffer from python object
#-----------------------------------------------------------------------------
cdef inline int check_buffer(object ob):
"""Version independent check for whether an object is a buffer.
Parameters
----------
object : object
Any Python object
Returns
-------
int : 0 if no buffer interface, 3 if newstyle buffer interface, 2 if oldstyle (removed).
"""
if PyObject_CheckBuffer(ob):
return 3
return 0
cdef inline object asbuffer(object ob, int writable, int format,
void **base, Py_ssize_t *size,
Py_ssize_t *itemsize):
"""Turn an object into a C buffer in a Python version-independent way.
Parameters
----------
ob : object
The object to be turned into a buffer.
Must provide a Python Buffer interface
writable : int
Whether the resulting buffer should be allowed to write
to the object.
format : int
The format of the buffer. See Python buffer docs.
base : void **
The pointer that will be used to store the resulting C buffer.
size : Py_ssize_t *
The size of the buffer(s).
itemsize : Py_ssize_t *
The size of an item, if the buffer is non-contiguous.
Returns
-------
An object describing the buffer format. Generally a str, such as 'B'.
"""
cdef void *bptr = NULL
cdef Py_ssize_t blen = 0, bitemlen = 0
cdef Py_buffer view
cdef int flags = PyBUF_SIMPLE
cdef int mode = 0
bfmt = None
mode = check_buffer(ob)
if mode == 0:
raise TypeError("%r does not provide a buffer interface."%ob)
if mode == 3:
flags = PyBUF_ANY_CONTIGUOUS
if writable:
flags |= PyBUF_WRITABLE
if format:
flags |= PyBUF_FORMAT
PyObject_GetBuffer(ob, &view, flags)
bptr = view.buf
blen = view.len
if format:
if view.format != NULL:
bfmt = view.format
bitemlen = view.itemsize
PyBuffer_Release(&view)
if base: base[0] = <void *>bptr
if size: size[0] = <Py_ssize_t>blen
if itemsize: itemsize[0] = <Py_ssize_t>bitemlen
if bfmt is not None:
return bfmt.decode('ascii')
return bfmt
cdef inline object asbuffer_r(object ob, void **base, Py_ssize_t *size):
"""Wrapper for standard calls to asbuffer with a readonly buffer."""
asbuffer(ob, 0, 0, base, size, NULL)
return ob
cdef inline object asbuffer_w(object ob, void **base, Py_ssize_t *size):
"""Wrapper for standard calls to asbuffer with a writable buffer."""
asbuffer(ob, 1, 0, base, size, NULL)
return ob
#------------------------------------------------------------------------------
# frombuffer: python buffer/view from C buffer
#------------------------------------------------------------------------------
cdef inline object frombuffer(void *ptr, Py_ssize_t s, int readonly):
"""Create a Python Memory View of a C array.
Parameters
----------
ptr : void *
Pointer to the array to be copied.
s : size_t
Length of the buffer.
readonly : int
whether the resulting object should be allowed to write to the buffer.
Returns
-------
Python Memory View of the C buffer.
"""
cdef Py_buffer pybuf
cdef Py_ssize_t *shape = [s]
cdef str astr=""
PyBuffer_FillInfo(&pybuf, astr, ptr, s, readonly, PyBUF_SIMPLE)
pybuf.format = "B"
pybuf.shape = shape
pybuf.ndim = 1
return PyMemoryView_FromBuffer(&pybuf)
cdef inline object frombuffer_r(void *ptr, Py_ssize_t s):
"""Wrapper for readonly view frombuffer."""
return frombuffer(ptr, s, 1)
cdef inline object frombuffer_w(void *ptr, Py_ssize_t s):
"""Wrapper for writable view frombuffer."""
return frombuffer(ptr, s, 0)
#------------------------------------------------------------------------------
# viewfromobject: python buffer/view from python object, refcounts intact
# frombuffer(asbuffer(obj)) would lose track of refs
#------------------------------------------------------------------------------
cdef inline object viewfromobject(object obj, int readonly):
"""Construct a Python Memory View object from another Python object.
Parameters
----------
obj : object
The input object to be cast as a buffer
readonly : int
Whether the result should be prevented from overwriting the original.
Returns
-------
MemoryView of the original object.
"""
return PyMemoryView_FromObject(obj)
cdef inline object viewfromobject_r(object obj):
"""Wrapper for readonly viewfromobject."""
return viewfromobject(obj, 1)
cdef inline object viewfromobject_w(object obj):
"""Wrapper for writable viewfromobject."""
return viewfromobject(obj, 0)

View File

@@ -0,0 +1,22 @@
{
"libraries": [
"zmq"
],
"include_dirs": [
"/usr/local/include",
"zmq/utils"
],
"library_dirs": [
"/usr/local/lib"
],
"runtime_library_dirs": [
"/usr/local/lib"
],
"extra_link_args": [],
"define_macros": [
[
"HAVE_SYS_UN_H",
1
]
]
}

View File

@@ -0,0 +1,13 @@
{
"zmq_prefix": "/usr/local",
"zmq_draft_api": false,
"libzmq_extension": false,
"no_libzmq_extension": true,
"skip_check_zmq": false,
"allow_legacy_libzmq": true,
"bundle_msvcp": null,
"build_ext": {},
"bdist_egg": {},
"win_ver": null,
"have_sys_un_h": true
}

View File

@@ -0,0 +1,214 @@
"""Garbage collection thread for representing zmq refcount of Python objects
used in zero-copy sends.
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import atexit
import struct
import warnings
from collections import namedtuple
from os import getpid
from threading import Event, Lock, Thread
import zmq
gcref = namedtuple('gcref', ['obj', 'event'])
class GarbageCollectorThread(Thread):
"""Thread in which garbage collection actually happens."""
def __init__(self, gc):
super().__init__()
self.gc = gc
self.daemon = True
self.pid = getpid()
self.ready = Event()
def run(self):
# detect fork at beginning of the thread
if getpid is None or getpid() != self.pid:
self.ready.set()
return
try:
s = self.gc.context.socket(zmq.PULL)
s.linger = 0
s.bind(self.gc.url)
finally:
self.ready.set()
while True:
# detect fork
if getpid is None or getpid() != self.pid:
return
msg = s.recv()
if msg == b'DIE':
break
fmt = 'L' if len(msg) == 4 else 'Q'
key = struct.unpack(fmt, msg)[0]
tup = self.gc.refs.pop(key, None)
if tup and tup.event:
tup.event.set()
del tup
s.close()
class GarbageCollector:
"""PyZMQ Garbage Collector
Used for representing the reference held by libzmq during zero-copy sends.
This object holds a dictionary, keyed by Python id,
of the Python objects whose memory are currently in use by zeromq.
When zeromq is done with the memory, it sends a message on an inproc PUSH socket
containing the packed size_t (32 or 64-bit unsigned int),
which is the key in the dict.
When the PULL socket in the gc thread receives that message,
the reference is popped from the dict,
and any tracker events that should be signaled fire.
"""
refs = None
_context = None
_lock = None
url = "inproc://pyzmq.gc.01"
def __init__(self, context=None):
super().__init__()
self.refs = {}
self.pid = None
self.thread = None
self._context = context
self._lock = Lock()
self._stay_down = False
self._push = None
self._push_mutex = None
atexit.register(self._atexit)
@property
def context(self):
if self._context is None:
if Thread.__module__.startswith('gevent'):
# gevent has monkey-patched Thread, use green Context
from zmq import green
self._context = green.Context()
else:
self._context = zmq.Context()
return self._context
@context.setter
def context(self, ctx):
if self.is_alive():
if self.refs:
warnings.warn(
"Replacing gc context while gc is running", RuntimeWarning
)
self.stop()
self._context = ctx
def _atexit(self):
"""atexit callback
sets _stay_down flag so that gc doesn't try to start up again in other atexit handlers
"""
self._stay_down = True
self.stop()
def stop(self):
"""stop the garbage-collection thread"""
if not self.is_alive():
return
self._stop()
def _clear(self):
"""Clear state
called after stop or when setting up a new subprocess
"""
self._push = None
self._push_mutex = None
self.thread = None
self.refs.clear()
self.context = None
def _stop(self):
push = self.context.socket(zmq.PUSH)
push.connect(self.url)
push.send(b'DIE')
push.close()
if self._push:
self._push.close()
self.thread.join()
self.context.term()
self._clear()
@property
def _push_socket(self):
"""The PUSH socket for use in the zmq message destructor callback."""
if getattr(self, "_stay_down", False):
raise RuntimeError("zmq gc socket requested during shutdown")
if not self.is_alive() or self._push is None:
self._push = self.context.socket(zmq.PUSH)
self._push.connect(self.url)
return self._push
def start(self):
"""Start a new garbage collection thread.
Creates a new zmq Context used for garbage collection.
Under most circumstances, this will only be called once per process.
"""
if self.thread is not None and self.pid != getpid():
# It's re-starting, must free earlier thread's context
# since a fork probably broke it
self._clear()
self.pid = getpid()
self.refs = {}
self.thread = GarbageCollectorThread(self)
self.thread.start()
self.thread.ready.wait()
def is_alive(self):
"""Is the garbage collection thread currently running?
Includes checks for process shutdown or fork.
"""
if (
getpid is None
or getpid() != self.pid
or self.thread is None
or not self.thread.is_alive()
):
return False
return True
def store(self, obj, event=None):
"""store an object and (optionally) event for zero-copy"""
if not self.is_alive():
if self._stay_down:
return 0
# safely start the gc thread
# use lock and double check,
# so we don't start multiple threads
with self._lock:
if not self.is_alive():
self.start()
tup = gcref(obj, event)
theid = id(tup)
self.refs[theid] = tup
return theid
def __del__(self):
if not self.is_alive():
return
try:
self.stop()
except Exception as e:
raise (e)
gc = GarbageCollector()

View File

@@ -0,0 +1,7 @@
#pragma once
#ifdef _WIN32
#include <process.h>
#define getpid _getpid
#else
#include <unistd.h>
#endif

View File

@@ -0,0 +1,29 @@
"""Utils for interoperability with other libraries.
Just CFFI pointer casting for now.
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from typing import Any
def cast_int_addr(n: Any) -> int:
"""Cast an address to a Python int
This could be a Python integer or a CFFI pointer
"""
if isinstance(n, int):
return n
try:
import cffi # type: ignore
except ImportError:
pass
else:
# from pyzmq, this is an FFI void *
ffi = cffi.FFI()
if isinstance(n, ffi.CData):
return int(ffi.cast("size_t", n))
raise ValueError("Cannot cast %r to int" % n)

View File

@@ -0,0 +1,27 @@
/*
Platform-independant detection of IPC path max length
Copyright (c) 2012 Godefroid Chapelle
Distributed under the terms of the New BSD License. The full license is in
the file LICENSE.BSD, distributed as part of this software.
*/
#pragma once
#if defined(HAVE_SYS_UN_H)
#if defined _MSC_VER
#include <afunix.h>
#else
#include <sys/un.h>
#endif
int get_ipc_path_max_len(void) {
struct sockaddr_un *dummy;
return sizeof(dummy->sun_path) - 1;
}
#else
int get_ipc_path_max_len(void) {
return 0;
}
#endif

View File

@@ -0,0 +1,37 @@
"""JSON serialize to/from utf8 bytes
.. versionchanged:: 22.2
Remove optional imports of different JSON implementations.
Now that we require recent Python, unconditionally use the standard library.
Custom JSON libraries can be used via custom serialization functions.
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import json
from typing import Any, Dict, List, Union
# backward-compatibility, unused
jsonmod = json
def dumps(o: Any, **kwargs) -> bytes:
"""Serialize object to JSON bytes (utf-8).
Keyword arguments are passed along to :py:func:`json.dumps`.
"""
return json.dumps(o, **kwargs).encode("utf8")
def loads(s: Union[bytes, str], **kwargs) -> Union[Dict, List, str, int, float]:
"""Load object from JSON bytes (utf-8).
Keyword arguments are passed along to :py:func:`json.loads`.
"""
if isinstance(s, bytes):
s = s.decode("utf8")
return json.loads(s, **kwargs)
__all__ = ['dumps', 'loads']

View File

@@ -0,0 +1,126 @@
"""Module holding utility and convenience functions for zmq event monitoring."""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import struct
from typing import Awaitable, List, Union, overload
import zmq
import zmq.asyncio
from zmq._typing import TypedDict
from zmq.error import _check_version
class _MonitorMessage(TypedDict):
event: int
value: int
endpoint: bytes
def parse_monitor_message(msg: List[bytes]) -> _MonitorMessage:
"""decode zmq_monitor event messages.
Parameters
----------
msg : list(bytes)
zmq multipart message that has arrived on a monitor PAIR socket.
First frame is::
16 bit event id
32 bit event value
no padding
Second frame is the endpoint as a bytestring
Returns
-------
event : dict
event description as dict with the keys `event`, `value`, and `endpoint`.
"""
if len(msg) != 2 or len(msg[0]) != 6:
raise RuntimeError("Invalid event message format: %s" % msg)
event_id, value = struct.unpack("=hi", msg[0])
event: _MonitorMessage = {
'event': zmq.Event(event_id),
'value': zmq.Event(value),
'endpoint': msg[1],
}
return event
async def _parse_monitor_msg_async(
awaitable_msg: Awaitable[List[bytes]],
) -> _MonitorMessage:
"""Like parse_monitor_msg, but awaitable
Given awaitable message, return awaitable for the parsed monitor message.
"""
msg = await awaitable_msg
# 4.0-style event API
return parse_monitor_message(msg)
@overload
def recv_monitor_message(
socket: "zmq.asyncio.Socket",
flags: int = 0,
) -> Awaitable[_MonitorMessage]:
...
@overload
def recv_monitor_message(
socket: zmq.Socket[bytes],
flags: int = 0,
) -> _MonitorMessage:
...
def recv_monitor_message(
socket: zmq.Socket,
flags: int = 0,
) -> Union[_MonitorMessage, Awaitable[_MonitorMessage]]:
"""Receive and decode the given raw message from the monitoring socket and return a dict.
Requires libzmq ≥ 4.0
The returned dict will have the following entries:
event : int, the event id as described in libzmq.zmq_socket_monitor
value : int, the event value associated with the event, see libzmq.zmq_socket_monitor
endpoint : string, the affected endpoint
.. versionchanged:: 23.1
Support for async sockets added.
When called with a async socket,
returns an awaitable for the monitor message.
Parameters
----------
socket : zmq PAIR socket
The PAIR socket (created by other.get_monitor_socket()) on which to recv the message
flags : bitfield (int)
standard zmq recv flags
Returns
-------
event : dict
event description as dict with the keys `event`, `value`, and `endpoint`.
"""
_check_version((4, 0), 'libzmq event API')
# will always return a list
msg = socket.recv_multipart(flags)
# transparently handle asyncio socket,
# returns a Future instead of a dict
if isinstance(msg, Awaitable):
return _parse_monitor_msg_async(msg)
# 4.0-style event API
return parse_monitor_message(msg)
__all__ = ['parse_monitor_message', 'recv_monitor_message']

View File

@@ -0,0 +1,82 @@
/*
* simplified from mutex.c from Foundation Library, in the Public Domain
* https://github.com/rampantpixels/foundation_lib/blob/master/foundation/mutex.c
*
* This file is Copyright (C) PyZMQ Developers
* Distributed under the terms of the Modified BSD License.
*
*/
#pragma once
#if defined(_WIN32)
# include <windows.h>
#else
# include <pthread.h>
#endif
typedef struct {
#if defined(_WIN32)
CRITICAL_SECTION csection;
#else
pthread_mutex_t mutex;
#endif
} mutex_t;
static void
_mutex_initialize(mutex_t* mutex) {
#if defined(_WIN32)
InitializeCriticalSectionAndSpinCount(&mutex->csection, 4000);
#else
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex->mutex, &attr);
pthread_mutexattr_destroy(&attr);
#endif
}
static void
_mutex_finalize(mutex_t* mutex) {
#if defined(_WIN32)
DeleteCriticalSection(&mutex->csection);
#else
pthread_mutex_destroy(&mutex->mutex);
#endif
}
mutex_t*
mutex_allocate(void) {
mutex_t* mutex = (mutex_t*)malloc(sizeof(mutex_t));
_mutex_initialize(mutex);
return mutex;
}
void
mutex_deallocate(mutex_t* mutex) {
if (!mutex)
return;
_mutex_finalize(mutex);
free(mutex);
}
int
mutex_lock(mutex_t* mutex) {
#if defined(_WIN32)
EnterCriticalSection(&mutex->csection);
return 0;
#else
return pthread_mutex_lock(&mutex->mutex);
#endif
}
int
mutex_unlock(mutex_t* mutex) {
#if defined(_WIN32)
LeaveCriticalSection(&mutex->csection);
return 0;
#else
return pthread_mutex_unlock(&mutex->mutex);
#endif
}

View File

@@ -0,0 +1,12 @@
#include "Python.h"
// default to Python's own target Windows version(s)
// override by setting WINVER, _WIN32_WINNT, (maybe also NTDDI_VERSION?) macros
#ifdef Py_WINVER
#ifndef WINVER
#define WINVER Py_WINVER
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT Py_WINVER
#endif
#endif

View File

@@ -0,0 +1,62 @@
"""Declare basic string types unambiguously for various Python versions.
Authors
-------
* MinRK
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import warnings
bytes = bytes
unicode = str
basestring = (str,)
def cast_bytes(s, encoding='utf8', errors='strict'):
"""cast unicode or bytes to bytes"""
warnings.warn(
"zmq.utils.strtypes is deprecated in pyzmq 23.",
DeprecationWarning,
stacklevel=2,
)
if isinstance(s, bytes):
return s
elif isinstance(s, str):
return s.encode(encoding, errors)
else:
raise TypeError("Expected unicode or bytes, got %r" % s)
def cast_unicode(s, encoding='utf8', errors='strict'):
"""cast bytes or unicode to unicode"""
warnings.warn(
"zmq.utils.strtypes is deprecated in pyzmq 23.",
DeprecationWarning,
stacklevel=2,
)
if isinstance(s, bytes):
return s.decode(encoding, errors)
elif isinstance(s, str):
return s
else:
raise TypeError("Expected unicode or bytes, got %r" % s)
# give short 'b' alias for cast_bytes, so that we can use fake b'stuff'
# to simulate b'stuff'
b = asbytes = cast_bytes
u = cast_unicode
__all__ = [
'asbytes',
'bytes',
'unicode',
'basestring',
'b',
'u',
'cast_bytes',
'cast_unicode',
]

View File

@@ -0,0 +1,126 @@
"""Win32 compatibility utilities."""
# -----------------------------------------------------------------------------
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
# -----------------------------------------------------------------------------
import os
from typing import Any, Callable, Optional
class allow_interrupt:
"""Utility for fixing CTRL-C events on Windows.
On Windows, the Python interpreter intercepts CTRL-C events in order to
translate them into ``KeyboardInterrupt`` exceptions. It (presumably)
does this by setting a flag in its "console control handler" and
checking it later at a convenient location in the interpreter.
However, when the Python interpreter is blocked waiting for the ZMQ
poll operation to complete, it must wait for ZMQ's ``select()``
operation to complete before translating the CTRL-C event into the
``KeyboardInterrupt`` exception.
The only way to fix this seems to be to add our own "console control
handler" and perform some application-defined operation that will
unblock the ZMQ polling operation in order to force ZMQ to pass control
back to the Python interpreter.
This context manager performs all that Windows-y stuff, providing you
with a hook that is called when a CTRL-C event is intercepted. This
hook allows you to unblock your ZMQ poll operation immediately, which
will then result in the expected ``KeyboardInterrupt`` exception.
Without this context manager, your ZMQ-based application will not
respond normally to CTRL-C events on Windows. If a CTRL-C event occurs
while blocked on ZMQ socket polling, the translation to a
``KeyboardInterrupt`` exception will be delayed until the I/O completes
and control returns to the Python interpreter (this may never happen if
you use an infinite timeout).
A no-op implementation is provided on non-Win32 systems to avoid the
application from having to conditionally use it.
Example usage:
.. sourcecode:: python
def stop_my_application():
# ...
with allow_interrupt(stop_my_application):
# main polling loop.
In a typical ZMQ application, you would use the "self pipe trick" to
send message to a ``PAIR`` socket in order to interrupt your blocking
socket polling operation.
In a Tornado event loop, you can use the ``IOLoop.stop`` method to
unblock your I/O loop.
"""
def __init__(self, action: Optional[Callable[[], Any]] = None) -> None:
"""Translate ``action`` into a CTRL-C handler.
``action`` is a callable that takes no arguments and returns no
value (returned value is ignored). It must *NEVER* raise an
exception.
If unspecified, a no-op will be used.
"""
if os.name != "nt":
return
self._init_action(action)
def _init_action(self, action):
from ctypes import WINFUNCTYPE, windll
from ctypes.wintypes import BOOL, DWORD
kernel32 = windll.LoadLibrary('kernel32')
# <http://msdn.microsoft.com/en-us/library/ms686016.aspx>
PHANDLER_ROUTINE = WINFUNCTYPE(BOOL, DWORD)
SetConsoleCtrlHandler = (
self._SetConsoleCtrlHandler
) = kernel32.SetConsoleCtrlHandler
SetConsoleCtrlHandler.argtypes = (PHANDLER_ROUTINE, BOOL)
SetConsoleCtrlHandler.restype = BOOL
if action is None:
action = lambda: None
self.action = action
@PHANDLER_ROUTINE
def handle(event):
if event == 0: # CTRL_C_EVENT
action()
# Typical C implementations would return 1 to indicate that
# the event was processed and other control handlers in the
# stack should not be executed. However, that would
# prevent the Python interpreter's handler from translating
# CTRL-C to a `KeyboardInterrupt` exception, so we pretend
# that we didn't handle it.
return 0
self.handle = handle
def __enter__(self):
"""Install the custom CTRL-C handler."""
if os.name != "nt":
return
result = self._SetConsoleCtrlHandler(self.handle, 1)
if result == 0:
# Have standard library automatically call `GetLastError()` and
# `FormatMessage()` into a nice exception object :-)
raise OSError()
def __exit__(self, *args):
"""Remove the custom CTRL-C handler."""
if os.name != "nt":
return
result = self._SetConsoleCtrlHandler(self.handle, 0)
if result == 0:
# Have standard library automatically call `GetLastError()` and
# `FormatMessage()` into a nice exception object :-)
raise OSError()

View File

@@ -0,0 +1,58 @@
"""Python implementation of Z85 85-bit encoding
Z85 encoding is a plaintext encoding for a bytestring interpreted as 32bit integers.
Since the chunks are 32bit, a bytestring must be a multiple of 4 bytes.
See ZMQ RFC 32 for details.
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import struct
# Z85CHARS is the base 85 symbol table
Z85CHARS = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#"
# Z85MAP maps integers in [0,84] to the appropriate character in Z85CHARS
Z85MAP = {c: idx for idx, c in enumerate(Z85CHARS)}
_85s = [85**i for i in range(5)][::-1]
def encode(rawbytes):
"""encode raw bytes into Z85"""
# Accepts only byte arrays bounded to 4 bytes
if len(rawbytes) % 4:
raise ValueError("length must be multiple of 4, not %i" % len(rawbytes))
nvalues = len(rawbytes) / 4
values = struct.unpack('>%dI' % nvalues, rawbytes)
encoded = []
for v in values:
for offset in _85s:
encoded.append(Z85CHARS[(v // offset) % 85])
return bytes(encoded)
def decode(z85bytes):
"""decode Z85 bytes to raw bytes, accepts ASCII string"""
if isinstance(z85bytes, str):
try:
z85bytes = z85bytes.encode('ascii')
except UnicodeEncodeError:
raise ValueError('string argument should contain only ASCII characters')
if len(z85bytes) % 5:
raise ValueError("Z85 length must be multiple of 5, not %i" % len(z85bytes))
nvalues = len(z85bytes) / 5
values = []
for i in range(0, len(z85bytes), 5):
value = 0
for j, offset in enumerate(_85s):
value += Z85MAP[z85bytes[i + j]] * offset
values.append(value)
return struct.pack('>%dI' % nvalues, *values)

View File

@@ -0,0 +1,112 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2010 Brian Granger, Min Ragan-Kelley
//
// Distributed under the terms of the New BSD License. The full license is in
// the file LICENSE.BSD, distributed as part of this software.
//-----------------------------------------------------------------------------
#pragma once
#if defined(_MSC_VER)
#define pyzmq_int64_t __int64
#define pyzmq_uint32_t unsigned __int32
#else
#include <stdint.h>
#define pyzmq_int64_t int64_t
#define pyzmq_uint32_t uint32_t
#endif
#include "zmq.h"
#define _missing (-1)
#if (ZMQ_VERSION >= 40303)
// libzmq >= 4.3.3 defines zmq_fd_t for us
#define ZMQ_FD_T zmq_fd_t
#else
#ifdef _WIN32
#if defined(_MSC_VER) && _MSC_VER <= 1400
#define ZMQ_FD_T UINT_PTR
#else
#define ZMQ_FD_T SOCKET
#endif
#else
#define ZMQ_FD_T int
#endif
#endif
#if (ZMQ_VERSION >= 40200)
// Nothing to remove
#else
#define zmq_curve_public(z85_public_key, z85_secret_key) _missing
#endif
// use unambiguous aliases for zmq_send/recv functions
#if ZMQ_VERSION_MAJOR >= 4
// nothing to remove
#if ZMQ_VERSION_MAJOR == 4 && ZMQ_VERSION_MINOR == 0
// zmq 4.1 deprecates zmq_utils.h
// we only get zmq_curve_keypair from it
#include "zmq_utils.h"
#endif
#else
#define zmq_curve_keypair(z85_public_key, z85_secret_key) _missing
#endif
// libzmq 4.2 draft API
#ifdef ZMQ_BUILD_DRAFT_API
#if ZMQ_VERSION >= 40200
#define PYZMQ_DRAFT_42
#endif
#endif
#ifndef PYZMQ_DRAFT_42
#define zmq_join(s, group) _missing
#define zmq_leave(s, group) _missing
#define zmq_msg_set_routing_id(msg, routing_id) _missing
#define zmq_msg_routing_id(msg) 0
#define zmq_msg_set_group(msg, group) _missing
#define zmq_msg_group(msg) NULL
#endif
#if ZMQ_VERSION >= 40100
// nothing to remove
#else
#define zmq_msg_gets(msg, prop) _missing
#define zmq_has(capability) _missing
#define zmq_proxy_steerable(in, out, mon, ctrl) _missing
#endif
#if ZMQ_VERSION_MAJOR >= 3
#define zmq_sendbuf zmq_send
#define zmq_recvbuf zmq_recv
// 3.x deprecations - these symbols haven't been removed,
// but let's protect against their planned removal
#define zmq_device(device_type, isocket, osocket) _missing
#define zmq_init(io_threads) ((void*)NULL)
#define zmq_term zmq_ctx_destroy
#else
#define zmq_ctx_set(ctx, opt, val) _missing
#define zmq_ctx_get(ctx, opt) _missing
#define zmq_ctx_destroy zmq_term
#define zmq_ctx_new() ((void*)NULL)
#define zmq_proxy(a,b,c) _missing
#define zmq_disconnect(s, addr) _missing
#define zmq_unbind(s, addr) _missing
#define zmq_msg_more(msg) _missing
#define zmq_msg_get(msg, opt) _missing
#define zmq_msg_set(msg, opt, val) _missing
#define zmq_msg_send(msg, s, flags) zmq_send(s, msg, flags)
#define zmq_msg_recv(msg, s, flags) zmq_recv(s, msg, flags)
#define zmq_sendbuf(s, buf, len, flags) _missing
#define zmq_recvbuf(s, buf, len, flags) _missing
#define zmq_socket_monitor(s, addr, flags) _missing
#endif