Commit d9e2479b authored by Jason Madden's avatar Jason Madden

More removal of obsolete code.

parent 07035b7e
...@@ -427,6 +427,8 @@ def run_setup(ext_modules): ...@@ -427,6 +427,8 @@ def run_setup(ext_modules):
# leak checks. previously we had a hand-rolled version. # leak checks. previously we had a hand-rolled version.
'objgraph', 'objgraph',
# We still have some places we like to test with pkg_resources
'setuptools',
], ],
}, },
# It's always safe to pass the CFFI keyword, even if # It's always safe to pass the CFFI keyword, even if
......
...@@ -12,12 +12,6 @@ import sys ...@@ -12,12 +12,6 @@ import sys
import os import os
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] >= 3
PY35 = sys.version_info[:2] >= (3, 5)
PY36 = sys.version_info[:2] >= (3, 6)
PY37 = sys.version_info[:2] >= (3, 7)
PY38 = sys.version_info[:2] >= (3, 8)
PY39 = sys.version_info[:2] >= (3, 9) PY39 = sys.version_info[:2] >= (3, 9)
PY311 = sys.version_info[:2] >= (3, 11) PY311 = sys.version_info[:2] >= (3, 11)
PYPY = hasattr(sys, 'pypy_version_info') PYPY = hasattr(sys, 'pypy_version_info')
...@@ -30,20 +24,12 @@ PURE_PYTHON = PYPY or os.getenv('PURE_PYTHON') ...@@ -30,20 +24,12 @@ PURE_PYTHON = PYPY or os.getenv('PURE_PYTHON')
## Types ## Types
if PY3:
string_types = (str,) string_types = (str,)
integer_types = (int,) integer_types = (int,)
text_type = str text_type = str
native_path_types = (str, bytes) native_path_types = (str, bytes)
thread_mod_name = '_thread' thread_mod_name = '_thread'
else:
import __builtin__ # pylint:disable=import-error
string_types = (__builtin__.basestring,)
text_type = __builtin__.unicode
integer_types = (int, __builtin__.long)
native_path_types = string_types
thread_mod_name = 'thread'
hostname_types = tuple(set(string_types + (bytearray, bytes))) hostname_types = tuple(set(string_types + (bytearray, bytes)))
...@@ -51,27 +37,20 @@ def NativeStrIO(): ...@@ -51,27 +37,20 @@ def NativeStrIO():
import io import io
return io.BytesIO() if str is bytes else io.StringIO() return io.BytesIO() if str is bytes else io.StringIO()
try:
from abc import ABC from abc import ABC # pylint:disable=unused-import
except ImportError:
import abc
ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()})
del abc
## Exceptions ## Exceptions
if PY3:
def reraise(t, value, tb=None): # pylint:disable=unused-argument def reraise(t, value, tb=None): # pylint:disable=unused-argument
if value.__traceback__ is not tb and tb is not None: if value.__traceback__ is not tb and tb is not None:
raise value.with_traceback(tb) raise value.with_traceback(tb)
raise value raise value
def exc_clear(): def exc_clear():
pass pass
else:
from gevent._util_py2 import reraise # pylint:disable=import-error,no-name-in-module
reraise = reraise # export
exc_clear = sys.exc_clear
## import locks ## import locks
try: try:
...@@ -86,127 +65,28 @@ imp_acquire_lock = imp.acquire_lock ...@@ -86,127 +65,28 @@ imp_acquire_lock = imp.acquire_lock
imp_release_lock = imp.release_lock imp_release_lock = imp.release_lock
## Functions ## Functions
if PY3: iteritems = dict.items
iteritems = dict.items itervalues = dict.values
itervalues = dict.values xrange = range
xrange = range izip = zip
izip = zip
else:
iteritems = dict.iteritems # python 3: pylint:disable=no-member
itervalues = dict.itervalues # python 3: pylint:disable=no-member
xrange = __builtin__.xrange
from itertools import izip # python 3: pylint:disable=no-member,no-name-in-module
izip = izip
## The __fspath__ protocol
try: ## The __fspath__ protocol
from os import PathLike # pylint:disable=unused-import from os import PathLike # pylint:disable=unused-import
except ImportError: from os import fspath
class PathLike(ABC): _fspath = fspath
@classmethod from os import fsencode # pylint:disable=unused-import
def __subclasshook__(cls, subclass): from os import fsdecode # pylint:disable=unused-import
return hasattr(subclass, '__fspath__')
# fspath from 3.6 os.py, but modified to raise the same exceptions as the
# real native implementation.
# Define for testing
def _fspath(path):
"""
Return the path representation of a path-like object.
If str or bytes is passed in, it is returned unchanged. Otherwise the
os.PathLike interface is used to get the path representation. If the
path representation is not str or bytes, TypeError is raised. If the
provided path is not str, bytes, or os.PathLike, TypeError is raised.
"""
if isinstance(path, native_path_types):
return path
# Work from the object's type to match method resolution of other magic
# methods.
path_type = type(path)
try:
path_type_fspath = path_type.__fspath__
except AttributeError:
raise TypeError("expected str, bytes or os.PathLike object, "
"not " + path_type.__name__)
path_repr = path_type_fspath(path)
if isinstance(path_repr, native_path_types):
return path_repr
raise TypeError("expected {}.__fspath__() to return str or bytes, "
"not {}".format(path_type.__name__,
type(path_repr).__name__))
try:
from os import fspath # pylint: disable=unused-import,no-name-in-module
except ImportError:
# if not available, use the Python version as transparently as
# possible
fspath = _fspath
fspath.__name__ = 'fspath'
try:
from os import fsencode # pylint: disable=unused-import,no-name-in-module
except ImportError:
encoding = sys.getfilesystemencoding() or ('utf-8' if not WIN else 'mbcs')
errors = 'strict' if WIN and encoding == 'mbcs' else 'surrogateescape'
# Added in 3.2, so this is for Python 2.7. Note that it doesn't have
# sys.getfilesystemencodeerrors(), which was added in 3.6
def fsencode(filename):
"""Encode filename (an os.PathLike, bytes, or str) to the filesystem
encoding with 'surrogateescape' error handler, return bytes unchanged.
On Windows, use 'strict' error handler if the file system encoding is
'mbcs' (which is the default encoding).
"""
filename = fspath(filename) # Does type-checking of `filename`.
if isinstance(filename, bytes):
return filename
try:
return filename.encode(encoding, errors)
except LookupError:
# Can't encode it, and the error handler doesn't
# exist. Probably on Python 2 with an astral character.
# Not sure how to handle this.
raise UnicodeEncodeError("Can't encode path to filesystem encoding")
try:
from os import fsdecode # pylint:disable=unused-import
except ImportError:
def fsdecode(filename):
"""Decode filename (an os.PathLike, bytes, or str) from the filesystem
encoding with 'surrogateescape' error handler, return str unchanged. On
Windows, use 'strict' error handler if the file system encoding is
'mbcs' (which is the default encoding).
"""
filename = fspath(filename) # Does type-checking of `filename`.
if PY3 and isinstance(filename, bytes):
return filename.decode(encoding, errors)
return filename
## Clocks ## Clocks
try: # Python 3.3+ (PEP 418)
# Python 3.3+ (PEP 418) from time import perf_counter
from time import perf_counter from time import get_clock_info
from time import get_clock_info from time import monotonic
from time import monotonic perf_counter = perf_counter
perf_counter = perf_counter monotonic = monotonic
monotonic = monotonic get_clock_info = get_clock_info
get_clock_info = get_clock_info
except ImportError:
import time
if sys.platform == "win32":
perf_counter = time.clock # pylint:disable=no-member
else:
perf_counter = time.time
monotonic = perf_counter
def get_clock_info(_):
return 'Unknown'
## Monitoring ## Monitoring
def get_this_psutil_process(): def get_this_psutil_process():
......
...@@ -14,7 +14,6 @@ import sys ...@@ -14,7 +14,6 @@ import sys
import os import os
from gevent.hub import _get_hub_noargs as get_hub from gevent.hub import _get_hub_noargs as get_hub
from gevent._compat import PY2
from gevent._compat import integer_types from gevent._compat import integer_types
from gevent._compat import reraise from gevent._compat import reraise
from gevent._compat import fspath from gevent._compat import fspath
...@@ -393,18 +392,12 @@ class OpenDescriptor(object): # pylint:disable=too-many-instance-attributes ...@@ -393,18 +392,12 @@ class OpenDescriptor(object): # pylint:disable=too-many-instance-attributes
if not self.binary: if not self.binary:
# Either native or text at this point. # Either native or text at this point.
if PY2 and self.native: # Python 2 and text mode, or Python 3 and either text or native (both are the same)
# Neither text mode nor binary mode specified. if not isinstance(raw, io.TextIOBase):
if self.universal: # Avoid double-wrapping a TextIOBase in another TextIOWrapper.
# universal was requested, e.g., 'rU' # That tends not to work. See https://github.com/gevent/gevent/issues/1542
result = UniversalNewlineBytesWrapper(result, line_buffering) result = io.TextIOWrapper(result, self.encoding, self.errors, self.newline,
else: line_buffering)
# Python 2 and text mode, or Python 3 and either text or native (both are the same)
if not isinstance(raw, io.TextIOBase):
# Avoid double-wrapping a TextIOBase in another TextIOWrapper.
# That tends not to work. See https://github.com/gevent/gevent/issues/1542
result = io.TextIOWrapper(result, self.encoding, self.errors, self.newline,
line_buffering)
if result is not raw or self._raw_object_is_new(raw): if result is not raw or self._raw_object_is_new(raw):
# Set the mode, if possible, but only if we created a new # Set the mode, if possible, but only if we created a new
......
...@@ -12,7 +12,7 @@ from __future__ import absolute_import, print_function ...@@ -12,7 +12,7 @@ from __future__ import absolute_import, print_function
import importlib import importlib
import sys import sys
from gevent._compat import PY3
from gevent._compat import iteritems from gevent._compat import iteritems
from gevent._compat import imp_acquire_lock from gevent._compat import imp_acquire_lock
from gevent._compat import imp_release_lock from gevent._compat import imp_release_lock
...@@ -25,23 +25,20 @@ MAPPING = { ...@@ -25,23 +25,20 @@ MAPPING = {
'gevent.local': '_threading_local', 'gevent.local': '_threading_local',
'gevent.socket': 'socket', 'gevent.socket': 'socket',
'gevent.select': 'select', 'gevent.select': 'select',
'gevent.selectors': 'selectors' if PY3 else 'selectors2', 'gevent.selectors': 'selectors',
'gevent.ssl': 'ssl', 'gevent.ssl': 'ssl',
'gevent.thread': '_thread' if PY3 else 'thread', 'gevent.thread': '_thread',
'gevent.subprocess': 'subprocess', 'gevent.subprocess': 'subprocess',
'gevent.os': 'os', 'gevent.os': 'os',
'gevent.threading': 'threading', 'gevent.threading': 'threading',
'gevent.builtins': 'builtins' if PY3 else '__builtin__', 'gevent.builtins': 'builtins',
'gevent.signal': 'signal', 'gevent.signal': 'signal',
'gevent.time': 'time', 'gevent.time': 'time',
'gevent.queue': 'queue' if PY3 else 'Queue', 'gevent.queue': 'queue',
'gevent.contextvars': 'contextvars', 'gevent.contextvars': 'contextvars',
} }
OPTIONAL_STDLIB_MODULES = frozenset() if PY3 else frozenset([ OPTIONAL_STDLIB_MODULES = frozenset()
'selectors2',
])
_PATCH_PREFIX = '__g_patched_module_' _PATCH_PREFIX = '__g_patched_module_'
def _collect_stdlib_gevent_modules(): def _collect_stdlib_gevent_modules():
......
...@@ -270,10 +270,16 @@ def getfqdn(name=''): ...@@ -270,10 +270,16 @@ def getfqdn(name=''):
First the hostname returned by gethostbyaddr() is checked, then First the hostname returned by gethostbyaddr() is checked, then
possibly existing aliases. In case no FQDN is available, hostname possibly existing aliases. In case no FQDN is available, hostname
from gethostname() is returned. from gethostname() is returned.
.. versionchanged:: NEXT
The IPv6 generic address '::' now returns the result of
``gethostname``, like the IPv4 address '0.0.0.0'.
""" """
# pylint: disable=undefined-variable # pylint: disable=undefined-variable
name = name.strip() name = name.strip()
if not name or name == '0.0.0.0': # IPv6 added in a late Python 3.10/3.11 patch release.
# https://github.com/python/cpython/issues/100374
if not name or name in ('0.0.0.0', '::'):
name = gethostname() name = gethostname()
try: try:
hostname, aliases, _ = gethostbyaddr(name) hostname, aliases, _ = gethostbyaddr(name)
......
...@@ -13,13 +13,13 @@ import ssl as __ssl__ ...@@ -13,13 +13,13 @@ import ssl as __ssl__
_ssl = __ssl__._ssl _ssl = __ssl__._ssl
import errno import errno
import sys
from gevent.socket import socket, timeout_default from gevent.socket import socket, timeout_default
from gevent.socket import error as socket_error from gevent.socket import error as socket_error
from gevent.socket import timeout as _socket_timeout from gevent.socket import timeout as _socket_timeout
from gevent._util import copy_globals from gevent._util import copy_globals
from gevent._compat import PY36
from weakref import ref as _wref from weakref import ref as _wref
...@@ -49,8 +49,8 @@ from ssl import SSL_ERROR_EOF ...@@ -49,8 +49,8 @@ from ssl import SSL_ERROR_EOF
from ssl import SSL_ERROR_WANT_READ from ssl import SSL_ERROR_WANT_READ
from ssl import SSL_ERROR_WANT_WRITE from ssl import SSL_ERROR_WANT_WRITE
from ssl import PROTOCOL_SSLv23 from ssl import PROTOCOL_SSLv23
from ssl import SSLObject #from ssl import SSLObject
from ssl import match_hostname
from ssl import CHANNEL_BINDING_TYPES from ssl import CHANNEL_BINDING_TYPES
from ssl import CERT_REQUIRED from ssl import CERT_REQUIRED
from ssl import DER_cert_to_PEM_cert from ssl import DER_cert_to_PEM_cert
...@@ -674,32 +674,14 @@ class SSLSocket(socket): ...@@ -674,32 +674,14 @@ class SSLSocket(socket):
raise raise
self._wait(self._write_event, timeout_exc=_SSLErrorHandshakeTimeout) self._wait(self._write_event, timeout_exc=_SSLErrorHandshakeTimeout)
if sys.version_info[:2] < (3, 7) and self._context.check_hostname: # 3.7+, making it difficult to create these objects.
# In Python 3.7, the underlying OpenSSL name matching is used. # There's a new type, _ssl.SSLSocket, that takes the
# The version implemented in Python doesn't understand IDNA encoding. # place of SSLObject for self._sslobj. This one does it all.
if not self.server_hostname: def __create_sslobj(self, server_side=False, session=None):
raise ValueError("check_hostname needs server_hostname " return self.context._wrap_socket(
"argument") self._sock, server_side, self.server_hostname,
match_hostname(self.getpeercert(), self.server_hostname) # pylint:disable=deprecated-method owner=self._sock, session=session
)
if hasattr(SSLObject, '_create'):
# 3.7+, making it difficult to create these objects.
# There's a new type, _ssl.SSLSocket, that takes the
# place of SSLObject for self._sslobj. This one does it all.
def __create_sslobj(self, server_side=False, session=None):
return self.context._wrap_socket(
self._sock, server_side, self.server_hostname,
owner=self._sock, session=session
)
elif PY36: # 3.6
def __create_sslobj(self, server_side=False, session=None):
sslobj = self._context._wrap_socket(self._sock, server_side, self.server_hostname)
return SSLObject(sslobj, owner=self._sock, session=session)
else: # 3.5
def __create_sslobj(self, server_side=False, session=None): # pylint:disable=unused-argument
sslobj = self._context._wrap_socket(self._sock, server_side, self.server_hostname)
return SSLObject(sslobj, owner=self._sock)
def _real_connect(self, addr, connect_ex): def _real_connect(self, addr, connect_ex):
if self.server_side: if self.server_side:
......
...@@ -9,8 +9,6 @@ from collections import deque ...@@ -9,8 +9,6 @@ from collections import deque
from gevent import monkey from gevent import monkey
from gevent._compat import thread_mod_name from gevent._compat import thread_mod_name
from gevent._compat import PY3
__all__ = [ __all__ = [
'Lock', 'Lock',
...@@ -33,21 +31,10 @@ start_new_thread, Lock, get_thread_ident, = monkey.get_original(thread_mod_name, ...@@ -33,21 +31,10 @@ start_new_thread, Lock, get_thread_ident, = monkey.get_original(thread_mod_name,
# #
# #
# In all cases, a timeout value of -1 means "infinite". Sigh. # In all cases, a timeout value of -1 means "infinite". Sigh.
if PY3: def acquire_with_timeout(lock, timeout=-1):
def acquire_with_timeout(lock, timeout=-1): globals()['acquire_with_timeout'] = type(lock).acquire
globals()['acquire_with_timeout'] = type(lock).acquire return lock.acquire(timeout=timeout)
return lock.acquire(timeout=timeout)
else:
def acquire_with_timeout(lock, timeout=-1,
_time=monkey.get_original('time', 'time'),
_sleep=monkey.get_original('time', 'sleep')):
deadline = _time() + timeout if timeout != -1 else None
while 1:
if lock.acquire(False): # Can we acquire non-blocking?
return True
if deadline is not None and _time() >= deadline:
return False
_sleep(0.005)
class _Condition(object): class _Condition(object):
# We could use libuv's ``uv_cond_wait`` to implement this whole # We could use libuv's ``uv_cond_wait`` to implement this whole
......
...@@ -18,8 +18,7 @@ from gevent.greenlet import Greenlet ...@@ -18,8 +18,7 @@ from gevent.greenlet import Greenlet
from gevent.hub import getcurrent from gevent.hub import getcurrent
from gevent.server import StreamServer from gevent.server import StreamServer
from gevent.pool import Pool from gevent.pool import Pool
from gevent._compat import PY36
from gevent._compat import exc_clear
__all__ = [ __all__ = [
'BackdoorServer', 'BackdoorServer',
...@@ -174,15 +173,13 @@ class BackdoorServer(StreamServer): ...@@ -174,15 +173,13 @@ class BackdoorServer(StreamServer):
getcurrent().switch_in() getcurrent().switch_in()
try: try:
console = InteractiveConsole(self._create_interactive_locals()) console = InteractiveConsole(self._create_interactive_locals())
if PY36: # Beginning in 3.6, the console likes to print "now exiting <class>"
# Beginning in 3.6, the console likes to print "now exiting <class>" # but probably our socket is already closed, so this just causes problems.
# but probably our socket is already closed, so this just causes problems. console.interact(banner=self.banner, exitmsg='') # pylint:disable=unexpected-keyword-arg
console.interact(banner=self.banner, exitmsg='') # pylint:disable=unexpected-keyword-arg
else:
console.interact(banner=self.banner)
except SystemExit: except SystemExit:
# raised by quit(); obviously this cannot propagate. # raised by quit(); obviously this cannot propagate.
exc_clear() # Python 2 pass
finally: finally:
raw_file.close() raw_file.close()
conn.close() conn.close()
......
...@@ -5,25 +5,14 @@ from __future__ import absolute_import ...@@ -5,25 +5,14 @@ from __future__ import absolute_import
import weakref import weakref
from gevent.lock import RLock from gevent.lock import RLock
from gevent._compat import PY3
from gevent._compat import imp_acquire_lock from gevent._compat import imp_acquire_lock
from gevent._compat import imp_release_lock from gevent._compat import imp_release_lock
# Normally we'd have the "expected" case inside the try
# (Python 3, because Python 3 is the way forward). But
# under Python 2, the popular `future` library *also* provides
# a `builtins` module---which lacks the __import__ attribute.
# So we test for the old, deprecated version first
try: # Py2 import builtins as __gbuiltins__
import __builtin__ as __gbuiltins__ _allowed_module_name_types = (str,)
_allowed_module_name_types = (basestring,) # pylint:disable=undefined-variable __target__ = 'builtins'
__target__ = '__builtin__'
except ImportError:
import builtins as __gbuiltins__ # pylint: disable=import-error
_allowed_module_name_types = (str,)
__target__ = 'builtins'
_import = __gbuiltins__.__import__ _import = __gbuiltins__.__import__
...@@ -121,11 +110,9 @@ def _lock_imports(): ...@@ -121,11 +110,9 @@ def _lock_imports():
global __lock_imports global __lock_imports
__lock_imports = True __lock_imports = True
if PY3:
__implements__ = [] __implements__ = []
__import__ = _import __import__ = _import
else:
__implements__ = ['__import__']
__all__ = __implements__ __all__ = __implements__
......
...@@ -53,12 +53,12 @@ try: ...@@ -53,12 +53,12 @@ try:
except ImportError: except ImportError:
from collections import Mapping # pylint:disable=deprecated-class from collections import Mapping # pylint:disable=deprecated-class
from gevent._compat import PY37
from gevent._util import _NONE from gevent._util import _NONE
from gevent.local import local from gevent.local import local
__stdlib_expected__ = __all__ __stdlib_expected__ = __all__
__implements__ = __stdlib_expected__ if PY37 else None __implements__ = __stdlib_expected__
# In the reference implementation, the interpreter level OS thread state # In the reference implementation, the interpreter level OS thread state
# is modified to contain a pointer to the current context. Obviously we can't # is modified to contain a pointer to the current context. Obviously we can't
......
...@@ -130,7 +130,7 @@ def notify_and_call_entry_points(event): ...@@ -130,7 +130,7 @@ def notify_and_call_entry_points(event):
entry_points = set( entry_points = set(
ep ep
for ep for ep
in ep_dict.get(event.ENTRY_POINT_NAME) in ep_dict.get(event.ENTRY_POINT_NAME, ())
) )
for plugin in entry_points: for plugin in entry_points:
......
...@@ -597,21 +597,7 @@ if local.__module__ == 'gevent.local': ...@@ -597,21 +597,7 @@ if local.__module__ == 'gevent.local':
# module has a different name than the pure-Python version and we can check for that. # module has a different name than the pure-Python version and we can check for that.
# It's not as direct, but it works. # It's not as direct, but it works.
# So here we're not compiled # So here we're not compiled
from gevent._compat import PYPY local.__new__ = classmethod(__new__)
from gevent._compat import PY2
if PYPY and PY2:
# The behaviour changed with no warning between PyPy2 7.3.2 and 7.3.3.
local.__new__ = __new__
try:
local() # <= 7.3.2
except TypeError:
# >= 7.3.3
local.__new__ = classmethod(__new__)
else:
local.__new__ = classmethod(__new__)
del PYPY
del PY2
else: # pragma: no cover else: # pragma: no cover
# Make sure we revisit in case of changes to the (accelerator) module names. # Make sure we revisit in case of changes to the (accelerator) module names.
if local.__module__ != 'gevent._gevent_clocal': if local.__module__ != 'gevent._gevent_clocal':
......
...@@ -12,7 +12,7 @@ from __future__ import print_function ...@@ -12,7 +12,7 @@ from __future__ import print_function
from gevent.hub import getcurrent from gevent.hub import getcurrent
from gevent._compat import PURE_PYTHON from gevent._compat import PURE_PYTHON
from gevent._compat import PY2
# This is the one exception to the rule of where to # This is the one exception to the rule of where to
# import Semaphore, obviously # import Semaphore, obviously
from gevent import monkey from gevent import monkey
...@@ -180,8 +180,6 @@ def _fixup_docstrings(): ...@@ -180,8 +180,6 @@ def _fixup_docstrings():
assert c.__doc__ == b.__doc__ assert c.__doc__ == b.__doc__
for m in 'acquire', 'release', 'wait': for m in 'acquire', 'release', 'wait':
c_meth = getattr(c, m) c_meth = getattr(c, m)
if PY2:
c_meth = c_meth.__func__
b_meth = getattr(b, m) b_meth = getattr(b, m)
c_meth.__doc__ = b_meth.__doc__ c_meth.__doc__ = b_meth.__doc__
......
This diff is collapsed.
...@@ -48,7 +48,6 @@ import sys ...@@ -48,7 +48,6 @@ import sys
from gevent.hub import _get_hub_noargs as get_hub from gevent.hub import _get_hub_noargs as get_hub
from gevent.hub import reinit from gevent.hub import reinit
from gevent._config import config from gevent._config import config
from gevent._compat import PY3
from gevent._util import copy_globals from gevent._util import copy_globals
import errno import errno
...@@ -102,8 +101,6 @@ if fcntl: ...@@ -102,8 +101,6 @@ if fcntl:
except OSError as e: except OSError as e:
if e.errno not in ignored_errors: if e.errno not in ignored_errors:
raise raise
if not PY3:
sys.exc_clear()
if hub is None: if hub is None:
hub = get_hub() hub = get_hub()
event = hub.loop.io(fd, 1) event = hub.loop.io(fd, 1)
...@@ -133,8 +130,6 @@ if fcntl: ...@@ -133,8 +130,6 @@ if fcntl:
except OSError as e: except OSError as e:
if e.errno not in ignored_errors: if e.errno not in ignored_errors:
raise raise
if not PY3:
sys.exc_clear()
if hub is None: if hub is None:
hub = get_hub() hub = get_hub()
event = hub.loop.io(fd, 2) event = hub.loop.io(fd, 2)
......
...@@ -31,13 +31,10 @@ from gevent import socket ...@@ -31,13 +31,10 @@ from gevent import socket
import gevent import gevent
from gevent.server import StreamServer from gevent.server import StreamServer
from gevent.hub import GreenletExit from gevent.hub import GreenletExit
from gevent._compat import PY3, reraise from gevent._compat import reraise
from functools import partial from functools import partial
if PY3: unquote_latin1 = partial(unquote, encoding='latin-1')
unquote_latin1 = partial(unquote, encoding='latin-1')
else:
unquote_latin1 = unquote
_no_undoc_members = True # Don't put undocumented things into sphinx _no_undoc_members = True # Don't put undocumented things into sphinx
...@@ -89,8 +86,7 @@ def format_date_time(timestamp): ...@@ -89,8 +86,7 @@ def format_date_time(timestamp):
# Return a byte string, not a native string # Return a byte string, not a native string
year, month, day, hh, mm, ss, wd, _y, _z = time.gmtime(timestamp) year, month, day, hh, mm, ss, wd, _y, _z = time.gmtime(timestamp)
value = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (_WEEKDAYNAME[wd], day, _MONTHNAME[month], year, hh, mm, ss) value = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (_WEEKDAYNAME[wd], day, _MONTHNAME[month], year, hh, mm, ss)
if PY3: value = value.encode("latin-1")
value = value.encode("latin-1")
return value return value
...@@ -392,13 +388,9 @@ class WSGIHandler(object): ...@@ -392,13 +388,9 @@ class WSGIHandler(object):
# pylint:disable=too-many-instance-attributes # pylint:disable=too-many-instance-attributes
protocol_version = 'HTTP/1.1' protocol_version = 'HTTP/1.1'
if PY3:
# if we do like Py2, then headers_factory unconditionally def MessageClass(self, *args):
# becomes a bound method, meaning the fp argument becomes WSGIHandler return headers_factory(*args)
def MessageClass(self, *args):
return headers_factory(*args)
else:
MessageClass = headers_factory
# Attributes reset at various times for each request; not public # Attributes reset at various times for each request; not public
# documented. Class attributes to keep the constructor fast # documented. Class attributes to keep the constructor fast
...@@ -562,10 +554,10 @@ class WSGIHandler(object): ...@@ -562,10 +554,10 @@ class WSGIHandler(object):
if self.request_version == "HTTP/1.1": if self.request_version == "HTTP/1.1":
conntype = self.headers.get("Connection", "").lower() conntype = self.headers.get("Connection", "").lower()
self.close_connection = (conntype == 'close') self.close_connection = (conntype == 'close') # pylint:disable=superfluous-parens
elif self.request_version == 'HTTP/1.0': elif self.request_version == 'HTTP/1.0':
conntype = self.headers.get("Connection", "close").lower() conntype = self.headers.get("Connection", "close").lower()
self.close_connection = (conntype != 'keep-alive') self.close_connection = (conntype != 'keep-alive') # pylint:disable=superfluous-parens
else: else:
# XXX: HTTP 0.9. We should drop support # XXX: HTTP 0.9. We should drop support
self.close_connection = True self.close_connection = True
...@@ -606,8 +598,7 @@ class WSGIHandler(object): ...@@ -606,8 +598,7 @@ class WSGIHandler(object):
latin-1). latin-1).
""" """
line = self.rfile.readline(MAX_REQUEST_LINE) line = self.rfile.readline(MAX_REQUEST_LINE)
if PY3: line = line.decode('latin-1')
line = line.decode('latin-1')
return line return line
def handle_one_request(self): def handle_one_request(self):
...@@ -659,7 +650,7 @@ class WSGIHandler(object): ...@@ -659,7 +650,7 @@ class WSGIHandler(object):
try: try:
self.requestline = self.read_requestline() self.requestline = self.read_requestline()
# Account for old subclasses that haven't done this # Account for old subclasses that haven't done this
if PY3 and isinstance(self.requestline, bytes): if isinstance(self.requestline, bytes):
self.requestline = self.requestline.decode('latin-1') self.requestline = self.requestline.decode('latin-1')
except socket.error: except socket.error:
# "Connection reset by peer" or other socket errors aren't interesting here # "Connection reset by peer" or other socket errors aren't interesting here
...@@ -720,8 +711,7 @@ class WSGIHandler(object): ...@@ -720,8 +711,7 @@ class WSGIHandler(object):
if hasattr(self.result, '__len__'): if hasattr(self.result, '__len__'):
total_len = sum(len(chunk) for chunk in self.result) total_len = sum(len(chunk) for chunk in self.result)
total_len_str = str(total_len) total_len_str = str(total_len)
if PY3: total_len_str = total_len_str.encode("latin-1")
total_len_str = total_len_str.encode("latin-1")
self.response_headers.append((b'Content-Length', total_len_str)) self.response_headers.append((b'Content-Length', total_len_str))
else: else:
self.response_use_chunked = ( self.response_use_chunked = (
...@@ -856,8 +846,8 @@ class WSGIHandler(object): ...@@ -856,8 +846,8 @@ class WSGIHandler(object):
# Note: Some Python 2 implementations, like Jython, may allow non-octet (above 255) values # Note: Some Python 2 implementations, like Jython, may allow non-octet (above 255) values
# in their str implementation; this is mentioned in the WSGI spec, but we don't # in their str implementation; this is mentioned in the WSGI spec, but we don't
# run on any platform like that so we can assume that a str value is pure bytes. # run on any platform like that so we can assume that a str value is pure bytes.
response_headers.append((header if not PY3 else header.encode("latin-1"), response_headers.append((header.encode("latin-1"),
value if not PY3 else value.encode("latin-1"))) value.encode("latin-1")))
except UnicodeEncodeError: except UnicodeEncodeError:
# If we get here, we're guaranteed to have a header and value # If we get here, we're guaranteed to have a header and value
raise UnicodeError("Non-latin1 header", repr(header), repr(value)) raise UnicodeError("Non-latin1 header", repr(header), repr(value))
...@@ -871,7 +861,7 @@ class WSGIHandler(object): ...@@ -871,7 +861,7 @@ class WSGIHandler(object):
# code # code
code = int(status.split(' ', 1)[0]) code = int(status.split(' ', 1)[0])
self.status = status if not PY3 else status.encode("latin-1") self.status = status.encode("latin-1")
self._orig_status = status # Preserve the native string for logging self._orig_status = status # Preserve the native string for logging
self.response_headers = response_headers self.response_headers = response_headers
self.code = code self.code = code
...@@ -898,8 +888,7 @@ class WSGIHandler(object): ...@@ -898,8 +888,7 @@ class WSGIHandler(object):
if self.code in (304, 204): if self.code in (304, 204):
if self.provided_content_length is not None and self.provided_content_length != '0': if self.provided_content_length is not None and self.provided_content_length != '0':
msg = 'Invalid Content-Length for %s response: %r (must be absent or zero)' % (self.code, self.provided_content_length) msg = 'Invalid Content-Length for %s response: %r (must be absent or zero)' % (self.code, self.provided_content_length)
if PY3: msg = msg.encode('latin-1')
msg = msg.encode('latin-1')
raise self.ApplicationError(msg) raise self.ApplicationError(msg)
return self.write return self.write
...@@ -1012,8 +1001,6 @@ class WSGIHandler(object): ...@@ -1012,8 +1001,6 @@ class WSGIHandler(object):
except socket.error as ex: except socket.error as ex:
if ex.args[0] in self.ignored_socket_errors: if ex.args[0] in self.ignored_socket_errors:
# See description of self.ignored_socket_errors. # See description of self.ignored_socket_errors.
if not PY3:
sys.exc_clear()
self.close_connection = True self.close_connection = True
else: else:
self.handle_error(*sys.exc_info()) self.handle_error(*sys.exc_info())
...@@ -1032,8 +1019,6 @@ class WSGIHandler(object): ...@@ -1032,8 +1019,6 @@ class WSGIHandler(object):
self.start_response(status, headers[:]) self.start_response(status, headers[:])
self.write(body) self.write(body)
except socket.error: except socket.error:
if not PY3:
sys.exc_clear()
self.close_connection = True self.close_connection = True
def _log_error(self, t, v, tb): def _log_error(self, t, v, tb):
...@@ -1558,7 +1543,7 @@ class WSGIServer(StreamServer): ...@@ -1558,7 +1543,7 @@ class WSGIServer(StreamServer):
name = socket.getfqdn(address[0]) name = socket.getfqdn(address[0])
except socket.error: except socket.error:
name = str(address[0]) name = str(address[0])
if PY3 and not isinstance(name, str): if not isinstance(name, str):
name = name.decode('ascii') name = name.decode('ascii')
self.environ['SERVER_NAME'] = name self.environ['SERVER_NAME'] = name
self.environ.setdefault('SERVER_PORT', str(address[1])) self.environ.setdefault('SERVER_PORT', str(address[1]))
......
...@@ -25,7 +25,6 @@ from gevent._compat import string_types ...@@ -25,7 +25,6 @@ from gevent._compat import string_types
from gevent._compat import text_type from gevent._compat import text_type
from gevent._compat import hostname_types from gevent._compat import hostname_types
from gevent._compat import integer_types from gevent._compat import integer_types
from gevent._compat import PY3
from gevent._compat import PYPY from gevent._compat import PYPY
from gevent._compat import MAC from gevent._compat import MAC
...@@ -98,7 +97,7 @@ def _resolve_special(hostname, family): ...@@ -98,7 +97,7 @@ def _resolve_special(hostname, family):
class AbstractResolver(object): class AbstractResolver(object):
HOSTNAME_ENCODING = 'idna' if PY3 else 'ascii' HOSTNAME_ENCODING = 'idna'
_LOCAL_HOSTNAMES = ( _LOCAL_HOSTNAMES = (
b'localhost', b'localhost',
......
...@@ -4,8 +4,6 @@ from __future__ import print_function ...@@ -4,8 +4,6 @@ from __future__ import print_function
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import division from __future__ import division
from contextlib import closing
import sys import sys
from _socket import error as SocketError from _socket import error as SocketError
...@@ -17,7 +15,7 @@ from _socket import SOCK_DGRAM ...@@ -17,7 +15,7 @@ from _socket import SOCK_DGRAM
from gevent.baseserver import BaseServer from gevent.baseserver import BaseServer
from gevent.socket import EWOULDBLOCK from gevent.socket import EWOULDBLOCK
from gevent.socket import socket as GeventSocket from gevent.socket import socket as GeventSocket
from gevent._compat import PYPY, PY3 from gevent._compat import PYPY
__all__ = ['StreamServer', 'DatagramServer'] __all__ = ['StreamServer', 'DatagramServer']
...@@ -29,13 +27,9 @@ else: ...@@ -29,13 +27,9 @@ else:
DEFAULT_REUSE_ADDR = 1 DEFAULT_REUSE_ADDR = 1
if PY3: # sockets and SSL sockets are context managers on Python 3
# sockets and SSL sockets are context managers on Python 3 def _closing_socket(sock):
def _closing_socket(sock): return sock
return sock
else:
# but they are not guaranteed to be so on Python 2
_closing_socket = closing
class StreamServer(BaseServer): class StreamServer(BaseServer):
...@@ -191,38 +185,21 @@ class StreamServer(BaseServer): ...@@ -191,38 +185,21 @@ class StreamServer(BaseServer):
backlog = cls.backlog backlog = cls.backlog
return _tcp_listener(address, backlog=backlog, reuse_addr=cls.reuse_addr, family=family) return _tcp_listener(address, backlog=backlog, reuse_addr=cls.reuse_addr, family=family)
if PY3: def do_read(self):
def do_read(self): sock = self.socket
sock = self.socket try:
try: fd, address = sock._accept()
fd, address = sock._accept() except BlockingIOError: # python 2: pylint: disable=undefined-variable
except BlockingIOError: # python 2: pylint: disable=undefined-variable if not sock.timeout:
if not sock.timeout: return
return raise
raise
sock = GeventSocket(sock.family, sock.type, sock.proto, fileno=fd)
sock = GeventSocket(sock.family, sock.type, sock.proto, fileno=fd) # XXX Python issue #7995? "if no default timeout is set
# XXX Python issue #7995? "if no default timeout is set # and the listening socket had a (non-zero) timeout, force
# and the listening socket had a (non-zero) timeout, force # the new socket in blocking mode to override
# the new socket in blocking mode to override # platform-specific socket flags inheritance."
# platform-specific socket flags inheritance." return sock, address
return sock, address
else:
def do_read(self):
try:
client_socket, address = self.socket.accept()
except SocketError as err:
if err.args[0] == EWOULDBLOCK:
return
raise
sockobj = GeventSocket(_sock=client_socket)
if PYPY:
# Undo the ref-count bump that the constructor
# did. We gave it ownership.
client_socket._drop()
return sockobj, address
def do_close(self, sock, *args): def do_close(self, sock, *args):
# pylint:disable=arguments-differ # pylint:disable=arguments-differ
......
...@@ -13,16 +13,15 @@ as well as the constants from the :mod:`socket` module are imported into this mo ...@@ -13,16 +13,15 @@ as well as the constants from the :mod:`socket` module are imported into this mo
# Our import magic sadly makes this warning useless # Our import magic sadly makes this warning useless
# pylint: disable=undefined-variable # pylint: disable=undefined-variable
from gevent._compat import PY3
from gevent._compat import PY311 from gevent._compat import PY311
from gevent._compat import exc_clear from gevent._compat import exc_clear
from gevent._util import copy_globals from gevent._util import copy_globals
if PY3:
from gevent import _socket3 as _source # python 2: pylint:disable=no-name-in-module from gevent import _socket3 as _source
else:
from gevent import _socket2 as _source
# define some things we're expecting to overwrite; each module # define some things we're expecting to overwrite; each module
# needs to define these # needs to define these
......
""" """
Secure Sockets Layer (SSL/TLS) module. Secure Sockets Layer (SSL/TLS) module.
""" """
from gevent._compat import PY2
from gevent._util import copy_globals from gevent._util import copy_globals
# things we expect to override, here for static analysis # things we expect to override, here for static analysis
...@@ -9,27 +9,8 @@ def wrap_socket(_sock, **_kwargs): ...@@ -9,27 +9,8 @@ def wrap_socket(_sock, **_kwargs):
# pylint:disable=unused-argument # pylint:disable=unused-argument
raise NotImplementedError() raise NotImplementedError()
if PY2:
if hasattr(__import__('ssl'), 'SSLContext'): from gevent import _ssl3 as _source
# It's not sufficient to check for >= 2.7.9; some distributions
# have backported most of PEP 466. Try to accommodate them. See Issue #702.
# We're just about to import ssl anyway so it's fine to import it here, just
# don't pollute the namespace
from gevent import _sslgte279 as _source
else: # pragma: no cover
from gevent import _ssl2 as _source
import warnings
warnings.warn(
"This version of Python has an insecure SSL implementation. "
"gevent is no longer tested with it, and support will be removed "
"in gevent 1.5. Please use Python 2.7.9 or newer.",
DeprecationWarning,
stacklevel=2,
)
del warnings
else:
# Py3
from gevent import _ssl3 as _source # pragma: no cover
copy_globals(_source, globals()) copy_globals(_source, globals())
This diff is collapsed.
...@@ -115,7 +115,6 @@ from .skipping import skipOnPy310 ...@@ -115,7 +115,6 @@ from .skipping import skipOnPy310
from .skipping import skipOnPy3 from .skipping import skipOnPy3
from .skipping import skipWithoutResource from .skipping import skipWithoutResource
from .skipping import skipWithoutExternalNetwork from .skipping import skipWithoutExternalNetwork
from .skipping import skipOnPy2
from .skipping import skipOnManylinux from .skipping import skipOnManylinux
from .skipping import skipOnMacOnCI from .skipping import skipOnMacOnCI
......
...@@ -45,7 +45,6 @@ skipOnPyPy3OnCI = _do_not_skip ...@@ -45,7 +45,6 @@ skipOnPyPy3OnCI = _do_not_skip
skipOnPyPy3 = _do_not_skip skipOnPyPy3 = _do_not_skip
skipOnPyPyOnWindows = _do_not_skip skipOnPyPyOnWindows = _do_not_skip
skipOnPy2 = unittest.skip if sysinfo.PY2 else _do_not_skip
skipOnPy3 = unittest.skip if sysinfo.PY3 else _do_not_skip skipOnPy3 = unittest.skip if sysinfo.PY3 else _do_not_skip
skipOnPy37 = unittest.skip if sysinfo.PY37 else _do_not_skip skipOnPy37 = unittest.skip if sysinfo.PY37 else _do_not_skip
skipOnPy310 = unittest.skip if sysinfo.PY310 else _do_not_skip skipOnPy310 = unittest.skip if sysinfo.PY310 else _do_not_skip
......
...@@ -17,18 +17,10 @@ try: ...@@ -17,18 +17,10 @@ try:
except ImportError: except ImportError:
GreenOpenDescriptor = None GreenOpenDescriptor = None
from gevent._compat import PY2
from gevent._compat import PY3
from gevent._compat import text_type
import gevent.testing as greentest import gevent.testing as greentest
from gevent.testing import sysinfo from gevent.testing import sysinfo
try:
ResourceWarning # pylint:disable=used-before-assignment
except NameError:
class ResourceWarning(Warning):
"Python 2 fallback"
# pylint:disable=unspecified-encoding # pylint:disable=unspecified-encoding
...@@ -136,11 +128,9 @@ class TestFileObjectBlock(CleanupMixin, ...@@ -136,11 +128,9 @@ class TestFileObjectBlock(CleanupMixin,
with open(path, 'rb') as f_raw: with open(path, 'rb') as f_raw:
f = self._makeOne(f_raw, 'rb', close=False) f = self._makeOne(f_raw, 'rb', close=False)
# On Python 3, all objects should have seekable.
if PY3 or hasattr(f, 'seekable'): # On Python 2, only our custom objects do.
# On Python 3, all objects should have seekable. self.assertTrue(f.seekable())
# On Python 2, only our custom objects do.
self.assertTrue(f.seekable())
f.seek(15) f.seek(15)
self.assertEqual(15, f.tell()) self.assertEqual(15, f.tell())
...@@ -169,7 +159,7 @@ class TestFileObjectBlock(CleanupMixin, ...@@ -169,7 +159,7 @@ class TestFileObjectBlock(CleanupMixin,
else: else:
# Note that we don't use ``io.open()`` for the raw file, # Note that we don't use ``io.open()`` for the raw file,
# on Python 2. We want 'r' to mean what the usual call to open() means. # on Python 2. We want 'r' to mean what the usual call to open() means.
opener = io.open if PY3 else open opener = io.open
with opener(path, open_mode, **open_kwargs) as raw: with opener(path, open_mode, **open_kwargs) as raw:
with self._makeOne(raw) as f: with self._makeOne(raw) as f:
gevent_data = getattr(f, meth)() gevent_data = getattr(f, meth)()
...@@ -190,7 +180,7 @@ class TestFileObjectBlock(CleanupMixin, ...@@ -190,7 +180,7 @@ class TestFileObjectBlock(CleanupMixin,
'r+', 'r+',
buffering=5, encoding='utf-8' buffering=5, encoding='utf-8'
) )
self.assertIsInstance(gevent_data, text_type) self.assertIsInstance(gevent_data, str)
@skipUnlessWorksWithRegularFiles @skipUnlessWorksWithRegularFiles
def test_does_not_leak_on_exception(self): def test_does_not_leak_on_exception(self):
...@@ -341,7 +331,7 @@ class ConcurrentFileObjectMixin(object): ...@@ -341,7 +331,7 @@ class ConcurrentFileObjectMixin(object):
self.addCleanup(os.close, w) self.addCleanup(os.close, w)
reader = self._makeOne(r) reader = self._makeOne(r)
self._close_on_teardown(reader) self._close_on_teardown(reader)
self.assertEqual(PY2, hasattr(reader, 'read1')) self.assertFalse(hasattr(reader, 'read1'))
def test_bufsize_0(self): def test_bufsize_0(self):
# Issue #840 # Issue #840
......
import sys import sys
import unittest import unittest
from gevent.testing import skipOnPy2
class TestSubnormalFloatsAreNotDisabled(unittest.TestCase): class TestSubnormalFloatsAreNotDisabled(unittest.TestCase):
@skipOnPy2('This test always fails on Python 2')
def test_subnormal_is_not_zero(self): def test_subnormal_is_not_zero(self):
# Enabling the -Ofast compiler flag resulted in subnormal floats getting # Enabling the -Ofast compiler flag resulted in subnormal floats getting
# disabled the moment when gevent was imported. This impacted libraries # disabled the moment when gevent was imported. This impacted libraries
...@@ -21,7 +19,7 @@ class TestSubnormalFloatsAreNotDisabled(unittest.TestCase): ...@@ -21,7 +19,7 @@ class TestSubnormalFloatsAreNotDisabled(unittest.TestCase):
# `sys.float_info.min` is the minimum representable positive normalized # `sys.float_info.min` is the minimum representable positive normalized
# float, so dividing it by two gives us a positive subnormal float, # float, so dividing it by two gives us a positive subnormal float,
# as long as subnormals floats are not disabled. # as long as subnormals floats are not disabled.
self.assertGreater(sys.float_info.min / 2, 0) self.assertGreater(sys.float_info.min / 2, 0.0)
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -104,21 +104,19 @@ class TestRun(greentest.TestCase): ...@@ -104,21 +104,19 @@ class TestRun(greentest.TestCase):
# Also, occasionally, they get '3' instead of '2' for the number of threads. # Also, occasionally, they get '3' instead of '2' for the number of threads.
# That could have something to do with...? Most commonly that's PyPy, but # That could have something to do with...? Most commonly that's PyPy, but
# sometimes CPython. Again, haven't reproduced. # sometimes CPython. Again, haven't reproduced.
@greentest.skipOnPy2("lost sys.stderr sometimes") # Not relevant since Py2 has been dropped.
def test_threadpool_in_patched_after_patch(self): def test_threadpool_in_patched_after_patch(self):
# Issue 1484 # Issue 1484
# If we don't have this correct, then we get exceptions # If we don't have this correct, then we get exceptions
out = self._run(os.path.join('monkey_package', 'threadpool_monkey_patches.py')) out = self._run(os.path.join('monkey_package', 'threadpool_monkey_patches.py'))
self.assertEqual(out, ['False', '2']) self.assertEqual(out, ['False', '2'])
@greentest.skipOnPy2("lost sys.stderr sometimes")
def test_threadpool_in_patched_after_patch_module(self): def test_threadpool_in_patched_after_patch_module(self):
# Issue 1484 # Issue 1484
# If we don't have this correct, then we get exceptions # If we don't have this correct, then we get exceptions
out = self._run('monkey_package.threadpool_monkey_patches', module=True) out = self._run('monkey_package.threadpool_monkey_patches', module=True)
self.assertEqual(out, ['False', '2']) self.assertEqual(out, ['False', '2'])
@greentest.skipOnPy2("lost sys.stderr sometimes")
def test_threadpool_not_patched_after_patch_module(self): def test_threadpool_not_patched_after_patch_module(self):
# Issue 1484 # Issue 1484
# If we don't have this correct, then we get exceptions # If we don't have this correct, then we get exceptions
......
...@@ -17,9 +17,6 @@ from gevent.tests.test__selectors import SelectorTestMixin ...@@ -17,9 +17,6 @@ from gevent.tests.test__selectors import SelectorTestMixin
class TestSelectors(SelectorTestMixin, greentest.TestCase): class TestSelectors(SelectorTestMixin, greentest.TestCase):
@greentest.skipOnPy2(
'selectors2 backport does not use _select'
)
@greentest.skipOnWindows( @greentest.skipOnWindows(
"SelectSelector._select is a normal function on Windows" "SelectSelector._select is a normal function on Windows"
) )
......
...@@ -11,6 +11,7 @@ class Test(unittest.TestCase): ...@@ -11,6 +11,7 @@ class Test(unittest.TestCase):
# Issue 1108: Python 2, importing pkg_resources, # Issue 1108: Python 2, importing pkg_resources,
# as is done for namespace packages, imports ssl, # as is done for namespace packages, imports ssl,
# leading to an unwanted SSL warning. # leading to an unwanted SSL warning.
# This is a deprecated API though.
__import__('pkg_resources') __import__('pkg_resources')
from gevent import monkey from gevent import monkey
......
...@@ -111,7 +111,6 @@ class TestPopen(greentest.TestCase): ...@@ -111,7 +111,6 @@ class TestPopen(greentest.TestCase):
'pineapple\n\xff\xff\xf2\xf9\n') 'pineapple\n\xff\xff\xf2\xf9\n')
@greentest.skipOnWindows("Windows IO is weird; this doesn't raise") @greentest.skipOnWindows("Windows IO is weird; this doesn't raise")
@greentest.skipOnPy2("Only Python 2 decodes")
def test_communicate_undecodable(self): def test_communicate_undecodable(self):
# If the subprocess writes non-decodable data, `communicate` raises the # If the subprocess writes non-decodable data, `communicate` raises the
# same UnicodeDecodeError that the stdlib does, instead of # same UnicodeDecodeError that the stdlib does, instead of
......
...@@ -9,7 +9,6 @@ Implementation of the standard :mod:`thread` module that spawns greenlets. ...@@ -9,7 +9,6 @@ Implementation of the standard :mod:`thread` module that spawns greenlets.
:class:`gevent.Greenlet` class or :func:`gevent.spawn`. :class:`gevent.Greenlet` class or :func:`gevent.spawn`.
""" """
from __future__ import absolute_import from __future__ import absolute_import
import sys
__implements__ = [ __implements__ = [
'allocate_lock', 'allocate_lock',
...@@ -22,31 +21,23 @@ __implements__ = [ ...@@ -22,31 +21,23 @@ __implements__ = [
] ]
__imports__ = ['error'] __imports__ = ['error']
if sys.version_info[0] == 2:
import thread as __thread__ # pylint:disable=import-error import _thread as __thread__ # pylint:disable=import-error
PY2 = True
PY3 = False __target__ = '_thread'
# Name the `future` backport that might already have been imported; __imports__ += [
# Importing `pkg_resources` imports this, for example. 'TIMEOUT_MAX',
__alternate_targets__ = ('_thread',) 'allocate',
else: 'exit_thread',
import _thread as __thread__ # pylint:disable=import-error 'interrupt_main',
PY2 = False 'start_new'
PY3 = True ]
__target__ = '_thread'
__imports__ += [ # We can't actually produce a value that "may be used
'TIMEOUT_MAX', # to identify this particular thread system-wide", right?
'allocate', # Even if we could, I imagine people will want to pass this to
'exit_thread', # non-Python (native) APIs, so we shouldn't mess with it.
'interrupt_main', __imports__.append('get_native_id')
'start_new'
]
if sys.version_info[:2] >= (3, 8):
# We can't actually produce a value that "may be used
# to identify this particular thread system-wide", right?
# Even if we could, I imagine people will want to pass this to
# non-Python (native) APIs, so we shouldn't mess with it.
__imports__.append('get_native_id')
error = __thread__.error error = __thread__.error
...@@ -63,7 +54,6 @@ from gevent.local import local as _local ...@@ -63,7 +54,6 @@ from gevent.local import local as _local
from gevent.exceptions import LoopExit from gevent.exceptions import LoopExit
if hasattr(__thread__, 'RLock'): if hasattr(__thread__, 'RLock'):
assert PY3 or PYPY
# Added in Python 3.4, backported to PyPy 2.7-7.0 # Added in Python 3.4, backported to PyPy 2.7-7.0
__imports__.append("RLock") __imports__.append("RLock")
...@@ -88,13 +78,11 @@ class LockType(BoundedSemaphore): ...@@ -88,13 +78,11 @@ class LockType(BoundedSemaphore):
# and any other API changes we need to make to match behaviour # and any other API changes we need to make to match behaviour
_OVER_RELEASE_ERROR = __thread__.error _OVER_RELEASE_ERROR = __thread__.error
if PYPY and PY3: if PYPY:
_OVER_RELEASE_ERROR = RuntimeError _OVER_RELEASE_ERROR = RuntimeError
if PY3:
_TIMEOUT_MAX = __thread__.TIMEOUT_MAX # python 2: pylint:disable=no-member _TIMEOUT_MAX = __thread__.TIMEOUT_MAX # pylint:disable=no-member
else:
_TIMEOUT_MAX = 9223372036.0
def acquire(self, blocking=True, timeout=-1): def acquire(self, blocking=True, timeout=-1):
# This is the Python 3 signature. # This is the Python 3 signature.
......
...@@ -50,8 +50,7 @@ from gevent.thread import get_ident as _get_ident ...@@ -50,8 +50,7 @@ from gevent.thread import get_ident as _get_ident
from gevent.hub import sleep as _sleep, getcurrent from gevent.hub import sleep as _sleep, getcurrent
from gevent.lock import RLock from gevent.lock import RLock
from gevent._compat import PY3
from gevent._compat import PYPY
from gevent._util import LazyOnClass from gevent._util import LazyOnClass
# Exports, prevent unused import warnings. # Exports, prevent unused import warnings.
...@@ -168,46 +167,45 @@ else: ...@@ -168,46 +167,45 @@ else:
return main_threads[0] return main_threads[0]
if PY3:
# XXX: Issue 18808 breaks us on Python 3.4+.
# Thread objects now expect a callback from the interpreter itself
# (threadmodule.c:release_sentinel) when the C-level PyThreadState
# object is being deallocated. Because this never happens
# when a greenlet exits, join() and friends will block forever.
# Fortunately this is easy to fix: just ensure that the allocation of the
# lock, _set_sentinel, creates a *gevent* lock, and release it when
# we're done. The main _shutdown code is in Python and deals with
# this gracefully.
class Thread(__threading__.Thread): # XXX: Issue 18808 breaks us on Python 3.4+.
# Thread objects now expect a callback from the interpreter itself
# (threadmodule.c:release_sentinel) when the C-level PyThreadState
# object is being deallocated. Because this never happens
# when a greenlet exits, join() and friends will block forever.
# Fortunately this is easy to fix: just ensure that the allocation of the
# lock, _set_sentinel, creates a *gevent* lock, and release it when
# we're done. The main _shutdown code is in Python and deals with
# this gracefully.
def _set_tstate_lock(self): class Thread(__threading__.Thread):
super(Thread, self)._set_tstate_lock()
greenlet = getcurrent()
greenlet.rawlink(self.__greenlet_finished)
def __greenlet_finished(self, _): def _set_tstate_lock(self):
if self._tstate_lock: super(Thread, self)._set_tstate_lock()
self._tstate_lock.release() greenlet = getcurrent()
self._stop() greenlet.rawlink(self.__greenlet_finished)
__implements__.append('Thread') def __greenlet_finished(self, _):
if self._tstate_lock:
self._tstate_lock.release()
self._stop()
class Timer(Thread, __threading__.Timer): # pylint:disable=abstract-method,inherit-non-class __implements__.append('Thread')
pass
class Timer(Thread, __threading__.Timer): # pylint:disable=abstract-method,inherit-non-class
pass
__implements__.append('Timer') __implements__.append('Timer')
_set_sentinel = allocate_lock _set_sentinel = allocate_lock
__implements__.append('_set_sentinel') __implements__.append('_set_sentinel')
# The main thread is patched up with more care # The main thread is patched up with more care
# in _gevent_will_monkey_patch # in _gevent_will_monkey_patch
if PY3: __implements__.remove('_get_ident')
__implements__.remove('_get_ident') __implements__.append('get_ident')
__implements__.append('get_ident') get_ident = _get_ident
get_ident = _get_ident __implements__.remove('_sleep')
__implements__.remove('_sleep')
if hasattr(__threading__, '_CRLock'): if hasattr(__threading__, '_CRLock'):
# Python 3 changed the implementation of threading.RLock # Python 3 changed the implementation of threading.RLock
...@@ -219,7 +217,6 @@ if hasattr(__threading__, '_CRLock'): ...@@ -219,7 +217,6 @@ if hasattr(__threading__, '_CRLock'):
# if the imported _CRLock is None; this arranges for that to be the case. # if the imported _CRLock is None; this arranges for that to be the case.
# This was also backported to PyPy 2.7-7.0 # This was also backported to PyPy 2.7-7.0
assert PY3 or PYPY, "Unsupported Python version"
_CRLock = None _CRLock = None
__implements__.append('_CRLock') __implements__.append('_CRLock')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment