forked from pool/python-eventlet
- Do not generate sphinx docu, it is online and now we have only
python3 Sphinx anyway - Update to 0.25.0: * Support for new python and ssl - Remove patches that are in upstream release: * 0001-IMPORTANT-late-import-in-use_hub-thread-race-caused-.patch * 0001-ssl-connect-used-non-monotonic-time.time-for-timeout.patch * 0002-Fix-for-Python-3.7-506.patch * 0003-Fix-compatibility-with-Python-3.7-ssl.SSLSocket-531.patch OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-eventlet?expand=0&rev=60
This commit is contained in:
committed by
Git OBS Bridge
parent
82c5a213c9
commit
4dd14d9320
@@ -1,717 +0,0 @@
|
|||||||
From 77bccbe48d4d9a46982b2e0503e76784e76b066a Mon Sep 17 00:00:00 2001
|
|
||||||
From: Sergey Shepelev <temotor@gmail.com>
|
|
||||||
Date: Sun, 2 Sep 2018 01:38:23 +0500
|
|
||||||
Subject: [PATCH] IMPORTANT: late import in `use_hub()` + thread race caused
|
|
||||||
using epolls even when it is unsupported on current platform
|
|
||||||
|
|
||||||
Solution: eager import all built-in hubs, explicitly check support later
|
|
||||||
|
|
||||||
https://github.com/eventlet/eventlet/issues/466
|
|
||||||
---
|
|
||||||
eventlet/hubs/__init__.py | 103 +++++++++++------------
|
|
||||||
eventlet/hubs/epolls.py | 39 +++------
|
|
||||||
eventlet/hubs/hub.py | 5 +-
|
|
||||||
eventlet/hubs/kqueue.py | 34 ++++----
|
|
||||||
eventlet/hubs/poll.py | 38 +++++----
|
|
||||||
eventlet/hubs/pyevent.py | 10 ++-
|
|
||||||
eventlet/hubs/selects.py | 38 +++++----
|
|
||||||
eventlet/hubs/timer.py | 6 +-
|
|
||||||
tests/hub_test.py | 56 ++----------
|
|
||||||
tests/isolated/hub_kqueue_unsupported.py | 28 ++++++
|
|
||||||
tests/isolated/hub_use_hub_class.py | 13 +++
|
|
||||||
11 files changed, 182 insertions(+), 188 deletions(-)
|
|
||||||
create mode 100644 tests/isolated/hub_kqueue_unsupported.py
|
|
||||||
create mode 100644 tests/isolated/hub_use_hub_class.py
|
|
||||||
|
|
||||||
diff --git a/eventlet/hubs/__init__.py b/eventlet/hubs/__init__.py
|
|
||||||
index fc5d3f3..867628c 100644
|
|
||||||
--- a/eventlet/hubs/__init__.py
|
|
||||||
+++ b/eventlet/hubs/__init__.py
|
|
||||||
@@ -1,4 +1,7 @@
|
|
||||||
+import importlib
|
|
||||||
+import inspect
|
|
||||||
import os
|
|
||||||
+import warnings
|
|
||||||
|
|
||||||
from eventlet import patcher
|
|
||||||
from eventlet.support import greenlets as greenlet
|
|
||||||
@@ -11,6 +14,15 @@ threading = patcher.original('threading')
|
|
||||||
_threadlocal = threading.local()
|
|
||||||
|
|
||||||
|
|
||||||
+# order is important, get_default_hub returns first available from here
|
|
||||||
+builtin_hub_names = ('epolls', 'kqueue', 'poll', 'selects')
|
|
||||||
+builtin_hub_modules = tuple(importlib.import_module('eventlet.hubs.' + name) for name in builtin_hub_names)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class HubError(Exception):
|
|
||||||
+ pass
|
|
||||||
+
|
|
||||||
+
|
|
||||||
def get_default_hub():
|
|
||||||
"""Select the default hub implementation based on what multiplexing
|
|
||||||
libraries are installed. The order that the hubs are tried is:
|
|
||||||
@@ -26,44 +38,33 @@ def get_default_hub():
|
|
||||||
.. include:: ../doc/common.txt
|
|
||||||
.. note :: |internal|
|
|
||||||
"""
|
|
||||||
+ for mod in builtin_hub_modules:
|
|
||||||
+ if mod.is_available():
|
|
||||||
+ return mod
|
|
||||||
|
|
||||||
- # pyevent hub disabled for now because it is not thread-safe
|
|
||||||
- # try:
|
|
||||||
- # import eventlet.hubs.pyevent
|
|
||||||
- # return eventlet.hubs.pyevent
|
|
||||||
- # except:
|
|
||||||
- # pass
|
|
||||||
-
|
|
||||||
- select = patcher.original('select')
|
|
||||||
- try:
|
|
||||||
- import eventlet.hubs.epolls
|
|
||||||
- return eventlet.hubs.epolls
|
|
||||||
- except ImportError:
|
|
||||||
- try:
|
|
||||||
- import eventlet.hubs.kqueue
|
|
||||||
- return eventlet.hubs.kqueue
|
|
||||||
- except ImportError:
|
|
||||||
- if hasattr(select, 'poll'):
|
|
||||||
- import eventlet.hubs.poll
|
|
||||||
- return eventlet.hubs.poll
|
|
||||||
- else:
|
|
||||||
- import eventlet.hubs.selects
|
|
||||||
- return eventlet.hubs.selects
|
|
||||||
+ raise HubError('no built-in hubs are available: {}'.format(builtin_hub_modules))
|
|
||||||
|
|
||||||
|
|
||||||
def use_hub(mod=None):
|
|
||||||
"""Use the module *mod*, containing a class called Hub, as the
|
|
||||||
event hub. Usually not required; the default hub is usually fine.
|
|
||||||
|
|
||||||
- Mod can be an actual module, a string, or None. If *mod* is a module,
|
|
||||||
- it uses it directly. If *mod* is a string and contains either '.' or ':'
|
|
||||||
- use_hub tries to import the hub using the 'package.subpackage.module:Class'
|
|
||||||
- convention, otherwise use_hub looks for a matching setuptools entry point
|
|
||||||
- in the 'eventlet.hubs' group to load or finally tries to import
|
|
||||||
- `eventlet.hubs.mod` and use that as the hub module. If *mod* is None,
|
|
||||||
- use_hub uses the default hub. Only call use_hub during application
|
|
||||||
- initialization, because it resets the hub's state and any existing
|
|
||||||
+ `mod` can be an actual hub class, a module, a string, or None.
|
|
||||||
+
|
|
||||||
+ If `mod` is a class, use it directly.
|
|
||||||
+ If `mod` is a module, use `module.Hub` class
|
|
||||||
+ If `mod` is a string and contains either '.' or ':'
|
|
||||||
+ then `use_hub` uses 'package.subpackage.module:Class' convention,
|
|
||||||
+ otherwise imports `eventlet.hubs.mod`.
|
|
||||||
+ If `mod` is None, `use_hub` uses the default hub.
|
|
||||||
+
|
|
||||||
+ Only call use_hub during application initialization,
|
|
||||||
+ because it resets the hub's state and any existing
|
|
||||||
timers or listeners will never be resumed.
|
|
||||||
+
|
|
||||||
+ These two threadlocal attributes are not part of Eventlet public API:
|
|
||||||
+ - `threadlocal.Hub` (capital H) is hub constructor, used when no hub is currently active
|
|
||||||
+ - `threadlocal.hub` (lowercase h) is active hub instance
|
|
||||||
"""
|
|
||||||
if mod is None:
|
|
||||||
mod = os.environ.get('EVENTLET_HUB', None)
|
|
||||||
@@ -71,36 +72,30 @@ def use_hub(mod=None):
|
|
||||||
mod = get_default_hub()
|
|
||||||
if hasattr(_threadlocal, 'hub'):
|
|
||||||
del _threadlocal.hub
|
|
||||||
+
|
|
||||||
+ classname = ''
|
|
||||||
if isinstance(mod, six.string_types):
|
|
||||||
assert mod.strip(), "Need to specify a hub"
|
|
||||||
if '.' in mod or ':' in mod:
|
|
||||||
modulename, _, classname = mod.strip().partition(':')
|
|
||||||
- mod = __import__(modulename, globals(), locals(), [classname])
|
|
||||||
- if classname:
|
|
||||||
- mod = getattr(mod, classname)
|
|
||||||
else:
|
|
||||||
- found = False
|
|
||||||
-
|
|
||||||
- # setuptools 5.4.1 test_import_patched_defaults fail
|
|
||||||
- # https://github.com/eventlet/eventlet/issues/177
|
|
||||||
- try:
|
|
||||||
- # try and import pkg_resources ...
|
|
||||||
- import pkg_resources
|
|
||||||
- except ImportError:
|
|
||||||
- # ... but do not depend on it
|
|
||||||
- pkg_resources = None
|
|
||||||
- if pkg_resources is not None:
|
|
||||||
- for entry in pkg_resources.iter_entry_points(
|
|
||||||
- group='eventlet.hubs', name=mod):
|
|
||||||
- mod, found = entry.load(), True
|
|
||||||
- break
|
|
||||||
- if not found:
|
|
||||||
- mod = __import__(
|
|
||||||
- 'eventlet.hubs.' + mod, globals(), locals(), ['Hub'])
|
|
||||||
- if hasattr(mod, 'Hub'):
|
|
||||||
- _threadlocal.Hub = mod.Hub
|
|
||||||
+ modulename = 'eventlet.hubs.' + mod
|
|
||||||
+ mod = importlib.import_module(modulename)
|
|
||||||
+
|
|
||||||
+ if hasattr(mod, 'is_available'):
|
|
||||||
+ if not mod.is_available():
|
|
||||||
+ raise Exception('selected hub is not available on this system mod={}'.format(mod))
|
|
||||||
else:
|
|
||||||
- _threadlocal.Hub = mod
|
|
||||||
+ msg = '''Please provide `is_available()` function in your custom Eventlet hub {mod}.
|
|
||||||
+It must return bool: whether hub supports current platform. See eventlet/hubs/{{epoll,kqueue}} for example.
|
|
||||||
+'''.format(mod=mod)
|
|
||||||
+ warnings.warn(msg, DeprecationWarning, stacklevel=3)
|
|
||||||
+
|
|
||||||
+ hubclass = mod
|
|
||||||
+ if not inspect.isclass(mod):
|
|
||||||
+ hubclass = getattr(mod, classname or 'Hub')
|
|
||||||
+
|
|
||||||
+ _threadlocal.Hub = hubclass
|
|
||||||
|
|
||||||
|
|
||||||
def get_hub():
|
|
||||||
diff --git a/eventlet/hubs/epolls.py b/eventlet/hubs/epolls.py
|
|
||||||
index c338756..07fec14 100644
|
|
||||||
--- a/eventlet/hubs/epolls.py
|
|
||||||
+++ b/eventlet/hubs/epolls.py
|
|
||||||
@@ -1,40 +1,29 @@
|
|
||||||
import errno
|
|
||||||
-from eventlet.support import get_errno
|
|
||||||
-from eventlet import patcher
|
|
||||||
+from eventlet import patcher, support
|
|
||||||
+from eventlet.hubs import hub, poll
|
|
||||||
select = patcher.original('select')
|
|
||||||
-if not hasattr(select, 'epoll'):
|
|
||||||
- # TODO: remove mention of python-epoll on 2019-01
|
|
||||||
- raise ImportError('No epoll implementation found in select module.'
|
|
||||||
- ' python-epoll (or similar) package support was removed,'
|
|
||||||
- ' please open issue on https://github.com/eventlet/eventlet/'
|
|
||||||
- ' if you must use epoll outside stdlib.')
|
|
||||||
-epoll = select.epoll
|
|
||||||
|
|
||||||
-from eventlet.hubs.hub import BaseHub
|
|
||||||
-from eventlet.hubs import poll
|
|
||||||
-from eventlet.hubs.poll import READ, WRITE
|
|
||||||
|
|
||||||
-# NOTE: we rely on the fact that the epoll flag constants
|
|
||||||
-# are identical in value to the poll constants
|
|
||||||
+def is_available():
|
|
||||||
+ return hasattr(select, 'epoll')
|
|
||||||
|
|
||||||
|
|
||||||
+# NOTE: we rely on the fact that the epoll flag constants
|
|
||||||
+# are identical in value to the poll constants
|
|
||||||
class Hub(poll.Hub):
|
|
||||||
def __init__(self, clock=None):
|
|
||||||
- BaseHub.__init__(self, clock)
|
|
||||||
- self.poll = epoll()
|
|
||||||
+ super(Hub, self).__init__(clock=clock)
|
|
||||||
+ self.poll = select.epoll()
|
|
||||||
|
|
||||||
def add(self, evtype, fileno, cb, tb, mac):
|
|
||||||
- oldlisteners = bool(self.listeners[READ].get(fileno) or
|
|
||||||
- self.listeners[WRITE].get(fileno))
|
|
||||||
- listener = BaseHub.add(self, evtype, fileno, cb, tb, mac)
|
|
||||||
+ oldlisteners = bool(self.listeners[self.READ].get(fileno) or
|
|
||||||
+ self.listeners[self.WRITE].get(fileno))
|
|
||||||
+ # not super() to avoid double register()
|
|
||||||
+ listener = hub.BaseHub.add(self, evtype, fileno, cb, tb, mac)
|
|
||||||
try:
|
|
||||||
- if not oldlisteners:
|
|
||||||
- # Means we've added a new listener
|
|
||||||
- self.register(fileno, new=True)
|
|
||||||
- else:
|
|
||||||
- self.register(fileno, new=False)
|
|
||||||
+ self.register(fileno, new=not oldlisteners)
|
|
||||||
except IOError as ex: # ignore EEXIST, #80
|
|
||||||
- if get_errno(ex) != errno.EEXIST:
|
|
||||||
+ if support.get_errno(ex) != errno.EEXIST:
|
|
||||||
raise
|
|
||||||
return listener
|
|
||||||
|
|
||||||
diff --git a/eventlet/hubs/hub.py b/eventlet/hubs/hub.py
|
|
||||||
index 112f467..8871082 100644
|
|
||||||
--- a/eventlet/hubs/hub.py
|
|
||||||
+++ b/eventlet/hubs/hub.py
|
|
||||||
@@ -19,7 +19,8 @@ else:
|
|
||||||
signal.alarm(math.ceil(seconds))
|
|
||||||
arm_alarm = alarm_signal
|
|
||||||
|
|
||||||
-from eventlet.hubs import timer, IOClosed
|
|
||||||
+import eventlet.hubs
|
|
||||||
+from eventlet.hubs import timer
|
|
||||||
from eventlet.support import greenlets as greenlet, clear_sys_exc_info
|
|
||||||
import monotonic
|
|
||||||
import six
|
|
||||||
@@ -265,7 +266,7 @@ class BaseHub(object):
|
|
||||||
listener = self.closed.pop()
|
|
||||||
if not listener.greenlet.dead:
|
|
||||||
# There's no point signalling a greenlet that's already dead.
|
|
||||||
- listener.tb(IOClosed(errno.ENOTCONN, "Operation on closed file"))
|
|
||||||
+ listener.tb(eventlet.hubs.IOClosed(errno.ENOTCONN, "Operation on closed file"))
|
|
||||||
|
|
||||||
def ensure_greenlet(self):
|
|
||||||
if self.greenlet.dead:
|
|
||||||
diff --git a/eventlet/hubs/kqueue.py b/eventlet/hubs/kqueue.py
|
|
||||||
index 0e60d33..bad4a87 100644
|
|
||||||
--- a/eventlet/hubs/kqueue.py
|
|
||||||
+++ b/eventlet/hubs/kqueue.py
|
|
||||||
@@ -1,25 +1,24 @@
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
from eventlet import patcher, support
|
|
||||||
+from eventlet.hubs import hub
|
|
||||||
import six
|
|
||||||
select = patcher.original('select')
|
|
||||||
time = patcher.original('time')
|
|
||||||
|
|
||||||
-from eventlet.hubs.hub import BaseHub, READ, WRITE, noop
|
|
||||||
|
|
||||||
+def is_available():
|
|
||||||
+ return hasattr(select, 'kqueue')
|
|
||||||
|
|
||||||
-if getattr(select, 'kqueue', None) is None:
|
|
||||||
- raise ImportError('No kqueue implementation found in select module')
|
|
||||||
|
|
||||||
-
|
|
||||||
-FILTERS = {READ: select.KQ_FILTER_READ,
|
|
||||||
- WRITE: select.KQ_FILTER_WRITE}
|
|
||||||
-
|
|
||||||
-
|
|
||||||
-class Hub(BaseHub):
|
|
||||||
+class Hub(hub.BaseHub):
|
|
||||||
MAX_EVENTS = 100
|
|
||||||
|
|
||||||
def __init__(self, clock=None):
|
|
||||||
+ self.FILTERS = {
|
|
||||||
+ hub.READ: select.KQ_FILTER_READ,
|
|
||||||
+ hub.WRITE: select.KQ_FILTER_WRITE,
|
|
||||||
+ }
|
|
||||||
super(Hub, self).__init__(clock)
|
|
||||||
self._events = {}
|
|
||||||
self._init_kqueue()
|
|
||||||
@@ -31,10 +30,9 @@ class Hub(BaseHub):
|
|
||||||
def _reinit_kqueue(self):
|
|
||||||
self.kqueue.close()
|
|
||||||
self._init_kqueue()
|
|
||||||
- kqueue = self.kqueue
|
|
||||||
events = [e for i in six.itervalues(self._events)
|
|
||||||
for e in six.itervalues(i)]
|
|
||||||
- kqueue.control(events, 0, 0)
|
|
||||||
+ self.kqueue.control(events, 0, 0)
|
|
||||||
|
|
||||||
def _control(self, events, max_events, timeout):
|
|
||||||
try:
|
|
||||||
@@ -51,7 +49,7 @@ class Hub(BaseHub):
|
|
||||||
events = self._events.setdefault(fileno, {})
|
|
||||||
if evtype not in events:
|
|
||||||
try:
|
|
||||||
- event = select.kevent(fileno, FILTERS.get(evtype), select.KQ_EV_ADD)
|
|
||||||
+ event = select.kevent(fileno, self.FILTERS.get(evtype), select.KQ_EV_ADD)
|
|
||||||
self._control([event], 0, 0)
|
|
||||||
events[evtype] = event
|
|
||||||
except ValueError:
|
|
||||||
@@ -90,8 +88,8 @@ class Hub(BaseHub):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def wait(self, seconds=None):
|
|
||||||
- readers = self.listeners[READ]
|
|
||||||
- writers = self.listeners[WRITE]
|
|
||||||
+ readers = self.listeners[self.READ]
|
|
||||||
+ writers = self.listeners[self.WRITE]
|
|
||||||
|
|
||||||
if not readers and not writers:
|
|
||||||
if seconds:
|
|
||||||
@@ -103,10 +101,10 @@ class Hub(BaseHub):
|
|
||||||
fileno = event.ident
|
|
||||||
evfilt = event.filter
|
|
||||||
try:
|
|
||||||
- if evfilt == FILTERS[READ]:
|
|
||||||
- readers.get(fileno, noop).cb(fileno)
|
|
||||||
- if evfilt == FILTERS[WRITE]:
|
|
||||||
- writers.get(fileno, noop).cb(fileno)
|
|
||||||
+ if evfilt == select.KQ_FILTER_READ:
|
|
||||||
+ readers.get(fileno, hub.noop).cb(fileno)
|
|
||||||
+ if evfilt == select.KQ_FILTER_WRITE:
|
|
||||||
+ writers.get(fileno, hub.noop).cb(fileno)
|
|
||||||
except SYSTEM_EXCEPTIONS:
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
diff --git a/eventlet/hubs/poll.py b/eventlet/hubs/poll.py
|
|
||||||
index 17bc9e7..1bbd401 100644
|
|
||||||
--- a/eventlet/hubs/poll.py
|
|
||||||
+++ b/eventlet/hubs/poll.py
|
|
||||||
@@ -1,21 +1,22 @@
|
|
||||||
import errno
|
|
||||||
import sys
|
|
||||||
|
|
||||||
-from eventlet import patcher
|
|
||||||
+from eventlet import patcher, support
|
|
||||||
+from eventlet.hubs import hub
|
|
||||||
select = patcher.original('select')
|
|
||||||
time = patcher.original('time')
|
|
||||||
|
|
||||||
-from eventlet.hubs.hub import BaseHub, READ, WRITE, noop
|
|
||||||
-from eventlet.support import get_errno, clear_sys_exc_info
|
|
||||||
|
|
||||||
-EXC_MASK = select.POLLERR | select.POLLHUP
|
|
||||||
-READ_MASK = select.POLLIN | select.POLLPRI
|
|
||||||
-WRITE_MASK = select.POLLOUT
|
|
||||||
+def is_available():
|
|
||||||
+ return hasattr(select, 'poll')
|
|
||||||
|
|
||||||
|
|
||||||
-class Hub(BaseHub):
|
|
||||||
+class Hub(hub.BaseHub):
|
|
||||||
def __init__(self, clock=None):
|
|
||||||
super(Hub, self).__init__(clock)
|
|
||||||
+ self.EXC_MASK = select.POLLERR | select.POLLHUP
|
|
||||||
+ self.READ_MASK = select.POLLIN | select.POLLPRI
|
|
||||||
+ self.WRITE_MASK = select.POLLOUT
|
|
||||||
self.poll = select.poll()
|
|
||||||
|
|
||||||
def add(self, evtype, fileno, cb, tb, mac):
|
|
||||||
@@ -29,10 +30,10 @@ class Hub(BaseHub):
|
|
||||||
|
|
||||||
def register(self, fileno, new=False):
|
|
||||||
mask = 0
|
|
||||||
- if self.listeners[READ].get(fileno):
|
|
||||||
- mask |= READ_MASK | EXC_MASK
|
|
||||||
- if self.listeners[WRITE].get(fileno):
|
|
||||||
- mask |= WRITE_MASK | EXC_MASK
|
|
||||||
+ if self.listeners[self.READ].get(fileno):
|
|
||||||
+ mask |= self.READ_MASK | self.EXC_MASK
|
|
||||||
+ if self.listeners[self.WRITE].get(fileno):
|
|
||||||
+ mask |= self.WRITE_MASK | self.EXC_MASK
|
|
||||||
try:
|
|
||||||
if mask:
|
|
||||||
if new:
|
|
||||||
@@ -68,8 +69,8 @@ class Hub(BaseHub):
|
|
||||||
return self.poll.poll(int(seconds * 1000.0))
|
|
||||||
|
|
||||||
def wait(self, seconds=None):
|
|
||||||
- readers = self.listeners[READ]
|
|
||||||
- writers = self.listeners[WRITE]
|
|
||||||
+ readers = self.listeners[self.READ]
|
|
||||||
+ writers = self.listeners[self.WRITE]
|
|
||||||
|
|
||||||
if not readers and not writers:
|
|
||||||
if seconds:
|
|
||||||
@@ -78,7 +79,7 @@ class Hub(BaseHub):
|
|
||||||
try:
|
|
||||||
presult = self.do_poll(seconds)
|
|
||||||
except (IOError, select.error) as e:
|
|
||||||
- if get_errno(e) == errno.EINTR:
|
|
||||||
+ if support.get_errno(e) == errno.EINTR:
|
|
||||||
return
|
|
||||||
raise
|
|
||||||
SYSTEM_EXCEPTIONS = self.SYSTEM_EXCEPTIONS
|
|
||||||
@@ -92,15 +93,16 @@ class Hub(BaseHub):
|
|
||||||
# polled for. It prevents one handler from invalidating
|
|
||||||
# another.
|
|
||||||
callbacks = set()
|
|
||||||
+ noop = hub.noop # shave getattr
|
|
||||||
for fileno, event in presult:
|
|
||||||
- if event & READ_MASK:
|
|
||||||
+ if event & self.READ_MASK:
|
|
||||||
callbacks.add((readers.get(fileno, noop), fileno))
|
|
||||||
- if event & WRITE_MASK:
|
|
||||||
+ if event & self.WRITE_MASK:
|
|
||||||
callbacks.add((writers.get(fileno, noop), fileno))
|
|
||||||
if event & select.POLLNVAL:
|
|
||||||
self.remove_descriptor(fileno)
|
|
||||||
continue
|
|
||||||
- if event & EXC_MASK:
|
|
||||||
+ if event & self.EXC_MASK:
|
|
||||||
callbacks.add((readers.get(fileno, noop), fileno))
|
|
||||||
callbacks.add((writers.get(fileno, noop), fileno))
|
|
||||||
|
|
||||||
@@ -111,7 +113,7 @@ class Hub(BaseHub):
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
self.squelch_exception(fileno, sys.exc_info())
|
|
||||||
- clear_sys_exc_info()
|
|
||||||
+ support.clear_sys_exc_info()
|
|
||||||
|
|
||||||
if self.debug_blocking:
|
|
||||||
self.block_detect_post()
|
|
||||||
diff --git a/eventlet/hubs/pyevent.py b/eventlet/hubs/pyevent.py
|
|
||||||
index 73c0a18..8367a65 100644
|
|
||||||
--- a/eventlet/hubs/pyevent.py
|
|
||||||
+++ b/eventlet/hubs/pyevent.py
|
|
||||||
@@ -1,12 +1,20 @@
|
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
-import event
|
|
||||||
import types
|
|
||||||
|
|
||||||
from eventlet.support import greenlets as greenlet
|
|
||||||
import six
|
|
||||||
from eventlet.hubs.hub import BaseHub, READ, WRITE
|
|
||||||
|
|
||||||
+try:
|
|
||||||
+ import event
|
|
||||||
+except ImportError:
|
|
||||||
+ event = None
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+def is_available():
|
|
||||||
+ return event is not None
|
|
||||||
+
|
|
||||||
|
|
||||||
class event_wrapper(object):
|
|
||||||
|
|
||||||
diff --git a/eventlet/hubs/selects.py b/eventlet/hubs/selects.py
|
|
||||||
index 3f04e1a..0ead5b8 100644
|
|
||||||
--- a/eventlet/hubs/selects.py
|
|
||||||
+++ b/eventlet/hubs/selects.py
|
|
||||||
@@ -1,60 +1,64 @@
|
|
||||||
import errno
|
|
||||||
import sys
|
|
||||||
-from eventlet import patcher
|
|
||||||
-from eventlet.support import get_errno, clear_sys_exc_info
|
|
||||||
+from eventlet import patcher, support
|
|
||||||
+from eventlet.hubs import hub
|
|
||||||
select = patcher.original('select')
|
|
||||||
time = patcher.original('time')
|
|
||||||
|
|
||||||
-from eventlet.hubs.hub import BaseHub, READ, WRITE, noop
|
|
||||||
-
|
|
||||||
try:
|
|
||||||
BAD_SOCK = set((errno.EBADF, errno.WSAENOTSOCK))
|
|
||||||
except AttributeError:
|
|
||||||
BAD_SOCK = set((errno.EBADF,))
|
|
||||||
|
|
||||||
|
|
||||||
-class Hub(BaseHub):
|
|
||||||
+def is_available():
|
|
||||||
+ return hasattr(select, 'select')
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class Hub(hub.BaseHub):
|
|
||||||
def _remove_bad_fds(self):
|
|
||||||
""" Iterate through fds, removing the ones that are bad per the
|
|
||||||
operating system.
|
|
||||||
"""
|
|
||||||
- all_fds = list(self.listeners[READ]) + list(self.listeners[WRITE])
|
|
||||||
+ all_fds = list(self.listeners[self.READ]) + list(self.listeners[self.WRITE])
|
|
||||||
for fd in all_fds:
|
|
||||||
try:
|
|
||||||
select.select([fd], [], [], 0)
|
|
||||||
except select.error as e:
|
|
||||||
- if get_errno(e) in BAD_SOCK:
|
|
||||||
+ if support.get_errno(e) in BAD_SOCK:
|
|
||||||
self.remove_descriptor(fd)
|
|
||||||
|
|
||||||
def wait(self, seconds=None):
|
|
||||||
- readers = self.listeners[READ]
|
|
||||||
- writers = self.listeners[WRITE]
|
|
||||||
+ readers = self.listeners[self.READ]
|
|
||||||
+ writers = self.listeners[self.WRITE]
|
|
||||||
if not readers and not writers:
|
|
||||||
if seconds:
|
|
||||||
time.sleep(seconds)
|
|
||||||
return
|
|
||||||
- all_fds = list(readers) + list(writers)
|
|
||||||
+ reader_fds = list(readers)
|
|
||||||
+ writer_fds = list(writers)
|
|
||||||
+ all_fds = reader_fds + writer_fds
|
|
||||||
try:
|
|
||||||
- r, w, er = select.select(readers.keys(), writers.keys(), all_fds, seconds)
|
|
||||||
+ r, w, er = select.select(reader_fds, writer_fds, all_fds, seconds)
|
|
||||||
except select.error as e:
|
|
||||||
- if get_errno(e) == errno.EINTR:
|
|
||||||
+ if support.get_errno(e) == errno.EINTR:
|
|
||||||
return
|
|
||||||
- elif get_errno(e) in BAD_SOCK:
|
|
||||||
+ elif support.get_errno(e) in BAD_SOCK:
|
|
||||||
self._remove_bad_fds()
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
|
|
||||||
for fileno in er:
|
|
||||||
- readers.get(fileno, noop).cb(fileno)
|
|
||||||
- writers.get(fileno, noop).cb(fileno)
|
|
||||||
+ readers.get(fileno, hub.noop).cb(fileno)
|
|
||||||
+ writers.get(fileno, hub.noop).cb(fileno)
|
|
||||||
|
|
||||||
for listeners, events in ((readers, r), (writers, w)):
|
|
||||||
for fileno in events:
|
|
||||||
try:
|
|
||||||
- listeners.get(fileno, noop).cb(fileno)
|
|
||||||
+ listeners.get(fileno, hub.noop).cb(fileno)
|
|
||||||
except self.SYSTEM_EXCEPTIONS:
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
self.squelch_exception(fileno, sys.exc_info())
|
|
||||||
- clear_sys_exc_info()
|
|
||||||
+ support.clear_sys_exc_info()
|
|
||||||
diff --git a/eventlet/hubs/timer.py b/eventlet/hubs/timer.py
|
|
||||||
index 9b10b00..1dfd561 100644
|
|
||||||
--- a/eventlet/hubs/timer.py
|
|
||||||
+++ b/eventlet/hubs/timer.py
|
|
||||||
@@ -1,8 +1,8 @@
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
+import eventlet.hubs
|
|
||||||
from eventlet.support import greenlets as greenlet
|
|
||||||
import six
|
|
||||||
-from eventlet.hubs import get_hub
|
|
||||||
|
|
||||||
""" If true, captures a stack trace for each timer when constructed. This is
|
|
||||||
useful for debugging leaking timers, to find out where the timer was set up. """
|
|
||||||
@@ -48,7 +48,7 @@ class Timer(object):
|
|
||||||
"""Schedule this timer to run in the current runloop.
|
|
||||||
"""
|
|
||||||
self.called = False
|
|
||||||
- self.scheduled_time = get_hub().add_timer(self)
|
|
||||||
+ self.scheduled_time = eventlet.hubs.get_hub().add_timer(self)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __call__(self, *args):
|
|
||||||
@@ -69,7 +69,7 @@ class Timer(object):
|
|
||||||
"""
|
|
||||||
if not self.called:
|
|
||||||
self.called = True
|
|
||||||
- get_hub().timer_canceled(self)
|
|
||||||
+ eventlet.hubs.get_hub().timer_canceled(self)
|
|
||||||
try:
|
|
||||||
del self.tpl
|
|
||||||
except AttributeError:
|
|
||||||
diff --git a/tests/hub_test.py b/tests/hub_test.py
|
|
||||||
index 61b5b0b..d62b805 100644
|
|
||||||
--- a/tests/hub_test.py
|
|
||||||
+++ b/tests/hub_test.py
|
|
||||||
@@ -4,7 +4,6 @@ import time
|
|
||||||
|
|
||||||
import tests
|
|
||||||
from tests import skip_with_pyevent, skip_if_no_itimer, skip_unless
|
|
||||||
-from tests.patcher_test import ProcessBase
|
|
||||||
import eventlet
|
|
||||||
from eventlet import hubs
|
|
||||||
from eventlet.support import greenlets
|
|
||||||
@@ -205,17 +204,6 @@ class TestExceptionInGreenthread(tests.LimitedTestCase):
|
|
||||||
g.kill()
|
|
||||||
|
|
||||||
|
|
||||||
-class TestHubSelection(tests.LimitedTestCase):
|
|
||||||
-
|
|
||||||
- def test_explicit_hub(self):
|
|
||||||
- oldhub = hubs.get_hub()
|
|
||||||
- try:
|
|
||||||
- hubs.use_hub(Foo)
|
|
||||||
- assert isinstance(hubs.get_hub(), Foo), hubs.get_hub()
|
|
||||||
- finally:
|
|
||||||
- hubs._threadlocal.hub = oldhub
|
|
||||||
-
|
|
||||||
-
|
|
||||||
class TestHubBlockingDetector(tests.LimitedTestCase):
|
|
||||||
TEST_TIMEOUT = 10
|
|
||||||
|
|
||||||
@@ -361,43 +349,11 @@ class TestDeadRunLoop(tests.LimitedTestCase):
|
|
||||||
assert g.dead # sanity check that dummyproc has completed
|
|
||||||
|
|
||||||
|
|
||||||
-class Foo(object):
|
|
||||||
- pass
|
|
||||||
-
|
|
||||||
-
|
|
||||||
-class TestDefaultHub(ProcessBase):
|
|
||||||
-
|
|
||||||
- def test_kqueue_unsupported(self):
|
|
||||||
- # https://github.com/eventlet/eventlet/issues/38
|
|
||||||
- # get_hub on windows broken by kqueue
|
|
||||||
- module_source = r'''
|
|
||||||
-from __future__ import print_function
|
|
||||||
-
|
|
||||||
-# Simulate absence of kqueue even on platforms that support it.
|
|
||||||
-import select
|
|
||||||
-try:
|
|
||||||
- del select.kqueue
|
|
||||||
-except AttributeError:
|
|
||||||
- pass
|
|
||||||
-
|
|
||||||
-from six.moves import builtins
|
|
||||||
-
|
|
||||||
-original_import = builtins.__import__
|
|
||||||
-
|
|
||||||
-def fail_import(name, *args, **kwargs):
|
|
||||||
- if 'epoll' in name:
|
|
||||||
- raise ImportError('disabled for test')
|
|
||||||
- if 'kqueue' in name:
|
|
||||||
- print('kqueue tried')
|
|
||||||
- return original_import(name, *args, **kwargs)
|
|
||||||
-
|
|
||||||
-builtins.__import__ = fail_import
|
|
||||||
+def test_use_hub_class():
|
|
||||||
+ tests.run_isolated('hub_use_hub_class.py')
|
|
||||||
|
|
||||||
|
|
||||||
-import eventlet.hubs
|
|
||||||
-eventlet.hubs.get_default_hub()
|
|
||||||
-print('ok')
|
|
||||||
-'''
|
|
||||||
- self.write_to_tempfile('newmod', module_source)
|
|
||||||
- output, _ = self.launch_subprocess('newmod.py')
|
|
||||||
- self.assertEqual(output, 'kqueue tried\nok\n')
|
|
||||||
+def test_kqueue_unsupported():
|
|
||||||
+ # https://github.com/eventlet/eventlet/issues/38
|
|
||||||
+ # get_hub on windows broken by kqueue
|
|
||||||
+ tests.run_isolated('hub_kqueue_unsupported.py')
|
|
||||||
diff --git a/tests/isolated/hub_kqueue_unsupported.py b/tests/isolated/hub_kqueue_unsupported.py
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..373df98
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/tests/isolated/hub_kqueue_unsupported.py
|
|
||||||
@@ -0,0 +1,28 @@
|
|
||||||
+from __future__ import print_function
|
|
||||||
+__test__ = False
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+def delattr_silent(x, name):
|
|
||||||
+ try:
|
|
||||||
+ delattr(x, name)
|
|
||||||
+ except AttributeError:
|
|
||||||
+ pass
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+if __name__ == '__main__':
|
|
||||||
+ # Simulate absence of kqueue even on platforms that support it.
|
|
||||||
+ import select
|
|
||||||
+ delattr_silent(select, 'kqueue')
|
|
||||||
+ delattr_silent(select, 'KQ_FILTER_READ')
|
|
||||||
+ # patcher.original used in hub may reimport and return deleted kqueue attribute
|
|
||||||
+ import eventlet.patcher
|
|
||||||
+ select_original = eventlet.patcher.original('select')
|
|
||||||
+ delattr_silent(select_original, 'kqueue')
|
|
||||||
+ delattr_silent(select_original, 'KQ_FILTER_READ')
|
|
||||||
+
|
|
||||||
+ import eventlet.hubs
|
|
||||||
+ default = eventlet.hubs.get_default_hub()
|
|
||||||
+ assert not default.__name__.endswith('kqueue')
|
|
||||||
+ import eventlet.hubs.kqueue
|
|
||||||
+ assert not eventlet.hubs.kqueue.is_available()
|
|
||||||
+ print('pass')
|
|
||||||
diff --git a/tests/isolated/hub_use_hub_class.py b/tests/isolated/hub_use_hub_class.py
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..9f7f308
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/tests/isolated/hub_use_hub_class.py
|
|
||||||
@@ -0,0 +1,13 @@
|
|
||||||
+from __future__ import print_function
|
|
||||||
+__test__ = False
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class Foo(object):
|
|
||||||
+ pass
|
|
||||||
+
|
|
||||||
+if __name__ == '__main__':
|
|
||||||
+ import eventlet.hubs
|
|
||||||
+ eventlet.hubs.use_hub(Foo)
|
|
||||||
+ hub = eventlet.hubs.get_hub()
|
|
||||||
+ assert isinstance(hub, Foo), repr(hub)
|
|
||||||
+ print('pass')
|
|
||||||
--
|
|
||||||
2.21.0
|
|
||||||
|
|
@@ -1,67 +0,0 @@
|
|||||||
From a28a275393d3c3ae3c3a5341cc4764fad21be3e5 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Sergey Shepelev <temotor@gmail.com>
|
|
||||||
Date: Mon, 27 Aug 2018 00:22:35 +0500
|
|
||||||
Subject: [PATCH 1/3] ssl: connect used non-monotonic time.time() for timeout
|
|
||||||
(#520)
|
|
||||||
|
|
||||||
Origin: https://github.com/eventlet/eventlet/pull/517
|
|
||||||
|
|
||||||
Related:
|
|
||||||
https://github.com/eventlet/eventlet/pull/388
|
|
||||||
https://github.com/eventlet/eventlet/pull/303
|
|
||||||
https://github.com/eventlet/eventlet/issues/270
|
|
||||||
https://github.com/eventlet/eventlet/issues/132
|
|
||||||
---
|
|
||||||
eventlet/green/ssl.py | 10 +++++-----
|
|
||||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/eventlet/green/ssl.py b/eventlet/green/ssl.py
|
|
||||||
index 53ee9a3..577afba 100644
|
|
||||||
--- a/eventlet/green/ssl.py
|
|
||||||
+++ b/eventlet/green/ssl.py
|
|
||||||
@@ -6,9 +6,8 @@ slurp_properties(__ssl, globals(), srckeys=dir(__ssl))
|
|
||||||
import errno
|
|
||||||
import functools
|
|
||||||
import sys
|
|
||||||
-import time
|
|
||||||
|
|
||||||
-from eventlet import greenio
|
|
||||||
+from eventlet import greenio, hubs
|
|
||||||
from eventlet.greenio import (
|
|
||||||
set_nonblocking, GreenSocket, CONNECT_ERR, CONNECT_SUCCESS,
|
|
||||||
)
|
|
||||||
@@ -264,6 +263,7 @@ class GreenSSLSocket(_original_sslsocket):
|
|
||||||
if self.act_non_blocking:
|
|
||||||
return real_connect(self, addr)
|
|
||||||
else:
|
|
||||||
+ clock = hubs.get_hub().clock
|
|
||||||
# *NOTE: gross, copied code from greenio because it's not factored
|
|
||||||
# well enough to reuse
|
|
||||||
if self.gettimeout() is None:
|
|
||||||
@@ -278,7 +278,7 @@ class GreenSSLSocket(_original_sslsocket):
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
- end = time.time() + self.gettimeout()
|
|
||||||
+ end = clock() + self.gettimeout()
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
real_connect(self, addr)
|
|
||||||
@@ -286,12 +286,12 @@ class GreenSSLSocket(_original_sslsocket):
|
|
||||||
if get_errno(exc) in CONNECT_ERR:
|
|
||||||
trampoline(
|
|
||||||
self, write=True,
|
|
||||||
- timeout=end - time.time(), timeout_exc=timeout_exc('timed out'))
|
|
||||||
+ timeout=end - clock(), timeout_exc=timeout_exc('timed out'))
|
|
||||||
elif get_errno(exc) in CONNECT_SUCCESS:
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
- if time.time() >= end:
|
|
||||||
+ if clock() >= end:
|
|
||||||
raise timeout_exc('timed out')
|
|
||||||
|
|
||||||
def connect(self, addr):
|
|
||||||
--
|
|
||||||
2.21.0
|
|
||||||
|
|
@@ -1,96 +0,0 @@
|
|||||||
From cf47cb518db3e0dbdd48473fb40cf9f6ecd50e07 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Marcel Plch <mplch@redhat.com>
|
|
||||||
Date: Fri, 28 Sep 2018 17:08:59 +0200
|
|
||||||
Subject: [PATCH 2/3] Fix for Python 3.7 (#506)
|
|
||||||
|
|
||||||
* Fix for Python 3.7
|
|
||||||
|
|
||||||
* Remove redundant piece of code.
|
|
||||||
|
|
||||||
* Put back do_handshake_on_connect kwarg
|
|
||||||
|
|
||||||
* Use Python 3.7 instead of 3.7-dev
|
|
||||||
|
|
||||||
* Fix buildbot failing permissions with 3.7
|
|
||||||
|
|
||||||
* tests: env_tpool_zero assert details
|
|
||||||
|
|
||||||
* setup: Python 3.7 classificator
|
|
||||||
---
|
|
||||||
eventlet/green/ssl.py | 46 +++++++++++++++++++++++++++++++++++++------
|
|
||||||
1 file changed, 40 insertions(+), 6 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/eventlet/green/ssl.py b/eventlet/green/ssl.py
|
|
||||||
index 577afba..53dff70 100644
|
|
||||||
--- a/eventlet/green/ssl.py
|
|
||||||
+++ b/eventlet/green/ssl.py
|
|
||||||
@@ -23,6 +23,7 @@ __patched__ = [
|
|
||||||
'create_default_context', '_create_default_https_context']
|
|
||||||
|
|
||||||
_original_sslsocket = __ssl.SSLSocket
|
|
||||||
+_original_wrap_socket = __ssl.wrap_socket
|
|
||||||
|
|
||||||
|
|
||||||
class GreenSSLSocket(_original_sslsocket):
|
|
||||||
@@ -56,11 +57,41 @@ class GreenSSLSocket(_original_sslsocket):
|
|
||||||
# this assignment
|
|
||||||
self._timeout = sock.gettimeout()
|
|
||||||
|
|
||||||
- # nonblocking socket handshaking on connect got disabled so let's pretend it's disabled
|
|
||||||
- # even when it's on
|
|
||||||
- super(GreenSSLSocket, self).__init__(
|
|
||||||
- sock.fd, keyfile, certfile, server_side, cert_reqs, ssl_version,
|
|
||||||
- ca_certs, do_handshake_on_connect and six.PY2, *args, **kw)
|
|
||||||
+ if sys.version_info >= (3, 7):
|
|
||||||
+ # Monkey-patch the sslsocket so our modified self gets
|
|
||||||
+ # injected into its _create method.
|
|
||||||
+ def fake_new(self, cls, *args, **kwargs):
|
|
||||||
+ return self
|
|
||||||
+
|
|
||||||
+ orig_new = _original_sslsocket.__new__
|
|
||||||
+ try:
|
|
||||||
+ _original_sslsocket.__new__ = fake_new.__get__(self, GreenSSLSocket)
|
|
||||||
+
|
|
||||||
+ self = _original_wrap_socket(
|
|
||||||
+ sock=sock.fd,
|
|
||||||
+ keyfile=keyfile,
|
|
||||||
+ certfile=certfile,
|
|
||||||
+ server_side=server_side,
|
|
||||||
+ cert_reqs=cert_reqs,
|
|
||||||
+ ssl_version=ssl_version,
|
|
||||||
+ ca_certs=ca_certs,
|
|
||||||
+ do_handshake_on_connect=False,
|
|
||||||
+ *args, **kw
|
|
||||||
+ )
|
|
||||||
+ self.keyfile = keyfile
|
|
||||||
+ self.certfile = certfile
|
|
||||||
+ self.cert_reqs = cert_reqs
|
|
||||||
+ self.ssl_version = ssl_version
|
|
||||||
+ self.ca_certs = ca_certs
|
|
||||||
+ finally:
|
|
||||||
+ # Unpatch
|
|
||||||
+ _original_sslsocket.__new__ = orig_new
|
|
||||||
+ else:
|
|
||||||
+ # nonblocking socket handshaking on connect got disabled so let's pretend it's disabled
|
|
||||||
+ # even when it's on
|
|
||||||
+ super(GreenSSLSocket, self).__init__(
|
|
||||||
+ sock.fd, keyfile, certfile, server_side, cert_reqs, ssl_version,
|
|
||||||
+ ca_certs, do_handshake_on_connect and six.PY2, *args, **kw)
|
|
||||||
|
|
||||||
# the superclass initializer trashes the methods so we remove
|
|
||||||
# the local-object versions of them and let the actual class
|
|
||||||
@@ -323,7 +354,10 @@ class GreenSSLSocket(_original_sslsocket):
|
|
||||||
except NameError:
|
|
||||||
self._sslobj = sslobj
|
|
||||||
else:
|
|
||||||
- self._sslobj = SSLObject(sslobj, owner=self)
|
|
||||||
+ if sys.version_info < (3, 7):
|
|
||||||
+ self._sslobj = SSLObject(sslobj, owner=self)
|
|
||||||
+ else:
|
|
||||||
+ self._sslobj = sslobj
|
|
||||||
|
|
||||||
if self.do_handshake_on_connect:
|
|
||||||
self.do_handshake()
|
|
||||||
--
|
|
||||||
2.21.0
|
|
||||||
|
|
@@ -1,165 +0,0 @@
|
|||||||
From a915bb642dd6cd4e92c959addff30509977a637c Mon Sep 17 00:00:00 2001
|
|
||||||
From: Junyi <xmaswillyou@gmail.com>
|
|
||||||
Date: Wed, 30 Jan 2019 00:10:31 -0800
|
|
||||||
Subject: [PATCH 3/3] Fix compatibility with Python 3.7 ssl.SSLSocket (#531)
|
|
||||||
|
|
||||||
---
|
|
||||||
eventlet/green/ssl.py | 86 ++++++++++++++++++++++++-------------------
|
|
||||||
1 file changed, 49 insertions(+), 37 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/eventlet/green/ssl.py b/eventlet/green/ssl.py
|
|
||||||
index 53dff70..9504aef 100644
|
|
||||||
--- a/eventlet/green/ssl.py
|
|
||||||
+++ b/eventlet/green/ssl.py
|
|
||||||
@@ -3,10 +3,7 @@ __ssl = __import__('ssl')
|
|
||||||
from eventlet.patcher import slurp_properties
|
|
||||||
slurp_properties(__ssl, globals(), srckeys=dir(__ssl))
|
|
||||||
|
|
||||||
-import errno
|
|
||||||
-import functools
|
|
||||||
import sys
|
|
||||||
-
|
|
||||||
from eventlet import greenio, hubs
|
|
||||||
from eventlet.greenio import (
|
|
||||||
set_nonblocking, GreenSocket, CONNECT_ERR, CONNECT_SUCCESS,
|
|
||||||
@@ -14,6 +11,8 @@ from eventlet.greenio import (
|
|
||||||
from eventlet.hubs import trampoline, IOClosed
|
|
||||||
from eventlet.support import get_errno, PY33
|
|
||||||
import six
|
|
||||||
+from contextlib import contextmanager
|
|
||||||
+
|
|
||||||
orig_socket = __import__('socket')
|
|
||||||
socket = orig_socket.socket
|
|
||||||
timeout_exc = SSLError
|
|
||||||
@@ -24,6 +23,21 @@ __patched__ = [
|
|
||||||
|
|
||||||
_original_sslsocket = __ssl.SSLSocket
|
|
||||||
_original_wrap_socket = __ssl.wrap_socket
|
|
||||||
+_original_sslcontext = getattr(__ssl, 'SSLContext', None)
|
|
||||||
+_is_under_py_3_7 = sys.version_info < (3, 7)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+@contextmanager
|
|
||||||
+def _original_ssl_context(*args, **kwargs):
|
|
||||||
+ tmp_sslcontext = _original_wrap_socket.__globals__.get('SSLContext', None)
|
|
||||||
+ tmp_sslsocket = _original_sslsocket._create.__globals__.get('SSLSocket', None)
|
|
||||||
+ _original_sslsocket._create.__globals__['SSLSocket'] = _original_sslsocket
|
|
||||||
+ _original_wrap_socket.__globals__['SSLContext'] = _original_sslcontext
|
|
||||||
+ try:
|
|
||||||
+ yield
|
|
||||||
+ finally:
|
|
||||||
+ _original_wrap_socket.__globals__['SSLContext'] = tmp_sslcontext
|
|
||||||
+ _original_sslsocket._create.__globals__['SSLSocket'] = tmp_sslsocket
|
|
||||||
|
|
||||||
|
|
||||||
class GreenSSLSocket(_original_sslsocket):
|
|
||||||
@@ -40,16 +54,43 @@ class GreenSSLSocket(_original_sslsocket):
|
|
||||||
settimeout(), and to close/reopen the connection when a timeout
|
|
||||||
occurs at an unexpected juncture in the code.
|
|
||||||
"""
|
|
||||||
+ def __new__(cls, sock=None, keyfile=None, certfile=None,
|
|
||||||
+ server_side=False, cert_reqs=CERT_NONE,
|
|
||||||
+ ssl_version=PROTOCOL_SSLv23, ca_certs=None,
|
|
||||||
+ do_handshake_on_connect=True, *args, **kw):
|
|
||||||
+ if _is_under_py_3_7:
|
|
||||||
+ return super(GreenSSLSocket, cls).__new__(cls)
|
|
||||||
+ else:
|
|
||||||
+ if not isinstance(sock, GreenSocket):
|
|
||||||
+ sock = GreenSocket(sock)
|
|
||||||
+ with _original_ssl_context():
|
|
||||||
+ ret = _original_wrap_socket(
|
|
||||||
+ sock=sock.fd,
|
|
||||||
+ keyfile=keyfile,
|
|
||||||
+ certfile=certfile,
|
|
||||||
+ server_side=server_side,
|
|
||||||
+ cert_reqs=cert_reqs,
|
|
||||||
+ ssl_version=ssl_version,
|
|
||||||
+ ca_certs=ca_certs,
|
|
||||||
+ do_handshake_on_connect=False,
|
|
||||||
+ *args, **kw
|
|
||||||
+ )
|
|
||||||
+ ret.keyfile = keyfile
|
|
||||||
+ ret.certfile = certfile
|
|
||||||
+ ret.cert_reqs = cert_reqs
|
|
||||||
+ ret.ssl_version = ssl_version
|
|
||||||
+ ret.ca_certs = ca_certs
|
|
||||||
+ ret.__class__ = GreenSSLSocket
|
|
||||||
+ return ret
|
|
||||||
+
|
|
||||||
# we are inheriting from SSLSocket because its constructor calls
|
|
||||||
# do_handshake whose behavior we wish to override
|
|
||||||
-
|
|
||||||
def __init__(self, sock, keyfile=None, certfile=None,
|
|
||||||
server_side=False, cert_reqs=CERT_NONE,
|
|
||||||
ssl_version=PROTOCOL_SSLv23, ca_certs=None,
|
|
||||||
do_handshake_on_connect=True, *args, **kw):
|
|
||||||
if not isinstance(sock, GreenSocket):
|
|
||||||
sock = GreenSocket(sock)
|
|
||||||
-
|
|
||||||
self.act_non_blocking = sock.act_non_blocking
|
|
||||||
|
|
||||||
if six.PY2:
|
|
||||||
@@ -57,42 +98,12 @@ class GreenSSLSocket(_original_sslsocket):
|
|
||||||
# this assignment
|
|
||||||
self._timeout = sock.gettimeout()
|
|
||||||
|
|
||||||
- if sys.version_info >= (3, 7):
|
|
||||||
- # Monkey-patch the sslsocket so our modified self gets
|
|
||||||
- # injected into its _create method.
|
|
||||||
- def fake_new(self, cls, *args, **kwargs):
|
|
||||||
- return self
|
|
||||||
-
|
|
||||||
- orig_new = _original_sslsocket.__new__
|
|
||||||
- try:
|
|
||||||
- _original_sslsocket.__new__ = fake_new.__get__(self, GreenSSLSocket)
|
|
||||||
-
|
|
||||||
- self = _original_wrap_socket(
|
|
||||||
- sock=sock.fd,
|
|
||||||
- keyfile=keyfile,
|
|
||||||
- certfile=certfile,
|
|
||||||
- server_side=server_side,
|
|
||||||
- cert_reqs=cert_reqs,
|
|
||||||
- ssl_version=ssl_version,
|
|
||||||
- ca_certs=ca_certs,
|
|
||||||
- do_handshake_on_connect=False,
|
|
||||||
- *args, **kw
|
|
||||||
- )
|
|
||||||
- self.keyfile = keyfile
|
|
||||||
- self.certfile = certfile
|
|
||||||
- self.cert_reqs = cert_reqs
|
|
||||||
- self.ssl_version = ssl_version
|
|
||||||
- self.ca_certs = ca_certs
|
|
||||||
- finally:
|
|
||||||
- # Unpatch
|
|
||||||
- _original_sslsocket.__new__ = orig_new
|
|
||||||
- else:
|
|
||||||
+ if _is_under_py_3_7:
|
|
||||||
# nonblocking socket handshaking on connect got disabled so let's pretend it's disabled
|
|
||||||
# even when it's on
|
|
||||||
super(GreenSSLSocket, self).__init__(
|
|
||||||
sock.fd, keyfile, certfile, server_side, cert_reqs, ssl_version,
|
|
||||||
ca_certs, do_handshake_on_connect and six.PY2, *args, **kw)
|
|
||||||
-
|
|
||||||
# the superclass initializer trashes the methods so we remove
|
|
||||||
# the local-object versions of them and let the actual class
|
|
||||||
# methods shine through
|
|
||||||
@@ -354,7 +365,7 @@ class GreenSSLSocket(_original_sslsocket):
|
|
||||||
except NameError:
|
|
||||||
self._sslobj = sslobj
|
|
||||||
else:
|
|
||||||
- if sys.version_info < (3, 7):
|
|
||||||
+ if _is_under_py_3_7:
|
|
||||||
self._sslobj = SSLObject(sslobj, owner=self)
|
|
||||||
else:
|
|
||||||
self._sslobj = sslobj
|
|
||||||
@@ -396,6 +407,7 @@ class GreenSSLSocket(_original_sslsocket):
|
|
||||||
def dup(self):
|
|
||||||
raise NotImplementedError("Can't dup an ssl object")
|
|
||||||
|
|
||||||
+
|
|
||||||
SSLSocket = GreenSSLSocket
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
2.21.0
|
|
||||||
|
|
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:d9d31a3c8dbcedbcce5859a919956d934685b17323fc80e1077cb344a2ffa68d
|
|
||||||
size 391579
|
|
3
eventlet-0.25.0.tar.gz
Normal file
3
eventlet-0.25.0.tar.gz
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:f0610bd0d3bb3d51d69f74caa4ad04fc7bce424cdb72e54d08ccda90d8c69800
|
||||||
|
size 392105
|
@@ -1,3 +1,16 @@
|
|||||||
|
-------------------------------------------------------------------
|
||||||
|
Fri Jun 7 12:14:00 UTC 2019 - Tomáš Chvátal <tchvatal@suse.com>
|
||||||
|
|
||||||
|
- Do not generate sphinx docu, it is online and now we have only
|
||||||
|
python3 Sphinx anyway
|
||||||
|
- Update to 0.25.0:
|
||||||
|
* Support for new python and ssl
|
||||||
|
- Remove patches that are in upstream release:
|
||||||
|
* 0001-IMPORTANT-late-import-in-use_hub-thread-race-caused-.patch
|
||||||
|
* 0001-ssl-connect-used-non-monotonic-time.time-for-timeout.patch
|
||||||
|
* 0002-Fix-for-Python-3.7-506.patch
|
||||||
|
* 0003-Fix-compatibility-with-Python-3.7-ssl.SSLSocket-531.patch
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Mon Apr 29 06:00:44 UTC 2019 - Thomas Bechtold <tbechtold@suse.com>
|
Mon Apr 29 06:00:44 UTC 2019 - Thomas Bechtold <tbechtold@suse.com>
|
||||||
|
|
||||||
|
@@ -18,26 +18,22 @@
|
|||||||
|
|
||||||
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
|
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
|
||||||
Name: python-eventlet
|
Name: python-eventlet
|
||||||
Version: 0.24.1
|
Version: 0.25.0
|
||||||
Release: 0
|
Release: 0
|
||||||
Summary: Concurrent networking library for Python
|
Summary: Concurrent networking library for Python
|
||||||
License: MIT
|
License: MIT
|
||||||
Group: Development/Languages/Python
|
Group: Development/Languages/Python
|
||||||
URL: http://eventlet.net
|
URL: http://eventlet.net
|
||||||
Source: https://files.pythonhosted.org/packages/source/e/eventlet/eventlet-%{version}.tar.gz
|
Source: https://files.pythonhosted.org/packages/source/e/eventlet/eventlet-%{version}.tar.gz
|
||||||
# PATCH-FIX-UPSTREAM 0001-IMPORTANT-late-import-in-use_hub-thread-race-caused-.patch -- https://github.com/eventlet/eventlet/commit/77bccbe48d4d9a46982b2e0503e76784e76b066a
|
BuildRequires: %{python_module dnspython >= 1.15.0}
|
||||||
Patch0: 0001-IMPORTANT-late-import-in-use_hub-thread-race-caused-.patch
|
BuildRequires: %{python_module greenlet >= 0.3}
|
||||||
# PATCH-FIX-UPSTREAM 0001-ssl-connect-used-non-monotonic-time.time-for-timeout.patch -- https://github.com/eventlet/eventlet/commit/a28a275393d3c3ae3c3a5341cc4764fad21be3e5
|
BuildRequires: %{python_module monotonic >= 1.4}
|
||||||
Patch1: 0001-ssl-connect-used-non-monotonic-time.time-for-timeout.patch
|
BuildRequires: %{python_module nose}
|
||||||
# PATCH-FIX-UPSTREAM 0002-Fix-for-Python-3.7-506.patch -- https://github.com/eventlet/eventlet/commit/cf47cb518db3e0dbdd48473fb40cf9f6ecd50e07
|
BuildRequires: %{python_module pyOpenSSL}
|
||||||
Patch2: 0002-Fix-for-Python-3.7-506.patch
|
|
||||||
# PATCH-FIX-UPSTREAM 0003-Fix-compatibility-with-Python-3.7-ssl.SSLSocket-531.patch -- https://github.com/eventlet/eventlet/commit/a915bb642dd6cd4e92c959addff30509977a637c
|
|
||||||
Patch3: 0003-Fix-compatibility-with-Python-3.7-ssl.SSLSocket-531.patch
|
|
||||||
|
|
||||||
BuildRequires: %{python_module Sphinx}
|
|
||||||
BuildRequires: %{python_module greenlet}
|
|
||||||
BuildRequires: %{python_module setuptools}
|
BuildRequires: %{python_module setuptools}
|
||||||
|
BuildRequires: %{python_module six >= 1.10.0}
|
||||||
BuildRequires: fdupes
|
BuildRequires: fdupes
|
||||||
|
BuildRequires: netcfg
|
||||||
BuildRequires: python-rpm-macros
|
BuildRequires: python-rpm-macros
|
||||||
# eventlet parses /etc/protocols which is not available in normal build envs
|
# eventlet parses /etc/protocols which is not available in normal build envs
|
||||||
Requires: netcfg
|
Requires: netcfg
|
||||||
@@ -45,6 +41,7 @@ Requires: python-dnspython >= 1.15.0
|
|||||||
Requires: python-greenlet >= 0.3
|
Requires: python-greenlet >= 0.3
|
||||||
Requires: python-monotonic >= 1.4
|
Requires: python-monotonic >= 1.4
|
||||||
Requires: python-six >= 1.10.0
|
Requires: python-six >= 1.10.0
|
||||||
|
Obsoletes: python-doc
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
%if %{python_version_nodots} < 34
|
%if %{python_version_nodots} < 34
|
||||||
Requires: python-enum34
|
Requires: python-enum34
|
||||||
@@ -61,38 +58,24 @@ to threading, but provide the benefits of non-blocking I/O. The event dispatch
|
|||||||
is implicit, which means Eventlet can be used from the Python
|
is implicit, which means Eventlet can be used from the Python
|
||||||
interpreter, or as part of a larger application.
|
interpreter, or as part of a larger application.
|
||||||
|
|
||||||
%package doc
|
|
||||||
Summary: Documentation for the Eventlet concurrent networking library
|
|
||||||
Group: Development/Libraries/Python
|
|
||||||
Requires: %{name} = %{version}
|
|
||||||
|
|
||||||
%description doc
|
|
||||||
Documentation for Eventlet, which is a concurrent networking library
|
|
||||||
for Python that allows changing how code is run.
|
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q -n eventlet-%{version}
|
%setup -q -n eventlet-%{version}
|
||||||
%patch0 -p1
|
|
||||||
%patch1 -p1
|
|
||||||
%patch2 -p1
|
|
||||||
%patch3 -p1
|
|
||||||
sed -i '/enum.compat/d' setup.py # crude way to drop the strange "enum-compat" requirement
|
|
||||||
sed -i "s|^#!.*||" eventlet/support/greendns.py # Fix non-executable script
|
sed -i "s|^#!.*||" eventlet/support/greendns.py # Fix non-executable script
|
||||||
|
|
||||||
%build
|
%build
|
||||||
%python_build
|
%python_build
|
||||||
%python_exec setup.py build_sphinx && rm build/sphinx/html/.buildinfo
|
|
||||||
|
|
||||||
%install
|
%install
|
||||||
%python_install
|
%python_install
|
||||||
%python_expand %fdupes %{buildroot}%{$python_sitelib}
|
%python_expand %fdupes %{buildroot}%{$python_sitelib}
|
||||||
|
|
||||||
|
%check
|
||||||
|
# 400 out of 600 tests either fail or error out
|
||||||
|
#%%python_expand PYTHONPATH=%{buildroot}%{$python_sitelib} nosetests-%{$python_bin_suffix} -v
|
||||||
|
|
||||||
%files %{python_files}
|
%files %{python_files}
|
||||||
%license LICENSE
|
%license LICENSE
|
||||||
%doc AUTHORS NEWS README.rst
|
%doc AUTHORS NEWS README.rst
|
||||||
%{python_sitelib}/*
|
%{python_sitelib}/*
|
||||||
|
|
||||||
%files %{python_files doc}
|
|
||||||
%doc build/sphinx/html examples
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
Reference in New Issue
Block a user