Python 3 compat: Improve subprocess, WSGI and tests

This commit is contained in:
Jakub Stasiak
2014-10-11 19:46:51 +01:00
parent 1c30e9b39f
commit d19770ec64
5 changed files with 44 additions and 47 deletions

View File

@@ -21,7 +21,7 @@ if getattr(subprocess_orig, 'TimeoutExpired', None) is None:
a child process. a child process.
""" """
def __init__(self, cmd, output=None): def __init__(self, timeout, cmd, output=None):
self.cmd = cmd self.cmd = cmd
self.output = output self.output = output
@@ -64,7 +64,7 @@ class Popen(subprocess_orig.Popen):
if status is not None: if status is not None:
return status return status
if timeout is not None and time.time() > endtime: if timeout is not None and time.time() > endtime:
raise TimeoutExpired(self.args) raise TimeoutExpired(self.args, timeout)
eventlet.sleep(check_interval) eventlet.sleep(check_interval)
except OSError as e: except OSError as e:
if e.errno == errno.ECHILD: if e.errno == errno.ECHILD:

View File

@@ -100,7 +100,7 @@ class Timeout(BaseException):
def __str__(self): def __str__(self):
""" """
>>> raise Timeout >>> raise Timeout # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last): Traceback (most recent call last):
... ...
Timeout Timeout

View File

@@ -99,10 +99,10 @@ class Input(object):
if self.hundred_continue_headers is not None: if self.hundred_continue_headers is not None:
# 100 Continue headers # 100 Continue headers
for header in self.hundred_continue_headers: for header in self.hundred_continue_headers:
towrite.append('%s: %s\r\n' % header) towrite.append(six.b('%s: %s\r\n' % header))
# Blank line # Blank line
towrite.append('\r\n') towrite.append(b'\r\n')
self.wfile.writelines(towrite) self.wfile.writelines(towrite)
self.wfile = None self.wfile = None
@@ -558,7 +558,7 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
if env.get('HTTP_EXPECT') == '100-continue': if env.get('HTTP_EXPECT') == '100-continue':
wfile = self.wfile wfile = self.wfile
wfile_line = 'HTTP/1.1 100 Continue\r\n' wfile_line = b'HTTP/1.1 100 Continue\r\n'
else: else:
wfile = None wfile = None
wfile_line = None wfile_line = None
@@ -580,6 +580,9 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
greenio.shutdown_safe(self.connection) greenio.shutdown_safe(self.connection)
self.connection.close() self.connection.close()
def handle_expect_100(self):
return True
class Server(BaseHTTPServer.HTTPServer): class Server(BaseHTTPServer.HTTPServer):

View File

@@ -8,6 +8,7 @@ import eventlet
import os import os
import sys import sys
import signal import signal
from eventlet.support import bytes_to_str, six
mydir = %r mydir = %r
signal_file = os.path.join(mydir, "output.txt") signal_file = os.path.join(mydir, "output.txt")
pid = os.fork() pid = os.fork()
@@ -30,18 +31,18 @@ if (pid != 0):
break break
except (IOError, IndexError): except (IOError, IndexError):
eventlet.sleep(0.1) eventlet.sleep(0.1)
print('result {0}'.format(result)) print('result {0}'.format(bytes_to_str(result)))
finally: finally:
os.kill(pid, signal.SIGTERM) os.kill(pid, signal.SIGTERM)
else: else:
try: try:
s = eventlet.listen(('', 0)) s = eventlet.listen(('', 0))
fd = open(signal_file, "wb") fd = open(signal_file, "wb")
fd.write(str(s.getsockname()[1])) fd.write(six.b(str(s.getsockname()[1])))
fd.write("\\n") fd.write(b"\\n")
fd.flush() fd.flush()
s.accept() s.accept()
fd.write("done") fd.write(b"done")
fd.flush() fd.flush()
finally: finally:
fd.close() fd.close()

View File

