Commit c9da45d0 authored by Jason Madden's avatar Jason Madden

Basic tests pass locally on 3.9.

Begin trying to install on Travis.
parent 99c9620e
......@@ -61,6 +61,7 @@ env:
- TRAVIS_PYTHON_VERSION=3.6
- TRAVIS_PYTHON_VERSION=3.7
- TRAVIS_PYTHON_VERSION=3.8
- TRAVIS_PYTHON_VERSION=3.9
- TRAVIS_PYTHON_VERSION=pypy2.7
- TRAVIS_PYTHON_VERSION=pypy3.6
- TRAVIS_PYTHON_VERSION=2.7 GEVENTSETUP_EMBED=0 GEVENTSETUP_EV_VERIFY=3
......@@ -153,6 +154,8 @@ jobs:
exclude:
- os: osx
env: TRAVIS_PYTHON_VERSION=3.5
- os: osx
env: TRAVIS_PYTHON_VERSION=3.9
- os: osx
env: TRAVIS_PYTHON_VERSION=pypy2.7
- os: osx
......@@ -174,7 +177,7 @@ jobs:
# First, the build dependencies (see setup.cfg)
# so that we don't have to use build isolation and can better use the cache;
# Note that we can't use -U for cffi and greenlet on PyPy.
- &build-gevent-deps pip install -U setuptools wheel twine && pip install -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"' 'cffi;platform_python_implementation=="CPython"' 'cython<3' 'greenlet;platform_python_implementation=="CPython"'
- &build-gevent-deps pip install -U setuptools wheel twine && pip install -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"' 'cffi;platform_python_implementation=="CPython"' 'cython<3' 'greenlet;platform_python_implementation=="CPython" and python_version <= "3.8"' 'git+https://github.com/python-greenlet/greenlet.git#egg=greenlet ; platform_python_implementation == "CPython" and python_version >= "3.9.0b1"'
# Next, build the wheel *in place*. This helps ccache, and also lets us cache the configure
# output (pip install uses a random temporary directory, making this difficult)
- python setup.py bdist_wheel
......@@ -194,6 +197,8 @@ jobs:
env: TRAVIS_PYTHON_VERSION=3.6
- <<: *build-gevent
env: TRAVIS_PYTHON_VERSION=3.7
- <<: *build-gevent
env: TRAVIS_PYTHON_VERSION=3.9
- <<: *build-gevent
env: TRAVIS_PYTHON_VERSION=pypy2.7
- <<: *build-gevent
......@@ -324,18 +329,9 @@ jobs:
# For the CPython interpreters, unless we have reason to expect
# different behaviour across the versions (e.g., as measured by coverage)
# it's sufficient to test the alternate backend library for non-current versions;
# run the full suite on the current version.
# it's sufficient to run the full suite on the current version.
# 3.6
- <<: *test-libuv-jobs
env: TRAVIS_PYTHON_VERSION=3.6
name: libuv36
# 3.7
- <<: *test-libuv-jobs
env: TRAVIS_PYTHON_VERSION=3.7
name: libuv37
# XXX: Move these to 3.9 once the basic tests get worked out.
# 3.8
- <<: *test-libuv-jobs
......
......@@ -20,4 +20,8 @@ zest.releaser[recommended]
# benchmarks use this
pyperf >= 1.6.1
# Python 3.9+ need a version of greenlet that
# is currently unreleased.
git+https://github.com/python-greenlet/greenlet.git#egg=greenlet ; platform_python_implementation == 'CPython' and python_version >= '3.9.0b1'
-e .[test,docs]
Add support for Python 3.9.
No binary wheels are available yet, however.
No binary wheels are available yet, however, and one must use a
greenlet built from current git master.
......@@ -54,12 +54,15 @@ def application(env, start_response):
if env['QUERY_STRING']:
path += '?' + env['QUERY_STRING']
path = path.lstrip('/')
if (method, path) == ('GET', ''):
start_response('200 OK', [('Content-Type', 'text/html')])
return [FORM]
elif method == 'GET':
if method == 'GET':
return proxy(path, start_response, proxy_url)
elif (method, path) == ('POST', ''):
if (method, path) == ('POST', ''):
key, value = env['wsgi.input'].read().strip().split(b'=')
assert key == b'url', repr(key)
value = _as_str(value)
......@@ -75,13 +78,16 @@ def proxy(path, start_response, proxy_url):
# pylint:disable=too-many-locals
if '://' not in path:
path = 'http://' + path
try:
try:
response = urllib2.urlopen(path)
except urllib2.HTTPError as ex:
response = ex
print('%s: %s %s' % (path, response.code, response.msg))
headers = [(k, v) for (k, v) in response.headers.items() if k not in drop_headers]
# Beginning in Python 3.8, headers aren't guaranteed to arrive in
# lowercase; we must do so ourself.
headers = [(k, v) for (k, v) in response.headers.items() if k.lower() not in DROP_HEADERS]
scheme, netloc, path, _params, _query, _fragment = urlparse(path)
host = (scheme or 'http') + '://' + netloc
except Exception as ex: # pylint:disable=broad-except
......@@ -94,6 +100,7 @@ def proxy(path, start_response, proxy_url):
error_str = '<h1>%s</h1><h2>%s</h2><pre>%s</pre>' % (error_str, escape(path), escape(tb))
return [_as_bytes(error_str)]
else:
print("Returning", headers)
start_response('%s %s' % (response.code, response.msg), headers)
data = response.read()
data = fix_links(data, proxy_url, host)
......@@ -110,7 +117,8 @@ def join(url1, *rest):
if url2.startswith(b'/'):
return join(url1 + url2[1:], *rest)
return join(url1 + url2, *rest)
elif url2.startswith(b'/'):
if url2.startswith(b'/'):
return join(url1 + url2, *rest)
return join(url1 + b'/' + url2, *rest)
......@@ -136,7 +144,11 @@ def fix_links(data, proxy_url, host_url):
_link_re_1 = re.compile(br'''(?P<before>(href|src|action)\s*=\s*)(?P<quote>['"])(?P<url>[^#].*?)(?P=quote)''')
_link_re_2 = re.compile(br'''(?P<before>(href|src|action)\s*=\s*)(?P<url>[^'"#>][^ >]*)''')
drop_headers = ['transfer-encoding', 'set-cookie']
# The lowercase names of headers that we will *NOT* forward.
DROP_HEADERS = {
'transfer-encoding',
'set-cookie'
}
FORM = b"""<html><head>
<title>Web Proxy - gevent example</title></head><body>
......
......@@ -22,7 +22,12 @@ requires = [
# See version requirements in setup.py
"cffi >= 1.12.3 ; platform_python_implementation == 'CPython'",
# Python 3.7 requires at least 0.4.14, which is ABI incompatible with earlier
"greenlet>=0.4.14 ; platform_python_implementation == 'CPython'",
# releases. Python 3.9 and 3.10 require 0.4.16, which has not been released yet.
# Listing it here fails to find a distro on PyPI; and this setting won't accept
# git+https:// VCS urls, it seems. If we list it in dev-requirements.txt, we seem to
# get what we need.
"greenlet>=0.4.14 ; platform_python_implementation == 'CPython' and python_version <= '3.8'",
#"greenlet > 0.4.15 ; platform_python_implementation == 'CPython' and python_version >= '3.9.0b1'",
]
[tool.towncrier]
......
......@@ -114,6 +114,9 @@ for var in "$@"; do
3.8)
install 3.8.2 python3.8 3.8.d
;;
3.9)
install 3.9-dev python3.9 3.9.d
;;
pypy2.7)
install pypy2.7-7.3.1 pypy2.7 pypy2.7.d
;;
......
......@@ -433,6 +433,8 @@ def run_setup(ext_modules):
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Operating System :: MacOS :: MacOS X",
......
......@@ -377,6 +377,17 @@ class AbstractLinkable(object):
gotit = self._wait_core(timeout)
return self._wait_return_value(True, gotit)
def _at_fork_reinit(self):
"""
This method was added in Python 3.9 and is called by logging.py
``_after_at_fork_child_reinit_locks`` on Lock objects.
It is also called from threading.py, ``_after_fork`` in
``_reset_internal_locks``, and that can hit ``Event`` objects.
Do we need to do anything?
"""
def _init():
greenlet_init() # pylint:disable=undefined-variable
......
......@@ -18,6 +18,7 @@ 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)
PYPY = hasattr(sys, 'pypy_version_info')
WIN = sys.platform.startswith("win")
LINUX = sys.platform.startswith('linux')
......
......@@ -73,6 +73,7 @@ import time
from gevent._hub_local import get_hub_noargs as get_hub
from gevent._compat import string_types, integer_types, PY3
from gevent._compat import PY38
from gevent._compat import PY39
from gevent._compat import WIN as is_windows
from gevent._compat import OSX as is_macos
from gevent._util import copy_globals
......@@ -83,6 +84,12 @@ if PY38:
'has_dualstack_ipv6',
])
if PY39:
__imports__.extend([
'recv_fds',
'send_fds',
])
# pylint:disable=no-name-in-module,unused-import
if is_windows:
# no such thing as WSAEPERM or error code 10001 according to winsock.h or MSDN
......
......@@ -6,9 +6,6 @@ For the documentation, refer to :mod:`ssl` module manual.
This module implements cooperative SSL socket wrappers.
"""
# Our import magic sadly makes this warning useless
# pylint: disable=undefined-variable
# pylint:disable=no-member
from __future__ import absolute_import
import ssl as __ssl__
......@@ -16,6 +13,8 @@ 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
......@@ -31,12 +30,38 @@ __implements__ = [
'get_server_certificate',
]
# Manually import things we use so we get better linting.
# Also, in the past (adding 3.9 support) it turned out we were
# relying on certain global variables being defined in the ssl module
# that weren't required to be there, e.g., AF_INET, which should be imported
# from socket
from socket import AF_INET
from socket import SOCK_STREAM
from socket import SO_TYPE
from socket import SOL_SOCKET
from ssl import SSLWantReadError
from ssl import SSLWantWriteError
from ssl import CERT_NONE
from ssl import SSLError
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 CHANNEL_BINDING_TYPES
from ssl import CERT_REQUIRED
from ssl import DER_cert_to_PEM_cert
from ssl import create_connection
# Import all symbols from Python's ssl.py, except those that we are implementing
# and "private" symbols.
__imports__ = copy_globals(__ssl__, globals(),
# SSLSocket *must* subclass gevent.socket.socket; see issue 597
names_to_ignore=__implements__ + ['socket'],
dunder_names_to_keep=())
__imports__ = copy_globals(
__ssl__, globals(),
# SSLSocket *must* subclass gevent.socket.socket; see issue 597
names_to_ignore=__implements__ + ['socket'],
dunder_names_to_keep=())
__all__ = __implements__ + __imports__
if 'namedtuple' in __all__:
......@@ -143,7 +168,7 @@ class SSLContext(orig_SSLContext):
__ssl__.SSLContext = orig_SSLContext
try:
super(SSLContext, SSLContext)._msg_callback.__set__(self, value)
super(SSLContext, SSLContext)._msg_callback.__set__(self, value) # pylint:disable=no-member
finally:
__ssl__.SSLContext = SSLContext
......@@ -153,7 +178,7 @@ class SSLContext(orig_SSLContext):
def sni_callback(self):
result = super().sni_callback
if isinstance(result, _Callback):
result = result.user_function
result = result.user_function # pylint:disable=no-member
return result
@sni_callback.setter
def sni_callback(self, value):
......
......@@ -733,19 +733,21 @@ class WSGIHandler(object):
else:
self._sendall(data)
ApplicationError = AssertionError
def write(self, data):
# The write() callable we return from start_response.
# https://www.python.org/dev/peps/pep-3333/#the-write-callable
# Supposed to do pretty much the same thing as yielding values
# from the application's return.
if self.code in (304, 204) and data:
raise AssertionError('The %s response must have no body' % self.code)
raise self.ApplicationError('The %s response must have no body' % self.code)
if self.headers_sent:
self._write(data)
else:
if not self.status:
raise AssertionError("The application did not call start_response()")
raise self.ApplicationError("The application did not call start_response()")
self._write_with_headers(data)
def _write_with_headers(self, data):
......@@ -870,7 +872,7 @@ class WSGIHandler(object):
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')
raise AssertionError(msg)
raise self.ApplicationError(msg)
return self.write
......@@ -1017,7 +1019,7 @@ class WSGIHandler(object):
def handle_error(self, t, v, tb):
# Called for internal, unexpected errors, NOT invalid client input
self._log_error(t, v, tb)
del tb
t = v = tb = None
self._send_error_response_if_possible(500)
def _handle_client_error(self, ex):
......
......@@ -19,7 +19,7 @@
# THE SOFTWARE.
from __future__ import absolute_import, print_function, division
from contextlib import contextmanager
from gevent.hub import Hub
from .exception import ExpectedException
......@@ -29,12 +29,37 @@ class QuietHub(Hub):
_threadpool = None
EXPECTED_TEST_ERROR = (ExpectedException,)
IGNORE_EXPECTED_TEST_ERROR = False
@contextmanager
def ignoring_expected_test_error(self):
"""
Code in the body of this context manager will ignore
``EXPECTED_TEST_ERROR`` objects reported to ``handle_error``;
they will not get a chance to go to the hub's parent.
This completely changes the semantics of normal error handling
by avoiding some switches (to the main greenlet, and eventually
once a callback is processed, back to the hub). This should be used
in narrow ways for test compatibility for tests that assume
``ExpectedException`` objects behave this way.
"""
old = self.IGNORE_EXPECTED_TEST_ERROR
self.IGNORE_EXPECTED_TEST_ERROR = True
try:
yield
finally:
self.IGNORE_EXPECTED_TEST_ERROR = old
def handle_error(self, context, type, value, tb):
type, value, tb = self._normalize_exception(type, value, tb)
# If we check that the ``type`` is a subclass of ``EXPECTED_TEST_ERROR``,
# and return, we completely change the semantics: We avoid raising
# this error in the main greenlet, which cuts out several switches.
# Overall, not good.
if issubclass(type, self.EXPECTED_TEST_ERROR):
# Don't print these to cut down on the noise in the test logs
if self.IGNORE_EXPECTED_TEST_ERROR and issubclass(type, self.EXPECTED_TEST_ERROR):
# Don't pass these up; avoid switches
return
return Hub.handle_error(self, context, type, value, tb)
......
......@@ -91,6 +91,9 @@ class ResultCollector(object):
return self
class FailFast(Exception):
pass
class Runner(object):
TIME_WAIT_REAP = 0.1
......@@ -125,7 +128,11 @@ class Runner(object):
kwargs['quiet'] = self._quiet
result = util.run(cmd, **kwargs)
if not result and self._failfast:
sys.exit(1)
# Under Python 3.9 (maybe older versions?), raising the
# SystemExit here (a background thread belonging to the
# pool) doesn't seem to work well. It gets stuck waiting
# for a lock? The job never shows up as finished.
raise FailFast(cmd)
self.results += result
def _reap(self):
......@@ -141,7 +148,10 @@ class Runner(object):
return len(self._running_jobs)
def _reap_all(self):
while self._reap() > 0:
util.log("Reaping %d jobs", len(self._running_jobs), color="debug")
while self._running_jobs:
if not self._reap():
break
util.sleep(self.TIME_WAIT_REAP)
def _spawn(self, pool, cmd, options):
......
from __future__ import print_function
# This file makes this directory into a runnable package.
# it exists to test 'python -m gevent.monkey monkey_package'
print(__file__)
# Note that the __file__ may differ slightly; starting with
# Python 3.9, directly running it gets an abspath, but
# using ``runpy`` doesn't.
import os.path
print(os.path.abspath(__file__))
print(__name__)
from __future__ import print_function
import socket
import sys
import os.path
if sys.argv[1] == 'patched':
print('gevent' in repr(socket.socket))
else:
assert sys.argv[1] == 'stdlib'
print('gevent' not in repr(socket.socket))
print(__file__)
print(os.path.abspath(__file__))
if sys.version_info[:2] == (2, 7):
# Prior to gevent 1.3, 'python -m gevent.monkey' guaranteed this to be
......
......@@ -14,6 +14,7 @@ def use_import():
return dedent(" text")
if __name__ == '__main__':
print(__file__)
import os.path
print(os.path.abspath(__file__))
print(__name__)
print(use_import())
......@@ -29,13 +29,15 @@ class TestKillWithException(greentest.TestCase):
assert isinstance(g.exception, ExpectedError)
def test_kill_with_exception_after_started(self):
g = gevent.spawn(f)
g.join(0)
g.kill(ExpectedError)
assert not g.successful()
with gevent.get_hub().ignoring_expected_test_error():
g = gevent.spawn(f)
g.join(0)
g.kill(ExpectedError)
self.assertFalse(g.successful())
self.assertRaises(ExpectedError, g.get)
assert g.value is None
assert isinstance(g.exception, ExpectedError)
self.assertIsNone(g.value)
self.assertIsInstance(g.exception, ExpectedError)
if __name__ == '__main__':
......
......@@ -86,12 +86,12 @@ class TestRun(greentest.TestCase):
self._run_package(module=True)
def test_issue_302(self):
lines = self._run(os.path.join('monkey_package', 'issue302monkey.py'))
monkey_lines = self._run(os.path.join('monkey_package', 'issue302monkey.py'))
self.assertEqual(lines[0].strip(), u'True')
lines[1] = lines[1].replace(u'\\', u'/') # windows path
self.assertEqual(lines[1].strip(), u'monkey_package/issue302monkey.py')
self.assertEqual(lines[2].strip(), u'True', lines)
self.assertEqual(monkey_lines[0].strip(), u'True')
monkey_lines[1] = monkey_lines[1].replace(u'\\', u'/') # windows path
self.assertTrue(monkey_lines[1].strip().endswith(u'monkey_package/issue302monkey.py'))
self.assertEqual(monkey_lines[2].strip(), u'True', monkey_lines)
# These three tests all sometimes fail on Py2 on CI, writing
# to stderr:
......
......@@ -47,11 +47,15 @@ from wsgiref.validate import validator
import gevent.testing as greentest
import gevent
from gevent.testing import PY3, PYPY
from gevent.testing.exception import ExpectedException
from gevent import socket
from gevent import pywsgi
from gevent.pywsgi import Input
class ExpectedAssertionError(ExpectedException, AssertionError):
"""An expected assertion error"""
CONTENT_LENGTH = 'Content-Length'
CONN_ABORTED_ERRORS = greentest.CONN_ABORTED_ERRORS
......@@ -90,11 +94,7 @@ def iread_chunks(fd):
while True:
line = fd.readline()
chunk_size = line.strip()
try:
chunk_size = int(chunk_size, 16)
except:
print('Failed to parse chunk size: %r' % line)
raise
chunk_size = int(chunk_size, 16)
if chunk_size == 0:
crlf = fd.read(2)
assert crlf == b'\r\n', repr(crlf)
......@@ -173,21 +173,18 @@ class Response(object):
if isinstance(content_length, int):
content_length = str(content_length)
self.assertHeader('Content-Length', content_length)
try:
if 'chunked' in headers.get('Transfer-Encoding', ''):
if CONTENT_LENGTH in headers:
print("WARNING: server used chunked transfer-encoding despite having Content-Length header (libevent 1.x's bug)")
self.chunks = list(iread_chunks(fd))
self.body = b''.join(self.chunks)
elif CONTENT_LENGTH in headers:
num = int(headers[CONTENT_LENGTH])
self.body = fd.read(num)
else:
self.body = fd.read()
except:
print('Response.read failed to read the body:\n%s' % self)
import traceback; traceback.print_exc()
raise
if 'chunked' in headers.get('Transfer-Encoding', ''):
if CONTENT_LENGTH in headers:
print("WARNING: server used chunked transfer-encoding despite having Content-Length header (libevent 1.x's bug)")
self.chunks = list(iread_chunks(fd))
self.body = b''.join(self.chunks)
elif CONTENT_LENGTH in headers:
num = int(headers[CONTENT_LENGTH])
self.body = fd.read(num)
else:
self.body = fd.read()
if body is not None:
self.assertBody(body)
if chunks is not None:
......@@ -210,15 +207,23 @@ class TestCase(greentest.TestCase):
# So use the hostname.
connect_addr = greentest.DEFAULT_LOCAL_HOST_ADDR
class handler_class(pywsgi.WSGIHandler):
ApplicationError = ExpectedAssertionError
def init_logger(self):
import logging
logger = logging.getLogger('gevent.pywsgi')
logger = logging.getLogger('gevent.tests.pywsgi')
logger.setLevel(logging.CRITICAL)
return logger
def init_server(self, application):
logger = self.logger = self.init_logger()
self.server = pywsgi.WSGIServer((self.listen_addr, 0), application,
log=logger, error_log=logger)
self.server = pywsgi.WSGIServer(
(self.listen_addr, 0),
application,
log=logger, error_log=logger,
handler_class=self.handler_class,
)
def setUp(self):
application = self.application
......@@ -1125,12 +1130,10 @@ class TestBody304(TestCase):
def test_err(self):
with self.makefile() as fd:
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
try:
with self.assertRaises(AssertionError) as exc:
read_http(fd)
except AssertionError as ex:
self.assertEqual(str(ex), 'The 304 response must have no body')
else:
raise AssertionError('AssertionError must be raised')
ex = exc.exception
self.assertEqual(str(ex), 'The 304 response must have no body')
class TestWrite304(TestCase):
......@@ -1142,9 +1145,9 @@ class TestWrite304(TestCase):
self.error_raised = False
try:
write('body')
except AssertionError:
except AssertionError as ex:
self.error_raised = True
raise
raise ExpectedAssertionError(*ex.args)
def test_err(self):
with self.makefile() as fd:
......@@ -1465,7 +1468,8 @@ class TestInvalidEnviron(TestCase):
for key, value in environ.items():
if key in ('CONTENT_LENGTH', 'CONTENT_TYPE') or key.startswith('HTTP_'):
if key != 'HTTP_HOST':
raise AssertionError('Unexpected environment variable: %s=%r' % (key, value))
raise ExpectedAssertionError('Unexpected environment variable: %s=%r' % (
key, value))
start_response('200 OK', [])
return []
......@@ -1493,37 +1497,31 @@ class TestInvalidHeadersDropped(TestCase):
read_http(fd)
class Handler(pywsgi.WSGIHandler):
def read_requestline(self):
data = self.rfile.read(7)
if data[0] == b'<'[0]: # py3: indexing bytes returns ints. sigh.
# Returning nothing stops handle_one_request()
# Note that closing or even deleting self.socket() here
# can lead to the read side throwing Connection Reset By Peer,
# depending on the Python version and OS
data += self.rfile.read(15)
if data.lower() == b'<policy-file-request/>':
self.socket.sendall(b'HELLO')
else:
self.log_error('Invalid request: %r', data)
return None
return data + self.rfile.readline()
class TestHandlerSubclass(TestCase):
validator = None
class handler_class(TestCase.handler_class):
def read_requestline(self):
data = self.rfile.read(7)
if data[0] == b'<'[0]: # py3: indexing bytes returns ints. sigh.
# Returning nothing stops handle_one_request()
# Note that closing or even deleting self.socket() here
# can lead to the read side throwing Connection Reset By Peer,
# depending on the Python version and OS
data += self.rfile.read(15)
if data.lower() == b'<policy-file-request/>':
self.socket.sendall(b'HELLO')
else:
self.log_error('Invalid request: %r', data)
return None
return data + self.rfile.readline()
def application(self, environ, start_response):
start_response('200 OK', [])
return []
def init_server(self, application):
self.server = pywsgi.WSGIServer((self.listen_addr, 0),
application,
handler_class=Handler)
def test(self):
with self.makefile() as fd:
fd.write(b'<policy-file-request/>\x00')
......@@ -1645,14 +1643,12 @@ class TestInputRaw(greentest.BaseTestCase):
def test_32bit_overflow(self):
# https://github.com/gevent/gevent/issues/289
# Should not raise an OverflowError on Python 2
print("BEGIN 32bit")
data = b'asdf\nghij\n'
long_data = b'a' * (pywsgi.MAX_REQUEST_LINE + 10)
long_data += b'\n'
data = data + long_data
partial_data = b'qjk\n' # Note terminating \n
n = 25 * 1000000000
print("N", n, "Data len", len(data))
if hasattr(n, 'bit_length'):
self.assertEqual(n.bit_length(), 35)
if not PY3 and not PYPY:
......
......@@ -381,6 +381,10 @@ class ThreadTests(unittest.TestCase):
# ignored.
# self.assertEqual(stderr, "")
@greentest.skipIf(
not(hasattr(sys, 'getcheckinterval')),
"Needs sys.getcheckinterval"
)
def test_enumerate_after_join(self):
# Try hard to trigger #1703448: a thread is still returned in
# threading.enumerate() after it has been join()ed.
......@@ -388,7 +392,8 @@ class ThreadTests(unittest.TestCase):
import warnings
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
# get/set checkinterval are deprecated in Python 3
# get/set checkinterval are deprecated in Python 3,
# and removed in Python 3.9
old_interval = sys.getcheckinterval()
try:
for i in xrange(1, 100):
......
......@@ -152,7 +152,8 @@ class TestTree(greentest.TestCase):
@greentest.ignores_leakcheck
def test_tree(self):
tree, str_tree, tree_format = self._build_tree()
with gevent.get_hub().ignoring_expected_test_error():
tree, str_tree, tree_format = self._build_tree()
self.assertTrue(tree.root)
......@@ -191,8 +192,8 @@ class TestTree(greentest.TestCase):
@greentest.ignores_leakcheck
def test_tree_no_track(self):
gevent.config.track_greenlet_tree = False
self._build_tree()
with gevent.get_hub().ignoring_expected_test_error():
self._build_tree()
@greentest.ignores_leakcheck
def test_forest_fake_parent(self):
......
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