Remove select.poll and improve subprocess

green select: Delete unpatched poll once again

https://github.com/eventlet/eventlet/pull/317

Previously attempted in f63165c, had to be reverted in 8ea9df6 because
subprocess was failing after monkey patching.

Turns out we haven't been monkey patching the subprocess module at all,
this patch adds that in order for the tests to pass.

This part is changed because otherwise Popen class instantiation would
cause an infinite loop when monkey patching is applied:

    -subprocess_orig = __import__("subprocess")
    +subprocess_orig = patcher.original("subprocess")

This patch is contributed by Smarkets Limited.

* green subprocess: Provide green check_output

This patch is contributed by Smarkets Limited.
This commit is contained in:
Jakub Stasiak
2016-05-20 10:23:36 +02:00
committed by Sergey Shepelev
parent d3db9f5064
commit 614a20462a
6 changed files with 37 additions and 16 deletions

View File

@@ -6,9 +6,7 @@ from eventlet.support import six
__patched__ = ['select']
# FIXME: must also delete `poll`, but it breaks subprocess `communicate()`
# https://github.com/eventlet/eventlet/issues/290
__deleted__ = ['devpoll', 'epoll', 'kqueue', 'kevent']
__deleted__ = ['devpoll', 'poll', 'epoll', 'kqueue', 'kevent']
def get_fileno(obj):

View File

@@ -9,6 +9,7 @@ from eventlet.green import select, threading, time
from eventlet.support import six
__patched__ = ['call', 'check_call', 'Popen']
to_patch = [('select', select), ('threading', threading), ('time', time)]
if sys.version_info > (3, 4):
@@ -16,7 +17,7 @@ if sys.version_info > (3, 4):
to_patch.append(('selectors', selectors))
patcher.inject('subprocess', globals(), *to_patch)
subprocess_orig = __import__("subprocess")
subprocess_orig = patcher.original("subprocess")
mswindows = sys.platform == "win32"
@@ -114,7 +115,17 @@ class Popen(subprocess_orig.Popen):
except AttributeError:
pass
# Borrow subprocess.call() and check_call(), but patch them so they reference
# OUR Popen class rather than subprocess.Popen.
call = FunctionType(six.get_function_code(subprocess_orig.call), globals())
check_call = FunctionType(six.get_function_code(subprocess_orig.check_call), globals())
def patched_function(function):
return FunctionType(six.get_function_code(function), globals())
call = patched_function(subprocess_orig.call)
check_call = patched_function(subprocess_orig.check_call)
# check_output is Python 2.7+
if hasattr(subprocess_orig, 'check_output'):
__patched__.append('check_output')
check_output = patched_function(subprocess_orig.check_output)
del patched_function

View File

@@ -224,7 +224,7 @@ def monkey_patch(**on):
"""
accepted_args = set(('os', 'select', 'socket',
'thread', 'time', 'psycopg', 'MySQLdb',
'builtins'))
'builtins', 'subprocess'))
# To make sure only one of them is passed here
assert not ('__builtin__' in on and 'builtins' in on)
try:
@@ -262,6 +262,7 @@ def monkey_patch(**on):
('time', _green_time_modules),
('MySQLdb', _green_MySQLdb),
('builtins', _green_builtins),
('subprocess', _green_subprocess_modules),
]:
if on[name] and not already_patched.get(name):
modules_to_patch += modules_function()
@@ -401,6 +402,11 @@ def _green_socket_modules():
return [('socket', socket)]
def _green_subprocess_modules():
from eventlet.green import subprocess
return [('subprocess', subprocess)]
def _green_thread_modules():
from eventlet.green import Queue
from eventlet.green import thread

View File

@@ -6,6 +6,14 @@ if __name__ == '__main__':
from eventlet.green import MySQLdb as gm
patcher.monkey_patch(all=True, MySQLdb=True)
patched_set = set(patcher.already_patched) - set(['psycopg'])
assert patched_set == frozenset(['MySQLdb', 'os', 'select', 'socket', 'thread', 'time'])
assert patched_set == frozenset([
'MySQLdb',
'os',
'select',
'socket',
'subprocess',
'thread',
'time',
])
assert m.connect == gm.connect
print('pass')

View File

@@ -11,9 +11,7 @@ if __name__ == '__main__':
# * https://bitbucket.org/eventlet/eventlet/issues/167
# * https://github.com/eventlet/eventlet/issues/169
import select
# FIXME: must also delete `poll`, but it breaks subprocess `communicate()`
# https://github.com/eventlet/eventlet/issues/290
for name in ['devpoll', 'epoll', 'kqueue', 'kevent']:
for name in ['devpoll', 'poll', 'epoll', 'kqueue', 'kevent']:
assert not hasattr(select, name), name
import sys

View File

@@ -185,15 +185,15 @@ print("already_patched {0}".format(",".join(sorted(patcher.already_patched.keys(
def test_boolean(self):
self.assert_boolean_logic("patcher.monkey_patch()",
'os,select,socket,thread,time')
'os,select,socket,subprocess,thread,time')
def test_boolean_all(self):
self.assert_boolean_logic("patcher.monkey_patch(all=True)",
'os,select,socket,thread,time')
'os,select,socket,subprocess,thread,time')
def test_boolean_all_single(self):
self.assert_boolean_logic("patcher.monkey_patch(all=True, socket=True)",
'os,select,socket,thread,time')
'os,select,socket,subprocess,thread,time')
def test_boolean_all_negative(self):
self.assert_boolean_logic(
@@ -210,11 +210,11 @@ print("already_patched {0}".format(",".join(sorted(patcher.already_patched.keys(
def test_boolean_negative(self):
self.assert_boolean_logic("patcher.monkey_patch(socket=False)",
'os,select,thread,time')
'os,select,subprocess,thread,time')
def test_boolean_negative2(self):
self.assert_boolean_logic("patcher.monkey_patch(socket=False, time=False)",
'os,select,thread')
'os,select,subprocess,thread')
def test_conflicting_specifications(self):
self.assert_boolean_logic("patcher.monkey_patch(socket=False, select=True)",