@@ -17,7 +17,7 @@ from eventlet.green import subprocess
from eventlet import greenio from eventlet import greenio
from eventlet import greenthread from eventlet import greenthread
from eventlet import support from eventlet import support
from eventlet.support import six from eventlet.support import bytes_to_str, six
from eventlet import tpool from eventlet import tpool
from eventlet import wsgi from eventlet import wsgi
@@ -27,13 +27,6 @@ import tests
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key') private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key')
if six.PY3:
def bytes_to_str(b):
return b.decode()
else:
def bytes_to_str(b):
return b
HttpReadResult = collections.namedtuple( HttpReadResult = collections.namedtuple(
'HttpReadResult', 'HttpReadResult',
@@ -347,7 +340,7 @@ class TestHttpd(_TestBase):
def test_007_get_arg(self): def test_007_get_arg(self):
# define a new handler that does a get_arg as well as a read_body # define a new handler that does a get_arg as well as a read_body
def new_app(env, start_response): def new_app(env, start_response):
body = env['wsgi.input'].read() body = bytes_to_str(env['wsgi.input'].read())
a = cgi.parse_qs(body).get('a', [1])[0] a = cgi.parse_qs(body).get('a', [1])[0]
start_response('200 OK', [('Content-type', 'text/plain')]) start_response('200 OK', [('Content-type', 'text/plain')])
return [six.b('a is %s, body is %s' % (a, body))] return [six.b('a is %s, body is %s' % (a, body))]
@@ -368,7 +361,7 @@ class TestHttpd(_TestBase):
# send some junk after the actual request # send some junk after the actual request
fd.write(b'01234567890123456789') fd.write(b'01234567890123456789')
result = read_http(sock) result = read_http(sock)
self.assertEqual(result.body, 'a is a, body is a=a') self.assertEqual(result.body, b'a is a, body is a=a')
fd.close() fd.close()
def test_008_correctresponse(self): def test_008_correctresponse(self):
@@ -434,7 +427,7 @@ class TestHttpd(_TestBase):
assert chunks > 1 assert chunks > 1
response = fd.read() response = fd.read()
# Require a CRLF to close the message body # Require a CRLF to close the message body
self.assertEqual(response, '\r\n') self.assertEqual(response, b'\r\n')
@tests.skip_if_no_ssl @tests.skip_if_no_ssl
def test_012_ssl_server(self): def test_012_ssl_server(self):
@@ -771,7 +764,7 @@ class TestHttpd(_TestBase):
break break
else: else:
header_lines.append(line) header_lines.append(line)
assert header_lines[0].startswith('HTTP/1.1 100 Continue') assert header_lines[0].startswith(b'HTTP/1.1 100 Continue')
header_lines = [] header_lines = []
while True: while True:
line = fd.readline() line = fd.readline()
@@ -779,7 +772,7 @@ class TestHttpd(_TestBase):
break break
else: else:
header_lines.append(line) header_lines.append(line)
assert header_lines[0].startswith('HTTP/1.1 200 OK') assert header_lines[0].startswith(b'HTTP/1.1 200 OK')
assert fd.read(7) == b'testing' assert fd.read(7) == b'testing'
fd.close() fd.close()
sock.close() sock.close()
@@ -788,7 +781,7 @@ class TestHttpd(_TestBase):
def wsgi_app(environ, start_response): def wsgi_app(environ, start_response):
if int(environ['CONTENT_LENGTH']) > 1024: if int(environ['CONTENT_LENGTH']) > 1024:
start_response('417 Expectation Failed', [('Content-Length', '7')]) start_response('417 Expectation Failed', [('Content-Length', '7')])
return ['failure'] return [b'failure']
else: else:
environ['wsgi.input'].set_hundred_continue_response_headers( environ['wsgi.input'].set_hundred_continue_response_headers(
[('Hundred-Continue-Header-1', 'H1'), [('Hundred-Continue-Header-1', 'H1'),
@@ -799,13 +792,13 @@ class TestHttpd(_TestBase):
return [text] return [text]
self.site.application = wsgi_app self.site.application = wsgi_app
sock = eventlet.connect(('localhost', self.port)) sock = eventlet.connect(('localhost', self.port))
fd = sock.makefile('rw') fd = sock.makefile('rwb')
fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n' fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n'
b'Expect: 100-continue\r\n\r\n') b'Expect: 100-continue\r\n\r\n')
fd.flush() fd.flush()
result = read_http(sock) result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 417 Expectation Failed') self.assertEqual(result.status, 'HTTP/1.1 417 Expectation Failed')
self.assertEqual(result.body, 'failure') self.assertEqual(result.body, b'failure')
fd.write( fd.write(
b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 7\r\n' b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 7\r\n'
b'Expect: 100-continue\r\n\r\ntesting') b'Expect: 100-continue\r\n\r\ntesting')
@@ -813,27 +806,27 @@ class TestHttpd(_TestBase):
header_lines = [] header_lines = []
while True: while True:
line = fd.readline() line = fd.readline()
if line == '\r\n': if line == b'\r\n':
break break
else: else:
header_lines.append(line.strip()) header_lines.append(line.strip())
assert header_lines[0].startswith('HTTP/1.1 100 Continue') assert header_lines[0].startswith(b'HTTP/1.1 100 Continue')
headers = dict((k, v) for k, v in (h.split(': ', 1) for h in header_lines[1:])) headers = dict((k, v) for k, v in (h.split(b': ', 1) for h in header_lines[1:]))
assert 'Hundred-Continue-Header-1' in headers assert b'Hundred-Continue-Header-1' in headers
assert 'Hundred-Continue-Header-2' in headers assert b'Hundred-Continue-Header-2' in headers
assert 'Hundred-Continue-Header-K' in headers assert b'Hundred-Continue-Header-K' in headers
self.assertEqual('H1', headers['Hundred-Continue-Header-1']) self.assertEqual(b'H1', headers[b'Hundred-Continue-Header-1'])
self.assertEqual('H2', headers['Hundred-Continue-Header-2']) self.assertEqual(b'H2', headers[b'Hundred-Continue-Header-2'])
self.assertEqual('Hk', headers['Hundred-Continue-Header-K']) self.assertEqual(b'Hk', headers[b'Hundred-Continue-Header-K'])
header_lines = [] header_lines = []
while True: while True:
line = fd.readline() line = fd.readline()
if line == '\r\n': if line == b'\r\n':
break break
else: else:
header_lines.append(line) header_lines.append(line)
assert header_lines[0].startswith('HTTP/1.1 200 OK') assert header_lines[0].startswith(b'HTTP/1.1 200 OK')
self.assertEqual(fd.read(7), 'testing') self.assertEqual(fd.read(7), b'testing')
fd.close() fd.close()
sock.close() sock.close()
@@ -1079,7 +1072,7 @@ class TestHttpd(_TestBase):
'POST / HTTP/1.0\r\n' 'POST / HTTP/1.0\r\n'
'Host: localhost\r\n' 'Host: localhost\r\n'
'Content-Length: %i\r\n\r\n%s' 'Content-Length: %i\r\n\r\n%s'
) % (len(upload_data), upload_data) ) % (len(upload_data), bytes_to_str(upload_data))
sock = eventlet.connect(('localhost', self.port)) sock = eventlet.connect(('localhost', self.port))
fd = sock.makefile('rwb') fd = sock.makefile('rwb')
fd.write(request.encode()) fd.write(request.encode())
@@ -1092,7 +1085,7 @@ class TestHttpd(_TestBase):
def test_zero_length_chunked_response(self): def test_zero_length_chunked_response(self):
def zero_chunked_app(env, start_response): def zero_chunked_app(env, start_response):
start_response('200 OK', [('Content-type', 'text/plain')]) start_response('200 OK', [('Content-type', 'text/plain')])
yield "" yield b""
self.site.application = zero_chunked_app self.site.application = zero_chunked_app
sock = eventlet.connect( sock = eventlet.connect(
@@ -1106,9 +1099,9 @@ class TestHttpd(_TestBase):
while True: while True:
h = response.pop(0) h = response.pop(0)
headers.append(h) headers.append(h)
if h == '': if h == b'':
break break
assert b'Transfer-Encoding: chunked' in ''.join(headers) assert b'Transfer-Encoding: chunked' in b''.join(headers), headers
# should only be one chunk of zero size with two blank lines # should only be one chunk of zero size with two blank lines
# (one terminates the chunk, one terminates the body) # (one terminates the chunk, one terminates the body)
self.assertEqual(response, [b'0', b'', b'']) self.assertEqual(response, [b'0', b'', b''])
@@ -1190,8 +1183,8 @@ class TestHttpd(_TestBase):
def test_path_info_decoding(self): def test_path_info_decoding(self):
def wsgi_app(environ, start_response): def wsgi_app(environ, start_response):
start_response("200 OK", []) start_response("200 OK", [])
yield "decoded: %s" % environ['PATH_INFO'] yield six.b("decoded: %s" % environ['PATH_INFO'])
yield "raw: %s" % environ['RAW_PATH_INFO'] yield six.b("raw: %s" % environ['RAW_PATH_INFO'])
self.site.application = wsgi_app self.site.application = wsgi_app
sock = eventlet.connect(('localhost', self.port)) sock = eventlet.connect(('localhost', self.port))
fd = sock.makefile('rwb') fd = sock.makefile('rwb')
@@ -1467,7 +1460,7 @@ class TestChunkedInput(_TestBase):
def ping(self, fd): def ping(self, fd):
fd.sendall(b"GET /ping HTTP/1.1\r\n\r\n") fd.sendall(b"GET /ping HTTP/1.1\r\n\r\n")
self.assertEqual(read_http(fd).body, "pong") self.assertEqual(read_http(fd).body, b"pong")
def test_short_read_with_content_length(self): def test_short_read_with_content_length(self):
body = self.body() body = self.body()
@@ -1529,12 +1522,12 @@ class TestChunkedInput(_TestBase):
fd = self.connect() fd = self.connect()
fd.sendall(b"POST /yield_spaces/override_min HTTP/1.1\r\nContent-Length: 0\r\n\r\n") fd.sendall(b"POST /yield_spaces/override_min HTTP/1.1\r\nContent-Length: 0\r\n\r\n")
resp_so_far = '' resp_so_far = b''
with eventlet.Timeout(.1): with eventlet.Timeout(.1):
while True: while True:
one_byte = fd.recv(1) one_byte = fd.recv(1)
resp_so_far += one_byte resp_so_far += one_byte
if resp_so_far.endswith('\r\n\r\n'): if resp_so_far.endswith(b'\r\n\r\n'):
break break
self.assertEqual(fd.recv(1), b' ') self.assertEqual(fd.recv(1), b' ')
try: try: