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):
# leak checks. previously we had a hand-rolled version.
'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
......
......@@ -12,12 +12,6 @@ import sys
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)
PY311 = sys.version_info[:2] >= (3, 11)
PYPY = hasattr(sys, 'pypy_version_info')
......@@ -30,20 +24,12 @@ PURE_PYTHON = PYPY or os.getenv('PURE_PYTHON')
## Types
if PY3:
string_types = (str,)
integer_types = (int,)
text_type = str
native_path_types = (str, bytes)
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'
string_types = (str,)
integer_types = (int,)
text_type = str
native_path_types = (str, bytes)
thread_mod_name = '_thread'
hostname_types = tuple(set(string_types + (bytearray, bytes)))
......@@ -51,27 +37,20 @@ def NativeStrIO():
import io
return io.BytesIO() if str is bytes else io.StringIO()
try:
from abc import ABC
except ImportError:
import abc
ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()})
del abc
from abc import ABC # pylint:disable=unused-import
## Exceptions
if PY3:
def reraise(t, value, tb=None): # pylint:disable=unused-argument
if value.__traceback__ is not tb and tb is not None:
raise value.with_traceback(tb)
raise value
def exc_clear():
pass
else:
from gevent._util_py2 import reraise # pylint:disable=import-error,no-name-in-module
reraise = reraise # export
exc_clear = sys.exc_clear
def reraise(t, value, tb=None): # pylint:disable=unused-argument
if value.__traceback__ is not tb and tb is not None:
raise value.with_traceback(tb)
raise value
def exc_clear():
pass
## import locks
try:
......@@ -86,127 +65,28 @@ imp_acquire_lock = imp.acquire_lock
imp_release_lock = imp.release_lock
## Functions
if PY3:
iteritems = dict.items
itervalues = dict.values
xrange = range
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
iteritems = dict.items
itervalues = dict.values
xrange = range
izip = zip
## The __fspath__ protocol
try:
from os import PathLike # pylint:disable=unused-import
except ImportError:
class PathLike(ABC):
@classmethod
def __subclasshook__(cls, subclass):
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
## The __fspath__ protocol
from os import PathLike # pylint:disable=unused-import
from os import fspath
_fspath = fspath
from os import fsencode # pylint:disable=unused-import
from os import fsdecode # pylint:disable=unused-import
## Clocks
try:
# Python 3.3+ (PEP 418)
from time import perf_counter
from time import get_clock_info
from time import monotonic
perf_counter = perf_counter
monotonic = monotonic
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'
# Python 3.3+ (PEP 418)
from time import perf_counter
from time import get_clock_info
from time import monotonic
perf_counter = perf_counter
monotonic = monotonic
get_clock_info = get_clock_info
## Monitoring
def get_this_psutil_process():
......
......@@ -14,7 +14,6 @@ import sys
import os
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 reraise
from gevent._compat import fspath
......@@ -393,18 +392,12 @@ class OpenDescriptor(object): # pylint:disable=too-many-instance-attributes
if not self.binary:
# Either native or text at this point.
if PY2 and self.native:
# Neither text mode nor binary mode specified.
if self.universal:
# universal was requested, e.g., 'rU'
result = UniversalNewlineBytesWrapper(result, line_buffering)
else:
# 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)
# 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):
# Set the mode, if possible, but only if we created a new
......
......@@ -12,7 +12,7 @@ from __future__ import absolute_import, print_function
import importlib
import sys
from gevent._compat import PY3
from gevent._compat import iteritems
from gevent._compat import imp_acquire_lock
from gevent._compat import imp_release_lock
......@@ -25,23 +25,20 @@ MAPPING = {
'gevent.local': '_threading_local',
'gevent.socket': 'socket',
'gevent.select': 'select',
'gevent.selectors': 'selectors' if PY3 else 'selectors2',
'gevent.selectors': 'selectors',
'gevent.ssl': 'ssl',
'gevent.thread': '_thread' if PY3 else 'thread',
'gevent.thread': '_thread',
'gevent.subprocess': 'subprocess',
'gevent.os': 'os',
'gevent.threading': 'threading',
'gevent.builtins': 'builtins' if PY3 else '__builtin__',
'gevent.builtins': 'builtins',
'gevent.signal': 'signal',
'gevent.time': 'time',
'gevent.queue': 'queue' if PY3 else 'Queue',
'gevent.queue': 'queue',
'gevent.contextvars': 'contextvars',
}
OPTIONAL_STDLIB_MODULES = frozenset() if PY3 else frozenset([
'selectors2',
])
OPTIONAL_STDLIB_MODULES = frozenset()
_PATCH_PREFIX = '__g_patched_module_'
def _collect_stdlib_gevent_modules():
......
......@@ -270,10 +270,16 @@ def getfqdn(name=''):
First the hostname returned by gethostbyaddr() is checked, then
possibly existing aliases. In case no FQDN is available, hostname
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
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()
try:
hostname, aliases, _ = gethostbyaddr(name)
......
......@@ -13,13 +13,13 @@ import ssl as __ssl__
_ssl = __ssl__._ssl
import errno
import sys
from gevent.socket import socket, timeout_default
from gevent.socket import error as socket_error
from gevent.socket import timeout as _socket_timeout
from gevent._util import copy_globals
from gevent._compat import PY36
from weakref import ref as _wref
......@@ -49,8 +49,8 @@ from ssl import SSL_ERROR_EOF
from ssl import SSL_ERROR_WANT_READ
from ssl import SSL_ERROR_WANT_WRITE
from ssl import PROTOCOL_SSLv23
from ssl import SSLObject
from ssl import match_hostname
#from ssl import SSLObject
from ssl import CHANNEL_BINDING_TYPES
from ssl import CERT_REQUIRED
from ssl import DER_cert_to_PEM_cert
......@@ -674,32 +674,14 @@ class SSLSocket(socket):
raise
self._wait(self._write_event, timeout_exc=_SSLErrorHandshakeTimeout)
if sys.version_info[:2] < (3, 7) and self._context.check_hostname:
# In Python 3.7, the underlying OpenSSL name matching is used.
# The version implemented in Python doesn't understand IDNA encoding.
if not self.server_hostname:
raise ValueError("check_hostname needs server_hostname "
"argument")
match_hostname(self.getpeercert(), self.server_hostname) # pylint:disable=deprecated-method
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)
# 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
)
def _real_connect(self, addr, connect_ex):
if self.server_side:
......
......@@ -9,8 +9,6 @@ from collections import deque
from gevent import monkey
from gevent._compat import thread_mod_name
from gevent._compat import PY3
__all__ = [
'Lock',
......@@ -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.
if PY3:
def acquire_with_timeout(lock, timeout=-1):
globals()['acquire_with_timeout'] = type(lock).acquire
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)
def acquire_with_timeout(lock, timeout=-1):
globals()['acquire_with_timeout'] = type(lock).acquire
return lock.acquire(timeout=timeout)
class _Condition(object):
# We could use libuv's ``uv_cond_wait`` to implement this whole
......
......@@ -18,8 +18,7 @@ from gevent.greenlet import Greenlet
from gevent.hub import getcurrent
from gevent.server import StreamServer
from gevent.pool import Pool
from gevent._compat import PY36
from gevent._compat import exc_clear
__all__ = [
'BackdoorServer',
......@@ -174,15 +173,13 @@ class BackdoorServer(StreamServer):
getcurrent().switch_in()
try:
console = InteractiveConsole(self._create_interactive_locals())
if PY36:
# Beginning in 3.6, the console likes to print "now exiting <class>"
# but probably our socket is already closed, so this just causes problems.
console.interact(banner=self.banner, exitmsg='') # pylint:disable=unexpected-keyword-arg
else:
console.interact(banner=self.banner)
# Beginning in 3.6, the console likes to print "now exiting <class>"
# but probably our socket is already closed, so this just causes problems.
console.interact(banner=self.banner, exitmsg='') # pylint:disable=unexpected-keyword-arg
except SystemExit:
# raised by quit(); obviously this cannot propagate.
exc_clear() # Python 2
pass
finally:
raw_file.close()
conn.close()
......
......@@ -5,25 +5,14 @@ from __future__ import absolute_import
import weakref
from gevent.lock import RLock
from gevent._compat import PY3
from gevent._compat import imp_acquire_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 __builtin__ as __gbuiltins__
_allowed_module_name_types = (basestring,) # pylint:disable=undefined-variable
__target__ = '__builtin__'
except ImportError:
import builtins as __gbuiltins__ # pylint: disable=import-error
_allowed_module_name_types = (str,)
__target__ = 'builtins'
import builtins as __gbuiltins__
_allowed_module_name_types = (str,)
__target__ = 'builtins'
_import = __gbuiltins__.__import__
......@@ -121,11 +110,9 @@ def _lock_imports():
global __lock_imports
__lock_imports = True
if PY3:
__implements__ = []
__import__ = _import
else:
__implements__ = ['__import__']
__implements__ = []
__import__ = _import
__all__ = __implements__
......
......@@ -53,12 +53,12 @@ try:
except ImportError:
from collections import Mapping # pylint:disable=deprecated-class
from gevent._compat import PY37
from gevent._util import _NONE
from gevent.local import local
__stdlib_expected__ = __all__
__implements__ = __stdlib_expected__ if PY37 else None
__implements__ = __stdlib_expected__
# In the reference implementation, the interpreter level OS thread state
# 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):
entry_points = set(
ep
for ep
in ep_dict.get(event.ENTRY_POINT_NAME)
in ep_dict.get(event.ENTRY_POINT_NAME, ())
)
for plugin in entry_points:
......
......@@ -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.
# It's not as direct, but it works.
# So here we're not compiled
from gevent._compat import PYPY
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
local.__new__ = classmethod(__new__)
else: # pragma: no cover
# Make sure we revisit in case of changes to the (accelerator) module names.
if local.__module__ != 'gevent._gevent_clocal':
......
......@@ -12,7 +12,7 @@ from __future__ import print_function
from gevent.hub import getcurrent
from gevent._compat import PURE_PYTHON
from gevent._compat import PY2
# This is the one exception to the rule of where to
# import Semaphore, obviously
from gevent import monkey
......@@ -180,8 +180,6 @@ def _fixup_docstrings():
assert c.__doc__ == b.__doc__
for m in 'acquire', 'release', 'wait':
c_meth = getattr(c, m)
if PY2:
c_meth = c_meth.__func__
b_meth = getattr(b, m)
c_meth.__doc__ = b_meth.__doc__
......
......@@ -149,20 +149,7 @@ __all__ = [
'main',
]
if sys.version_info[0] >= 3:
string_types = (str,)
PY3 = True
PY2 = False
else:
import __builtin__ # pylint:disable=import-error
string_types = (__builtin__.basestring,)
PY3 = False
PY2 = True
WIN = sys.platform.startswith("win")
PY36 = sys.version_info[:2] >= (3, 6)
PY37 = sys.version_info[:2] >= (3, 7)
class _BadImplements(AttributeError):
"""
......@@ -280,8 +267,8 @@ def get_original(mod_name, item_name):
``item_name`` or a sequence of original values if a
sequence was passed.
"""
mod_names = [mod_name] if isinstance(mod_name, string_types) else mod_name
if isinstance(item_name, string_types):
mod_names = [mod_name] if isinstance(mod_name, str) else mod_name
if isinstance(item_name, str):
item_names = [item_name]
unpack = True
else:
......@@ -333,7 +320,6 @@ def __call_module_hook(gevent_module, name, module, items, _warnings):
class _GeventDoPatchRequest(object):
PY3 = PY3
get_original = staticmethod(get_original)
def __init__(self,
......@@ -513,7 +499,7 @@ def _patch_sys_std(name):
patch_item(sys, name, FileObjectThread(orig))
@_ignores_DoNotPatch
def patch_sys(stdin=True, stdout=True, stderr=True):
def patch_sys(stdin=True, stdout=True, stderr=True): # pylint:disable=unused-argument
"""
Patch sys.std[in,out,err] to use a cooperative IO via a
threadpool.
......@@ -529,29 +515,11 @@ def patch_sys(stdin=True, stdout=True, stderr=True):
time leads to a hang.
.. _`misinterpreting control keys`: https://github.com/gevent/gevent/issues/274
"""
# test__issue6.py demonstrates the hang if these lines are removed;
# strangely enough that test passes even without monkey-patching sys
if PY3:
items = None
else:
items = set([('stdin' if stdin else None),
('stdout' if stdout else None),
('stderr' if stderr else None)])
items.discard(None)
items = list(items)
if not items:
return
from gevent import events
_notify_patch(events.GeventWillPatchModuleEvent('sys', None, sys,
items))
for item in items:
_patch_sys_std(item)
_notify_patch(events.GeventDidPatchModuleEvent('sys', None, sys))
.. deprecated:: NEXT
Does nothing on any supported version.
"""
return
@_ignores_DoNotPatch
def patch_os():
......@@ -612,21 +580,11 @@ def patch_contextvars():
natively handles switching context vars when greenlets are switched.
Older versions of Python that have the backport installed will
still be patched.
.. deprecated:: NEXT
Does nothing on any supported version.
"""
if PY37:
return
try:
__import__('contextvars')
except ImportError:
pass
else:
try:
_patch_module('contextvars')
except _BadImplements:
# Prior to Python 3.7, but the backport must be installed.
# *Assume* it has the same things as the standard library would.
import gevent.contextvars
_patch_module('contextvars', gevent.contextvars.__stdlib_expected__)
return
def _patch_existing_locks(threading):
......@@ -853,103 +811,101 @@ def patch_thread(threading=True, _threading_local=True, Event=True, logging=True
continue
thread.join = make_join_func(thread, None)
if PY3:
# Issue 18808 changes the nature of Thread.join() to use
# locks. This means that a greenlet spawned in the main thread
# (which is already running) cannot wait for the main thread---it
# hangs forever. We patch around this if possible. See also
# gevent.threading.
greenlet = __import__('greenlet')
already_patched = is_object_patched('threading', '_shutdown')
orig_shutdown = threading_mod._shutdown
if orig_current_thread == threading_mod.main_thread() and not already_patched:
main_thread = threading_mod.main_thread()
_greenlet = main_thread._greenlet = greenlet.getcurrent()
main_thread.__real_tstate_lock = main_thread._tstate_lock
assert main_thread.__real_tstate_lock is not None
# The interpreter will call threading._shutdown
# when the main thread exits and is about to
# go away. It is called *in* the main thread. This
# is a perfect place to notify other greenlets that
# the main thread is done. We do this by overriding the
# lock of the main thread during operation, and only restoring
# it to the native blocking version at shutdown time
# (the interpreter also has a reference to this lock in a
# C data structure).
main_thread._tstate_lock = threading_mod.Lock()
main_thread._tstate_lock.acquire()
def _shutdown():
# Release anyone trying to join() me,
# and let us switch to them.
if not main_thread._tstate_lock:
return
# Issue 18808 changes the nature of Thread.join() to use
# locks. This means that a greenlet spawned in the main thread
# (which is already running) cannot wait for the main thread---it
# hangs forever. We patch around this if possible. See also
# gevent.threading.
greenlet = __import__('greenlet')
already_patched = is_object_patched('threading', '_shutdown')
orig_shutdown = threading_mod._shutdown
if orig_current_thread == threading_mod.main_thread() and not already_patched:
main_thread = threading_mod.main_thread()
_greenlet = main_thread._greenlet = greenlet.getcurrent()
main_thread.__real_tstate_lock = main_thread._tstate_lock
assert main_thread.__real_tstate_lock is not None
# The interpreter will call threading._shutdown
# when the main thread exits and is about to
# go away. It is called *in* the main thread. This
# is a perfect place to notify other greenlets that
# the main thread is done. We do this by overriding the
# lock of the main thread during operation, and only restoring
# it to the native blocking version at shutdown time
# (the interpreter also has a reference to this lock in a
# C data structure).
main_thread._tstate_lock = threading_mod.Lock()
main_thread._tstate_lock.acquire()
def _shutdown():
# Release anyone trying to join() me,
# and let us switch to them.
if not main_thread._tstate_lock:
return
main_thread._tstate_lock.release()
from gevent import sleep
try:
sleep()
except: # pylint:disable=bare-except
# A greenlet could have .kill() us
# or .throw() to us. I'm the main greenlet,
# there's no where else for this to go.
from gevent import get_hub
get_hub().print_exception(_greenlet, *sys.exc_info())
# Now, this may have resulted in us getting stopped
# if some other greenlet actually just ran there.
# That's not good, we're not supposed to be stopped
# when we enter _shutdown.
main_thread._is_stopped = False
main_thread._tstate_lock = main_thread.__real_tstate_lock
main_thread.__real_tstate_lock = None
# The only truly blocking native shutdown lock to
# acquire should be our own (hopefully), and the call to
# _stop that orig_shutdown makes will discard it.
orig_shutdown()
patch_item(threading_mod, '_shutdown', orig_shutdown)
patch_item(threading_mod, '_shutdown', _shutdown)
# We create a bit of a reference cycle here,
# so main_thread doesn't get to be collected in a timely way.
# Not good. Take it out of dangling so we don't get
# warned about it.
threading_mod._dangling.remove(main_thread)
# Patch up the ident of the main thread to match. This
# matters if threading was imported before monkey-patching
# thread
oldid = main_thread.ident
main_thread._tstate_lock.release()
from gevent import sleep
try:
sleep()
except: # pylint:disable=bare-except
# A greenlet could have .kill() us
# or .throw() to us. I'm the main greenlet,
# there's no where else for this to go.
from gevent import get_hub
get_hub().print_exception(_greenlet, *sys.exc_info())
# Now, this may have resulted in us getting stopped
# if some other greenlet actually just ran there.
# That's not good, we're not supposed to be stopped
# when we enter _shutdown.
main_thread._is_stopped = False
main_thread._tstate_lock = main_thread.__real_tstate_lock
main_thread.__real_tstate_lock = None
# The only truly blocking native shutdown lock to
# acquire should be our own (hopefully), and the call to
# _stop that orig_shutdown makes will discard it.
orig_shutdown()
patch_item(threading_mod, '_shutdown', orig_shutdown)
patch_item(threading_mod, '_shutdown', _shutdown)
# We create a bit of a reference cycle here,
# so main_thread doesn't get to be collected in a timely way.
# Not good. Take it out of dangling so we don't get
# warned about it.
threading_mod._dangling.remove(main_thread)
# Patch up the ident of the main thread to match. This
# matters if threading was imported before monkey-patching
# thread
oldid = main_thread.ident
main_thread._ident = threading_mod.get_ident()
if oldid in threading_mod._active:
threading_mod._active[main_thread.ident] = threading_mod._active[oldid]
if oldid != main_thread.ident:
del threading_mod._active[oldid]
elif not already_patched:
_queue_warning("Monkey-patching not on the main thread; "
"threading.main_thread().join() will hang from a greenlet",
_warnings)
main_thread = threading_mod.main_thread()
def _shutdown():
# We've patched get_ident but *did not* patch the
# main_thread.ident value. Beginning in Python 3.9.8
# and then later releases (3.10.1, probably), the
# _main_thread object is only _stop() if the ident of
# the current thread (the *real* main thread) matches
# the ident of the _main_thread object. But without doing that,
# the main thread's shutdown lock (threading._shutdown_locks) is never
# removed *or released*, thus hanging the interpreter.
# XXX: There's probably a better way to do this. Probably need to take a
# step back and look at the whole picture.
main_thread._ident = threading_mod.get_ident()
if oldid in threading_mod._active:
threading_mod._active[main_thread.ident] = threading_mod._active[oldid]
if oldid != main_thread.ident:
del threading_mod._active[oldid]
elif not already_patched:
_queue_warning("Monkey-patching not on the main thread; "
"threading.main_thread().join() will hang from a greenlet",
_warnings)
main_thread = threading_mod.main_thread()
def _shutdown():
# We've patched get_ident but *did not* patch the
# main_thread.ident value. Beginning in Python 3.9.8
# and then later releases (3.10.1, probably), the
# _main_thread object is only _stop() if the ident of
# the current thread (the *real* main thread) matches
# the ident of the _main_thread object. But without doing that,
# the main thread's shutdown lock (threading._shutdown_locks) is never
# removed *or released*, thus hanging the interpreter.
# XXX: There's probably a better way to do this. Probably need to take a
# step back and look at the whole picture.
main_thread._ident = threading_mod.get_ident()
orig_shutdown()
patch_item(threading_mod, '_shutdown', orig_shutdown)
patch_item(threading_mod, '_shutdown', _shutdown)
orig_shutdown()
patch_item(threading_mod, '_shutdown', orig_shutdown)
patch_item(threading_mod, '_shutdown', _shutdown)
from gevent import events
_notify_patch(events.GeventDidPatchModuleEvent('thread', gevent_thread_mod, thread_mod))
......@@ -1031,7 +987,6 @@ def patch_ssl(_warnings=None, _first_time=True):
"""
may_need_warning = (
_first_time
and PY36
and 'ssl' in sys.modules
and hasattr(sys.modules['ssl'], 'SSLContext'))
# Previously, we didn't warn on Python 2 if pkg_resources has been imported
......@@ -1145,9 +1100,10 @@ def patch_builtins():
.. _greenlet safe: https://github.com/gevent/gevent/issues/108
.. deprecated:: NEXT
Does nothing on any supported platform.
"""
if PY2:
_patch_module('builtins')
@_ignores_DoNotPatch
def patch_signal():
......
......@@ -48,7 +48,6 @@ import sys
from gevent.hub import _get_hub_noargs as get_hub
from gevent.hub import reinit
from gevent._config import config
from gevent._compat import PY3
from gevent._util import copy_globals
import errno
......@@ -102,8 +101,6 @@ if fcntl:
except OSError as e:
if e.errno not in ignored_errors:
raise
if not PY3:
sys.exc_clear()
if hub is None:
hub = get_hub()
event = hub.loop.io(fd, 1)
......@@ -133,8 +130,6 @@ if fcntl:
except OSError as e:
if e.errno not in ignored_errors:
raise
if not PY3:
sys.exc_clear()
if hub is None:
hub = get_hub()
event = hub.loop.io(fd, 2)
......
......@@ -31,13 +31,10 @@ from gevent import socket
import gevent
from gevent.server import StreamServer
from gevent.hub import GreenletExit
from gevent._compat import PY3, reraise
from gevent._compat import reraise
from functools import partial
if PY3:
unquote_latin1 = partial(unquote, encoding='latin-1')
else:
unquote_latin1 = unquote
unquote_latin1 = partial(unquote, encoding='latin-1')
_no_undoc_members = True # Don't put undocumented things into sphinx
......@@ -89,8 +86,7 @@ def format_date_time(timestamp):
# Return a byte string, not a native string
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)
if PY3:
value = value.encode("latin-1")
value = value.encode("latin-1")
return value
......@@ -392,13 +388,9 @@ class WSGIHandler(object):
# pylint:disable=too-many-instance-attributes
protocol_version = 'HTTP/1.1'
if PY3:
# if we do like Py2, then headers_factory unconditionally
# becomes a bound method, meaning the fp argument becomes WSGIHandler
def MessageClass(self, *args):
return headers_factory(*args)
else:
MessageClass = headers_factory
def MessageClass(self, *args):
return headers_factory(*args)
# Attributes reset at various times for each request; not public
# documented. Class attributes to keep the constructor fast
......@@ -562,10 +554,10 @@ class WSGIHandler(object):
if self.request_version == "HTTP/1.1":
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':
conntype = self.headers.get("Connection", "close").lower()
self.close_connection = (conntype != 'keep-alive')
self.close_connection = (conntype != 'keep-alive') # pylint:disable=superfluous-parens
else:
# XXX: HTTP 0.9. We should drop support
self.close_connection = True
......@@ -606,8 +598,7 @@ class WSGIHandler(object):
latin-1).
"""
line = self.rfile.readline(MAX_REQUEST_LINE)
if PY3:
line = line.decode('latin-1')
line = line.decode('latin-1')
return line
def handle_one_request(self):
......@@ -659,7 +650,7 @@ class WSGIHandler(object):
try:
self.requestline = self.read_requestline()
# 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')
except socket.error:
# "Connection reset by peer" or other socket errors aren't interesting here
......@@ -720,8 +711,7 @@ class WSGIHandler(object):
if hasattr(self.result, '__len__'):
total_len = sum(len(chunk) for chunk in self.result)
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))
else:
self.response_use_chunked = (
......@@ -856,8 +846,8 @@ class WSGIHandler(object):
# 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
# 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"),
value if not PY3 else value.encode("latin-1")))
response_headers.append((header.encode("latin-1"),
value.encode("latin-1")))
except UnicodeEncodeError:
# If we get here, we're guaranteed to have a header and value
raise UnicodeError("Non-latin1 header", repr(header), repr(value))
......@@ -871,7 +861,7 @@ class WSGIHandler(object):
# code
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.response_headers = response_headers
self.code = code
......@@ -898,8 +888,7 @@ class WSGIHandler(object):
if self.code in (304, 204):
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)
if PY3:
msg = msg.encode('latin-1')
msg = msg.encode('latin-1')
raise self.ApplicationError(msg)
return self.write
......@@ -1012,8 +1001,6 @@ class WSGIHandler(object):
except socket.error as ex:
if ex.args[0] in self.ignored_socket_errors:
# See description of self.ignored_socket_errors.
if not PY3:
sys.exc_clear()
self.close_connection = True
else:
self.handle_error(*sys.exc_info())
......@@ -1032,8 +1019,6 @@ class WSGIHandler(object):
self.start_response(status, headers[:])
self.write(body)
except socket.error:
if not PY3:
sys.exc_clear()
self.close_connection = True
def _log_error(self, t, v, tb):
......@@ -1558,7 +1543,7 @@ class WSGIServer(StreamServer):
name = socket.getfqdn(address[0])
except socket.error:
name = str(address[0])
if PY3 and not isinstance(name, str):
if not isinstance(name, str):
name = name.decode('ascii')
self.environ['SERVER_NAME'] = name
self.environ.setdefault('SERVER_PORT', str(address[1]))
......
......@@ -25,7 +25,6 @@ from gevent._compat import string_types
from gevent._compat import text_type
from gevent._compat import hostname_types
from gevent._compat import integer_types
from gevent._compat import PY3
from gevent._compat import PYPY
from gevent._compat import MAC
......@@ -98,7 +97,7 @@ def _resolve_special(hostname, family):
class AbstractResolver(object):
HOSTNAME_ENCODING = 'idna' if PY3 else 'ascii'
HOSTNAME_ENCODING = 'idna'
_LOCAL_HOSTNAMES = (
b'localhost',
......
......@@ -4,8 +4,6 @@ from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
from contextlib import closing
import sys
from _socket import error as SocketError
......@@ -17,7 +15,7 @@ from _socket import SOCK_DGRAM
from gevent.baseserver import BaseServer
from gevent.socket import EWOULDBLOCK
from gevent.socket import socket as GeventSocket
from gevent._compat import PYPY, PY3
from gevent._compat import PYPY
__all__ = ['StreamServer', 'DatagramServer']
......@@ -29,13 +27,9 @@ else:
DEFAULT_REUSE_ADDR = 1
if PY3:
# sockets and SSL sockets are context managers on Python 3
def _closing_socket(sock):
return sock
else:
# but they are not guaranteed to be so on Python 2
_closing_socket = closing
# sockets and SSL sockets are context managers on Python 3
def _closing_socket(sock):
return sock
class StreamServer(BaseServer):
......@@ -191,38 +185,21 @@ class StreamServer(BaseServer):
backlog = cls.backlog
return _tcp_listener(address, backlog=backlog, reuse_addr=cls.reuse_addr, family=family)
if PY3:
def do_read(self):
sock = self.socket
try:
fd, address = sock._accept()
except BlockingIOError: # python 2: pylint: disable=undefined-variable
if not sock.timeout:
return
raise
sock = GeventSocket(sock.family, sock.type, sock.proto, fileno=fd)
# XXX Python issue #7995? "if no default timeout is set
# and the listening socket had a (non-zero) timeout, force
# the new socket in blocking mode to override
# platform-specific socket flags inheritance."
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_read(self):
sock = self.socket
try:
fd, address = sock._accept()
except BlockingIOError: # python 2: pylint: disable=undefined-variable
if not sock.timeout:
return
raise
sock = GeventSocket(sock.family, sock.type, sock.proto, fileno=fd)
# XXX Python issue #7995? "if no default timeout is set
# and the listening socket had a (non-zero) timeout, force
# the new socket in blocking mode to override
# platform-specific socket flags inheritance."
return sock, address
def do_close(self, sock, *args):
# pylint:disable=arguments-differ
......
......@@ -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
# pylint: disable=undefined-variable
from gevent._compat import PY3
from gevent._compat import PY311
from gevent._compat import exc_clear
from gevent._util import copy_globals
if PY3:
from gevent import _socket3 as _source # python 2: pylint:disable=no-name-in-module
else:
from gevent import _socket2 as _source
from gevent import _socket3 as _source
# define some things we're expecting to overwrite; each module
# needs to define these
......
"""
Secure Sockets Layer (SSL/TLS) module.
"""
from gevent._compat import PY2
from gevent._util import copy_globals
# things we expect to override, here for static analysis
......@@ -9,27 +9,8 @@ def wrap_socket(_sock, **_kwargs):
# pylint:disable=unused-argument
raise NotImplementedError()
if PY2:
if hasattr(__import__('ssl'), 'SSLContext'):
# 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
from gevent import _ssl3 as _source
copy_globals(_source, globals())
......@@ -59,11 +59,11 @@ from gevent.hub import linkproxy
from gevent.hub import sleep
from gevent.hub import getcurrent
from gevent._compat import integer_types, string_types, xrange
from gevent._compat import PY3
from gevent._compat import PY35
from gevent._compat import PY36
from gevent._compat import PY37
from gevent._compat import PY38
# from gevent._compat import PY3
# from gevent._compat import PY35
# from gevent._compat import PY36
# from gevent._compat import PY37
# from gevent._compat import PY38
from gevent._compat import PY311
from gevent._compat import PYPY
from gevent._compat import reraise
......@@ -85,7 +85,7 @@ __implements__ = [
'check_call',
'check_output',
]
if PY3 and not sys.platform.startswith('win32'):
if not sys.platform.startswith('win32'):
__implements__.append("_posixsubprocess")
_posixsubprocess = None
......@@ -142,74 +142,69 @@ __extra__ = [
'CompletedProcess',
]
if PY3:
__imports__ += [
'DEVNULL',
'getstatusoutput',
'getoutput',
'SubprocessError',
'TimeoutExpired',
]
else:
__extra__.append("TimeoutExpired")
if PY35:
__extra__.remove('run')
__extra__.remove('CompletedProcess')
__implements__.append('run')
__implements__.append('CompletedProcess')
# Removed in Python 3.5; this is the exact code that was removed:
# https://hg.python.org/cpython/rev/f98b0a5e5ef5
__extra__.remove('MAXFD')
try:
MAXFD = os.sysconf("SC_OPEN_MAX")
except:
MAXFD = 256
if PY36:
# This was added to __all__ for windows in 3.6
__extra__.remove('STARTUPINFO')
__imports__.append('STARTUPINFO')
__imports__ += [
'DEVNULL',
'getstatusoutput',
'getoutput',
'SubprocessError',
'TimeoutExpired',
]
if PY37:
__imports__.extend([
'ABOVE_NORMAL_PRIORITY_CLASS', 'BELOW_NORMAL_PRIORITY_CLASS',
'HIGH_PRIORITY_CLASS', 'IDLE_PRIORITY_CLASS',
'NORMAL_PRIORITY_CLASS',
'REALTIME_PRIORITY_CLASS',
'CREATE_NO_WINDOW', 'DETACHED_PROCESS',
'CREATE_DEFAULT_ERROR_MODE',
'CREATE_BREAKAWAY_FROM_JOB'
])
# Became standard in 3.5
__extra__.remove('run')
__extra__.remove('CompletedProcess')
__implements__.append('run')
__implements__.append('CompletedProcess')
if PY38:
# Using os.posix_spawn() to start subprocesses
# bypasses our child watchers on certain operating systems,
# and with certain library versions. Possibly the right
# fix is to monkey-patch os.posix_spawn like we do os.fork?
# These have no effect, they're just here to match the stdlib.
# TODO: When available, given a monkey patch on them, I think
# we ought to be able to use them if the stdlib has identified them
# as suitable.
# Removed in Python 3.5; this is the exact code that was removed:
# https://hg.python.org/cpython/rev/f98b0a5e5ef5
__extra__.remove('MAXFD')
try:
MAXFD = os.sysconf("SC_OPEN_MAX")
except:
MAXFD = 256
# This was added to __all__ for windows in 3.6
__extra__.remove('STARTUPINFO')
__imports__.append('STARTUPINFO')
__imports__.extend([
'ABOVE_NORMAL_PRIORITY_CLASS', 'BELOW_NORMAL_PRIORITY_CLASS',
'HIGH_PRIORITY_CLASS', 'IDLE_PRIORITY_CLASS',
'NORMAL_PRIORITY_CLASS',
'REALTIME_PRIORITY_CLASS',
'CREATE_NO_WINDOW', 'DETACHED_PROCESS',
'CREATE_DEFAULT_ERROR_MODE',
'CREATE_BREAKAWAY_FROM_JOB'
])
# Using os.posix_spawn() to start subprocesses
# bypasses our child watchers on certain operating systems,
# and with certain library versions. Possibly the right
# fix is to monkey-patch os.posix_spawn like we do os.fork?
# These have no effect, they're just here to match the stdlib.
# TODO: When available, given a monkey patch on them, I think
# we ought to be able to use them if the stdlib has identified them
# as suitable.
__implements__.extend([
'_use_posix_spawn',
])
def _use_posix_spawn():
return False
_USE_POSIX_SPAWN = False
if __subprocess__._USE_POSIX_SPAWN:
__implements__.extend([
'_use_posix_spawn',
'_USE_POSIX_SPAWN',
])
else:
__imports__.extend([
'_USE_POSIX_SPAWN',
])
def _use_posix_spawn():
return False
_USE_POSIX_SPAWN = False
if __subprocess__._USE_POSIX_SPAWN:
__implements__.extend([
'_USE_POSIX_SPAWN',
])
else:
__imports__.extend([
'_USE_POSIX_SPAWN',
])
if PY311:
# Python 3.11 added some module-level attributes to control the
......@@ -270,26 +265,25 @@ for _x in ('run', 'CompletedProcess', 'TimeoutExpired'):
mswindows = sys.platform == 'win32'
if mswindows:
import msvcrt # pylint: disable=import-error
if PY3:
class Handle(int):
closed = False
def Close(self):
if not self.closed:
self.closed = True
_winapi.CloseHandle(self)
def Detach(self):
if not self.closed:
self.closed = True
return int(self)
raise ValueError("already closed")
def __repr__(self):
return "Handle(%d)" % int(self)
__del__ = Close
__str__ = __repr__
class Handle(int):
closed = False
def Close(self):
if not self.closed:
self.closed = True
_winapi.CloseHandle(self)
def Detach(self):
if not self.closed:
self.closed = True
return int(self)
raise ValueError("already closed")
def __repr__(self):
return "Handle(%d)" % int(self)
__del__ = Close
__str__ = __repr__
else:
import fcntl
import pickle
......@@ -478,14 +472,6 @@ def FileObject(*args, **kwargs):
# Defer importing FileObject until we need it
# to allow it to be configured more easily.
from gevent.fileobject import FileObject as _FileObject
if not PY3:
# Make write behave like the old Python 2 file
# write and loop to consume output, even when not
# buffered.
__FileObject = _FileObject
def _FileObject(*args, **kwargs):
kwargs['atomic_write'] = True
return __FileObject(*args, **kwargs)
globals()['FileObject'] = _FileObject
return _FileObject(*args)
......@@ -666,13 +652,13 @@ class Popen(object):
_communicate_empty_value = b''
def __init__(self, args,
bufsize=-1 if PY3 else 0,
bufsize=-1,
executable=None,
stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS, shell=False,
cwd=None, env=None, universal_newlines=None,
startupinfo=None, creationflags=0,
restore_signals=PY3, start_new_session=False,
restore_signals=True, start_new_session=False,
pass_fds=(),
# Added in 3.6. These are kept as ivars
encoding=None, errors=None,
......@@ -696,7 +682,7 @@ class Popen(object):
if bufsize is None:
# Python 2 doesn't allow None at all, but Python 3 treats
# it the same as the default. We do as well.
bufsize = -1 if PY3 else 0
bufsize = -1
if not isinstance(bufsize, integer_types):
raise TypeError("bufsize must be an integer")
......@@ -704,20 +690,10 @@ class Popen(object):
if preexec_fn is not None:
raise ValueError("preexec_fn is not supported on Windows "
"platforms")
if PY37:
if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS:
close_fds = True
else:
any_stdio_set = (stdin is not None or stdout is not None or
stderr is not None)
if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS:
if any_stdio_set:
close_fds = False
else:
close_fds = True
elif close_fds and any_stdio_set:
raise ValueError("close_fds is not supported on Windows "
"platforms if you redirect stdin/stdout/stderr")
if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS:
close_fds = True
if threadpool is None:
threadpool = hub.threadpool
self.threadpool = threadpool
......@@ -726,10 +702,7 @@ class Popen(object):
# POSIX
if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS:
# close_fds has different defaults on Py3/Py2
if PY3: # pylint: disable=simplifiable-if-statement
close_fds = True
else:
close_fds = False
close_fds = True
if pass_fds and not close_fds:
import warnings
......@@ -791,7 +764,7 @@ class Popen(object):
if errread != -1:
errread = msvcrt.open_osfhandle(errread.Detach(), 0)
text_mode = PY3 and (self.encoding or self.errors or universal_newlines or text)
text_mode = self.encoding or self.errors or universal_newlines or text
if text_mode or universal_newlines:
# Always a native str in universal_newlines mode, even when that
# str type is bytes. Additionally, text_mode is only true under
......@@ -801,7 +774,7 @@ class Popen(object):
uid, gid, gids = self.__handle_uids(user, group, extra_groups)
if p2cwrite != -1:
if PY3 and text_mode:
if text_mode:
# Under Python 3, if we left on the 'b' we'd get different results
# depending on whether we used FileObjectPosix or FileObjectThread
self.stdin = FileObject(p2cwrite, 'w', bufsize,
......@@ -811,25 +784,20 @@ class Popen(object):
if c2pread != -1:
if universal_newlines or text_mode:
if PY3:
self.stdout = FileObject(c2pread, 'r', bufsize,
encoding=self.encoding, errors=self.errors)
# NOTE: Universal Newlines are broken on Windows/Py3, at least
# in some cases. This is true in the stdlib subprocess module
# as well; the following line would fix the test cases in
# test__subprocess.py that depend on python_universal_newlines,
# but would be inconsistent with the stdlib:
else:
self.stdout = FileObject(c2pread, 'rU', bufsize)
self.stdout = FileObject(c2pread, 'r', bufsize,
encoding=self.encoding, errors=self.errors)
# NOTE: Universal Newlines are broken on Windows/Py3, at least
# in some cases. This is true in the stdlib subprocess module
# as well; the following line would fix the test cases in
# test__subprocess.py that depend on python_universal_newlines,
# but would be inconsistent with the stdlib:
else:
self.stdout = FileObject(c2pread, 'rb', bufsize)
if errread != -1:
if universal_newlines or text_mode:
if PY3:
self.stderr = FileObject(errread, 'r', bufsize,
encoding=encoding, errors=errors)
else:
self.stderr = FileObject(errread, 'rU', bufsize)
self.stderr = FileObject(errread, 'r', bufsize,
encoding=encoding, errors=errors)
else:
self.stderr = FileObject(errread, 'rb', bufsize)
......@@ -853,8 +821,6 @@ class Popen(object):
# (gevent: New in python3, but reported as gevent bug in #347.
# Note that under Py2, any error raised below will replace the
# original error so we have to use reraise)
if not PY3:
exc_info = sys.exc_info()
for f in filter(None, (self.stdin, self.stdout, self.stderr)):
try:
f.close()
......@@ -876,11 +842,6 @@ class Popen(object):
os.close(fd)
except (OSError, IOError):
pass
if not PY3:
try:
reraise(*exc_info)
finally:
del exc_info
raise
def __handle_uids(self, user, group, extra_groups):
......@@ -1074,7 +1035,7 @@ class Popen(object):
# blocks forever.
self.wait()
def _gevent_result_wait(self, timeout=None, raise_exc=PY3):
def _gevent_result_wait(self, timeout=None, raise_exc=True):
result = self.result.wait(timeout=timeout)
if raise_exc and timeout is not None and not self.result.ready():
raise TimeoutExpired(self.args, timeout)
......@@ -1108,13 +1069,11 @@ class Popen(object):
p2cread = GetStdHandle(STD_INPUT_HANDLE)
if p2cread is None:
p2cread, _ = CreatePipe(None, 0)
if PY3:
p2cread = Handle(p2cread)
_winapi.CloseHandle(_)
p2cread = Handle(p2cread)
_winapi.CloseHandle(_)
elif stdin == PIPE:
p2cread, p2cwrite = CreatePipe(None, 0)
if PY3:
p2cread, p2cwrite = Handle(p2cread), Handle(p2cwrite)
p2cread, p2cwrite = Handle(p2cread), Handle(p2cwrite)
elif stdin == _devnull:
p2cread = msvcrt.get_osfhandle(self._get_devnull())
elif isinstance(stdin, int):
......@@ -1128,13 +1087,11 @@ class Popen(object):
c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE)
if c2pwrite is None:
_, c2pwrite = CreatePipe(None, 0)
if PY3:
c2pwrite = Handle(c2pwrite)
_winapi.CloseHandle(_)
c2pwrite = Handle(c2pwrite)
_winapi.CloseHandle(_)
elif stdout == PIPE:
c2pread, c2pwrite = CreatePipe(None, 0)
if PY3:
c2pread, c2pwrite = Handle(c2pread), Handle(c2pwrite)
c2pread, c2pwrite = Handle(c2pread), Handle(c2pwrite)
elif stdout == _devnull:
c2pwrite = msvcrt.get_osfhandle(self._get_devnull())
elif isinstance(stdout, int):
......@@ -1148,13 +1105,11 @@ class Popen(object):
errwrite = GetStdHandle(STD_ERROR_HANDLE)
if errwrite is None:
_, errwrite = CreatePipe(None, 0)
if PY3:
errwrite = Handle(errwrite)
_winapi.CloseHandle(_)
errwrite = Handle(errwrite)
_winapi.CloseHandle(_)
elif stderr == PIPE:
errread, errwrite = CreatePipe(None, 0)
if PY3:
errread, errwrite = Handle(errread), Handle(errwrite)
errread, errwrite = Handle(errread), Handle(errwrite)
elif stderr == STDOUT:
errwrite = c2pwrite
elif stderr == _devnull:
......@@ -1223,7 +1178,7 @@ class Popen(object):
if isinstance(args, str):
pass
elif isinstance(args, bytes):
if shell and PY3:
if shell:
raise TypeError('bytes args is not allowed on Windows')
args = list2cmdline([args])
elif isinstance(args, PathLike):
......@@ -1317,7 +1272,7 @@ class Popen(object):
# CreateProcess call on PyPy. Currently we don't test PyPy3 on Windows,
# so we don't know for sure if it's built into CreateProcess there.
if PYPY:
def _check_nul(s, err_kind=(ValueError if PY3 else TypeError)):
def _check_nul(s, err_kind=ValueError):
if not s:
return
nul = b'\0' if isinstance(s, bytes) else '\0'
......@@ -1347,14 +1302,13 @@ class Popen(object):
env,
cwd, # fsdecode handled earlier
startupinfo)
except IOError as e: # From 2.6 on, pywintypes.error was defined as IOError
# Translate pywintypes.error to WindowsError, which is
# a subclass of OSError. FIXME: We should really
# translate errno using _sys_errlist (or similar), but
# how can this be done from Python?
if PY3:
raise # don't remap here
raise WindowsError(*e.args)
# except IOError as e: # From 2.6 on, pywintypes.error was defined as IOError
# # Translate pywintypes.error to WindowsError, which is
# # a subclass of OSError. FIXME: We should really
# # translate errno using _sys_errlist (or similar), but
# # how can this be done from Python?
# raise # don't remap here
# raise WindowsError(*e.args)
finally:
# Child is launched. Close the parent's copy of those pipe
# handles that only the child should have open. You need
......@@ -1408,7 +1362,7 @@ class Popen(object):
def _wait(self):
self.threadpool.spawn(self._blocking_wait).rawlink(self.result)
def wait(self, timeout=None, _raise_exc=PY3):
def wait(self, timeout=None, _raise_exc=True):
"""Wait for child process to terminate. Returns returncode
attribute."""
if self.returncode is None:
......@@ -1628,9 +1582,7 @@ class Popen(object):
start_new_session, process_group):
"""Execute program (POSIX version)"""
if PY3 and isinstance(args, (str, bytes)):
args = [args]
elif not PY3 and isinstance(args, string_types):
if isinstance(args, (str, bytes)):
args = [args]
elif isinstance(args, PathLike):
if shell:
......@@ -1728,7 +1680,7 @@ class Popen(object):
# Close pipe fds. Make sure we don't close the
# same fd more than once, or standard fds.
if not PY3:
if not True:
closed = set([None])
for fd in [p2cread, c2pwrite, errwrite]:
if fd not in closed and fd > 2:
......@@ -1785,17 +1737,16 @@ class Popen(object):
if env is None:
os.execvp(executable, args)
else:
if PY3:
# Python 3.6 started testing for
# bytes values in the env; it also
# started encoding strs using
# fsencode and using a lower-level
# API that takes a list of keys
# and values. We don't have access
# to that API, so we go the reverse direction.
env = {os.fsdecode(k) if isinstance(k, bytes) else k:
os.fsdecode(v) if isinstance(v, bytes) else v
for k, v in env.items()}
# Python 3.6 started testing for
# bytes values in the env; it also
# started encoding strs using
# fsencode and using a lower-level
# API that takes a list of keys
# and values. We don't have access
# to that API, so we go the reverse direction.
env = {os.fsdecode(k) if isinstance(k, bytes) else k:
os.fsdecode(v) if isinstance(v, bytes) else v
for k, v in env.items()}
os.execvpe(executable, args, env)
except:
......@@ -1893,7 +1844,7 @@ class Popen(object):
sleep(0.00001)
return self.returncode
def wait(self, timeout=None, _raise_exc=PY3):
def wait(self, timeout=None, _raise_exc=True):
"""
Wait for child process to terminate. Returns :attr:`returncode`
attribute.
......
......@@ -115,7 +115,6 @@ from .skipping import skipOnPy310
from .skipping import skipOnPy3
from .skipping import skipWithoutResource
from .skipping import skipWithoutExternalNetwork
from .skipping import skipOnPy2
from .skipping import skipOnManylinux
from .skipping import skipOnMacOnCI
......
......@@ -45,7 +45,6 @@ skipOnPyPy3OnCI = _do_not_skip
skipOnPyPy3 = _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
skipOnPy37 = unittest.skip if sysinfo.PY37 else _do_not_skip
skipOnPy310 = unittest.skip if sysinfo.PY310 else _do_not_skip
......
......@@ -17,18 +17,10 @@ try:
except ImportError:
GreenOpenDescriptor = None
from gevent._compat import PY2
from gevent._compat import PY3
from gevent._compat import text_type
import gevent.testing as greentest
from gevent.testing import sysinfo
try:
ResourceWarning # pylint:disable=used-before-assignment
except NameError:
class ResourceWarning(Warning):
"Python 2 fallback"
# pylint:disable=unspecified-encoding
......@@ -136,11 +128,9 @@ class TestFileObjectBlock(CleanupMixin,
with open(path, 'rb') as f_raw:
f = self._makeOne(f_raw, 'rb', close=False)
if PY3 or hasattr(f, 'seekable'):
# On Python 3, all objects should have seekable.
# On Python 2, only our custom objects do.
self.assertTrue(f.seekable())
# On Python 3, all objects should have seekable.
# On Python 2, only our custom objects do.
self.assertTrue(f.seekable())
f.seek(15)
self.assertEqual(15, f.tell())
......@@ -169,7 +159,7 @@ class TestFileObjectBlock(CleanupMixin,
else:
# 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.
opener = io.open if PY3 else open
opener = io.open
with opener(path, open_mode, **open_kwargs) as raw:
with self._makeOne(raw) as f:
gevent_data = getattr(f, meth)()
......@@ -190,7 +180,7 @@ class TestFileObjectBlock(CleanupMixin,
'r+',
buffering=5, encoding='utf-8'
)
self.assertIsInstance(gevent_data, text_type)
self.assertIsInstance(gevent_data, str)
@skipUnlessWorksWithRegularFiles
def test_does_not_leak_on_exception(self):
......@@ -341,7 +331,7 @@ class ConcurrentFileObjectMixin(object):
self.addCleanup(os.close, w)
reader = self._makeOne(r)
self._close_on_teardown(reader)
self.assertEqual(PY2, hasattr(reader, 'read1'))
self.assertFalse(hasattr(reader, 'read1'))
def test_bufsize_0(self):
# Issue #840
......
import sys
import unittest
from gevent.testing import skipOnPy2
class TestSubnormalFloatsAreNotDisabled(unittest.TestCase):
@skipOnPy2('This test always fails on Python 2')
def test_subnormal_is_not_zero(self):
# Enabling the -Ofast compiler flag resulted in subnormal floats getting
# disabled the moment when gevent was imported. This impacted libraries
......@@ -21,7 +19,7 @@ class TestSubnormalFloatsAreNotDisabled(unittest.TestCase):
# `sys.float_info.min` is the minimum representable positive normalized
# float, so dividing it by two gives us a positive subnormal float,
# 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__":
......
......@@ -104,21 +104,19 @@ class TestRun(greentest.TestCase):
# 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
# 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):
# Issue 1484
# If we don't have this correct, then we get exceptions
out = self._run(os.path.join('monkey_package', 'threadpool_monkey_patches.py'))
self.assertEqual(out, ['False', '2'])
@greentest.skipOnPy2("lost sys.stderr sometimes")
def test_threadpool_in_patched_after_patch_module(self):
# Issue 1484
# If we don't have this correct, then we get exceptions
out = self._run('monkey_package.threadpool_monkey_patches', module=True)
self.assertEqual(out, ['False', '2'])
@greentest.skipOnPy2("lost sys.stderr sometimes")
def test_threadpool_not_patched_after_patch_module(self):
# Issue 1484
# If we don't have this correct, then we get exceptions
......
......@@ -17,9 +17,6 @@ from gevent.tests.test__selectors import SelectorTestMixin
class TestSelectors(SelectorTestMixin, greentest.TestCase):
@greentest.skipOnPy2(
'selectors2 backport does not use _select'
)
@greentest.skipOnWindows(
"SelectSelector._select is a normal function on Windows"
)
......
......@@ -11,6 +11,7 @@ class Test(unittest.TestCase):
# Issue 1108: Python 2, importing pkg_resources,
# as is done for namespace packages, imports ssl,
# leading to an unwanted SSL warning.
# This is a deprecated API though.
__import__('pkg_resources')
from gevent import monkey
......
......@@ -111,7 +111,6 @@ class TestPopen(greentest.TestCase):
'pineapple\n\xff\xff\xf2\xf9\n')
@greentest.skipOnWindows("Windows IO is weird; this doesn't raise")
@greentest.skipOnPy2("Only Python 2 decodes")
def test_communicate_undecodable(self):
# If the subprocess writes non-decodable data, `communicate` raises the
# same UnicodeDecodeError that the stdlib does, instead of
......
......@@ -9,7 +9,6 @@ Implementation of the standard :mod:`thread` module that spawns greenlets.
:class:`gevent.Greenlet` class or :func:`gevent.spawn`.
"""
from __future__ import absolute_import
import sys
__implements__ = [
'allocate_lock',
......@@ -22,31 +21,23 @@ __implements__ = [
]
__imports__ = ['error']
if sys.version_info[0] == 2:
import thread as __thread__ # pylint:disable=import-error
PY2 = True
PY3 = False
# Name the `future` backport that might already have been imported;
# Importing `pkg_resources` imports this, for example.
__alternate_targets__ = ('_thread',)
else:
import _thread as __thread__ # pylint:disable=import-error
PY2 = False
PY3 = True
__target__ = '_thread'
__imports__ += [
'TIMEOUT_MAX',
'allocate',
'exit_thread',
'interrupt_main',
'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')
import _thread as __thread__ # pylint:disable=import-error
__target__ = '_thread'
__imports__ += [
'TIMEOUT_MAX',
'allocate',
'exit_thread',
'interrupt_main',
'start_new'
]
# 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
......@@ -63,7 +54,6 @@ from gevent.local import local as _local
from gevent.exceptions import LoopExit
if hasattr(__thread__, 'RLock'):
assert PY3 or PYPY
# Added in Python 3.4, backported to PyPy 2.7-7.0
__imports__.append("RLock")
......@@ -88,13 +78,11 @@ class LockType(BoundedSemaphore):
# and any other API changes we need to make to match behaviour
_OVER_RELEASE_ERROR = __thread__.error
if PYPY and PY3:
if PYPY:
_OVER_RELEASE_ERROR = RuntimeError
if PY3:
_TIMEOUT_MAX = __thread__.TIMEOUT_MAX # python 2: pylint:disable=no-member
else:
_TIMEOUT_MAX = 9223372036.0
_TIMEOUT_MAX = __thread__.TIMEOUT_MAX # pylint:disable=no-member
def acquire(self, blocking=True, timeout=-1):
# This is the Python 3 signature.
......
......@@ -50,8 +50,7 @@ from gevent.thread import get_ident as _get_ident
from gevent.hub import sleep as _sleep, getcurrent
from gevent.lock import RLock
from gevent._compat import PY3
from gevent._compat import PYPY
from gevent._util import LazyOnClass
# Exports, prevent unused import warnings.
......@@ -168,46 +167,45 @@ else:
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):
super(Thread, self)._set_tstate_lock()
greenlet = getcurrent()
greenlet.rawlink(self.__greenlet_finished)
class Thread(__threading__.Thread):
def __greenlet_finished(self, _):
if self._tstate_lock:
self._tstate_lock.release()
self._stop()
def _set_tstate_lock(self):
super(Thread, self)._set_tstate_lock()
greenlet = getcurrent()
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
pass
__implements__.append('Thread')
class Timer(Thread, __threading__.Timer): # pylint:disable=abstract-method,inherit-non-class
pass
__implements__.append('Timer')
__implements__.append('Timer')
_set_sentinel = allocate_lock
__implements__.append('_set_sentinel')
# The main thread is patched up with more care
# in _gevent_will_monkey_patch
_set_sentinel = allocate_lock
__implements__.append('_set_sentinel')
# The main thread is patched up with more care
# in _gevent_will_monkey_patch
if PY3:
__implements__.remove('_get_ident')
__implements__.append('get_ident')
get_ident = _get_ident
__implements__.remove('_sleep')
__implements__.remove('_get_ident')
__implements__.append('get_ident')
get_ident = _get_ident
__implements__.remove('_sleep')
if hasattr(__threading__, '_CRLock'):
# Python 3 changed the implementation of threading.RLock
......@@ -219,7 +217,6 @@ if hasattr(__threading__, '_CRLock'):
# if the imported _CRLock is None; this arranges for that to be the case.
# This was also backported to PyPy 2.7-7.0
assert PY3 or PYPY, "Unsupported Python version"
_CRLock = None
__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