Skip to content

Commit

Permalink
Merge pull request gevent#1848 from gevent/issue1798
Browse files Browse the repository at this point in the history
Add pypy3.7 to Appveyor.
  • Loading branch information
jamadden authored Dec 14, 2021
2 parents 9338965 + 42fdaec commit b7ba2f4
Show file tree
Hide file tree
Showing 15 changed files with 6,582 additions and 28 deletions.
19 changes: 16 additions & 3 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ environment:
# a later point release.

# 64-bit
- PYTHON: "C:\\pypy3.7-v7.3.7-win64"
PYTHON_ID: "pypy3"
PYTHON_EXE: pypy3w
PYTHON_VERSION: "3.7.x"
PYTHON_ARCH: "64"
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019

- PYTHON: "C:\\pypy2.7-v7.3.6-win64"
PYTHON_ID: "pypy"
PYTHON_EXE: pypy
Expand Down Expand Up @@ -168,6 +175,12 @@ install:
}
7z x -y "${env:PYTMP}\pypy2-v7.3.6-win64.zip" -oC:\ | Out-Null;
}
elseif ("${env:PYTHON_ID}" -eq "pypy3") {
if (!(Test-Path "${env:PYTMP}\pypy3.7-v7.3.7-win64.zip")) {
(New-Object Net.WebClient).DownloadFile("https://downloads.python.org/pypy/pypy3.7-v7.3.7-win64.zip", "${env:PYTMP}\pypy3.7-v7.3.7-win64.zip");
}
7z x -y "${env:PYTMP}\pypy3.7-v7.3.7-win64.zip" -oC:\ | Out-Null;
}
elseif (-not(Test-Path($env:PYTHON))) {
& appveyor\install.ps1;
}
Expand Down Expand Up @@ -198,9 +211,8 @@ cache:

build_script:
# Build the compiled extension
# Try to get some things that don't wind up in the pip cache as
# built wheels if they're built during an isolated build.
- "%CMD_IN_ENV% %PYEXE% -m pip install -U wheel cython setuptools cffi"
- "%CMD_IN_ENV% %PYEXE% -m pip install -U wheel"
- "%CMD_IN_ENV% %PYEXE% -m pip install -U setuptools"
- if not "%GWHEEL_ONLY%"=="true" %PYEXE% -m pip install -U -e .[test]

test_script:
Expand All @@ -209,6 +221,7 @@ test_script:
- if not "%GWHEEL_ONLY%"=="true" %PYEXE% -c "import gevent.core; print(gevent.core.loop)"
- if not "%GWHEEL_ONLY%"=="true" %PYEXE% -c "import gevent; print(gevent.config.settings['resolver'].get_options())"
- if not "%GWHEEL_ONLY%"=="true" %PYEXE% -c "from gevent._compat import get_clock_info; print(get_clock_info('perf_counter'))"
- if not "%GWHEEL_ONLY%"=="true" %PYEXE% -mgevent.tests.known_failures
- if not "%GWHEEL_ONLY%"=="true" %PYEXE% -mgevent.tests --second-chance --config known_failures.py

after_test:
Expand Down
4 changes: 4 additions & 0 deletions docs/changes/1798.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Windows: Test and provide binary wheels for PyPy3.7.

Note that there may be issues with subprocesses, signals, and it may
be slow.
8 changes: 5 additions & 3 deletions docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ library and will install the `cffi`_ library by default on Windows.
The cffi library will become the default on all platforms in a future
release of gevent.

This version of gevent also runs on PyPy 7.0 or above. On PyPy, there
are no external dependencies.
This version of gevent also runs on PyPy 7.3.7 (7.3.6 for PyPy2) or
above. On PyPy, there are no external dependencies.

gevent is tested on Windows, macOS, and Linux, and should run on most
other Unix-like operating systems (e.g., FreeBSD, Solaris, etc.)

.. note::

Windows is supported as a tier 2, "best effort," platform. It is
suitable for development, but not recommended for production.
suitable for development, but not recommended for production. In
particular, PyPy3 on Windows may have issues, especially with
subprocesses.

On Windows using the deprecated libev backend, gevent is
limited to a maximum of 1024 open sockets due to
Expand Down
38 changes: 37 additions & 1 deletion src/gevent/testing/patched_tests_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,15 @@ def get_switch_expected(fullname):
# (unless signal handler raises an error) maybe it should?
'test_signal.WakeupSignalTests.test_wakeup_fd_during',

# these rely on os.read raising EINTR which never happens with gevent.os.read
'test_signal.SiginterruptTest.test_without_siginterrupt',
'test_signal.SiginterruptTest.test_siginterrupt_on',
# these rely on os.read raising EINTR which never happens with gevent.os.read
'test_signal.SiginterruptTest.test_siginterrupt_off',
# This one takes forever and relies on threading details
'test_signal.StressTest.test_stress_modifying_handlers',
# This uses an external file, and launches it. This means that it's not
# actually testing gevent because there's no monkey-patch.
'test_signal.PosixTests.test_interprocess_signal',

'test_subprocess.ProcessTestCase.test_leak_fast_process_del_killed',
'test_subprocess.ProcessTestCase.test_zombie_fast_process_del',
Expand Down Expand Up @@ -680,6 +686,34 @@ def get_switch_expected(fullname):
'test_socket.InheritanceTest.test_SOCK_CLOEXEC',
]

if PYPY3 and WIN:
disabled_tests += [
# test_httpservers.CGIHTTPServerTestCase all seem to hang.
# There seem to be some general subprocess issues. This is
# ignored entirely from known_failures.py

# This produces:
#
# OSError: [Errno 10014] The system detected an invalid
# pointer address in attempting to use a pointer argument in
# a call
#
# When calling socket.socket(fileno=fd) when we actually
# call ``self._socket =self._gevent_sock_class()``.
'test_socket.GeneralModuleTests.test_socket_fileno',

# This doesn't respect the scope properly
#
# self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, ifindex))
# AssertionError: Tuples differ: ('ff02::1de:c0:face:8d%42', 1234, 0, 42) != ('ff02::1de:c0:face:8d', 1234, 0, 42
#
'test_socket.GeneralModuleTests.test_getaddrinfo_ipv6_scopeid_numeric',

# self.assertEqual(newsock.get_inheritable(), False)
# AssertionError: True != False
'test_socket.InheritanceTest.test_dup',
]

def _make_run_with_original(mod_name, func_name):
@contextlib.contextmanager
def with_orig():
Expand Down Expand Up @@ -1412,6 +1446,8 @@ def test(*args, **kwargs):
# We don't currently implement pipesize.
'test_subprocess.ProcessTestCase.test_pipesize_default',
'test_subprocess.ProcessTestCase.test_pipesizes',
# Unknown
'test_signal.SiginterruptTest.test_siginterrupt_off',
]

if TRAVIS:
Expand Down
38 changes: 31 additions & 7 deletions src/gevent/testing/testrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,15 +808,39 @@ def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--ignore')
parser.add_argument('--discover', action='store_true')
parser.add_argument('--full', action='store_true')
parser.add_argument('--config', default='known_failures.py')
parser.add_argument("--coverage", action="store_true")
parser.add_argument("--quiet", action="store_true", default=True)
parser.add_argument(
'--discover', action='store_true',
help="Only print the tests found."
)
parser.add_argument(
'--config', default='known_failures.py',
help="The path to the config file containing "
"FAILING_TESTS, IGNORED_TESTS and RUN_ALONE. "
"Defaults to %(default)s."
)
parser.add_argument(
"--coverage", action="store_true",
help="Enable coverage recording with coverage.py."
)
# TODO: Quiet and verbose should be mutually exclusive
parser.add_argument(
"--quiet", action="store_true", default=True,
help="Be quiet. Defaults to %(default)s. Also the "
"GEVENTTEST_QUIET environment variable."
)
parser.add_argument("--verbose", action="store_false", dest='quiet')
parser.add_argument("--debug", action="store_true", default=False)

parser.add_argument("--package", default="gevent.tests")
parser.add_argument(
"--debug", action="store_true", default=False,
help="Enable debug settings. If the GEVENT_DEBUG environment variable is not set, "
"this sets it to 'debug'. This can also enable PYTHONTRACEMALLOC and the debug PYTHONMALLOC "
"allocators, if not already set. Defaults to %(default)s."
)

parser.add_argument(
"--package", default="gevent.tests",
help="Load tests from the given package. Defaults to %(default)s."
)
parser.add_argument(
"--processes", "-j", default=DEFAULT_NWORKERS, type=int,
help="Use up to the given number of parallel processes to execute tests. "
Expand Down
48 changes: 40 additions & 8 deletions src/gevent/tests/known_failures.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def __init__(self, name):
ConstantCondition.__init__(self, getattr(sysinfo, name), name)

PYPY = _AttrCondition('PYPY')
PYPY3 = _AttrCondition('PYPY3')
PY3 = _AttrCondition('PY3')
PY2 = _AttrCondition('PY2')
OSX = _AttrCondition('OSX')
Expand Down Expand Up @@ -160,12 +161,18 @@ class Multi(object):
def __init__(self):
self._conds = []

def flaky(self, reason='', when=True):
self._conds.append(Flaky(reason, when))
def flaky(self, reason='', when=True, ignore_coverage=NEVER, run_alone=NEVER):
self._conds.append(
Flaky(
reason, when=when,
ignore_coverage=ignore_coverage,
run_alone=run_alone,
)
)
return self

def ignored(self, reason='', when=True):
self._conds.append(Ignored(reason, when))
self._conds.append(Ignored(reason, when=when))
return self

def __set_name__(self, owner, name):
Expand Down Expand Up @@ -279,13 +286,19 @@ class Definitions(DefinitionsBase):

test__backdoor = Flaky(when=LEAKTEST | PYPY)
test__socket_errors = Flaky(when=LEAKTEST)
test_signal = Flaky(
test_signal = Multi().flaky(
"On Travis, this very frequently fails due to timing",
when=TRAVIS & LEAKTEST,
# Partial workaround for the _testcapi issue on PyPy,
# but also because signal delivery can sometimes be slow, and this
# spawn processes of its own
run_alone=APPVEYOR,
).ignored(
"""
This fails to run a single test. It looks like just importing the module
can hang. All I see is the output from patch_all()
""",
when=APPVEYOR & PYPY3
)

test__monkey_sigchld_2 = Ignored(
Expand All @@ -303,10 +316,22 @@ class Definitions(DefinitionsBase):
allocate SSL Context objects, either in Python 2.7 or 3.6.
There must be some library incompatibility. No point even
running them. XXX: Remember to turn this back on.
On Windows, with PyPy3.7 7.3.7, there seem to be all kind of certificate
errors.
""",
when=(PYPY & TRAVIS) | (PYPY3 & WIN)
)

test_httpservers = Ignored(
"""
All the CGI tests hang. There appear to be subprocess problems.
""",
when=PYPY & TRAVIS
when=PYPY3 & WIN
)



test__pywsgi = Ignored(
"""
XXX: Re-enable this when we can investigate more. This has
Expand All @@ -319,16 +344,23 @@ class Definitions(DefinitionsBase):
On Appveyor 3.8.0, for some reason this takes *way* too long, about 100s, which
often goes just over the default timeout of 100s. This makes no sense.
But it also takes nearly that long in 3.7. 3.6 and earlier are much faster.
It also takes just over 100s on PyPy 3.7.
""",
when=(PYPY & TRAVIS & LIBUV) | PY380_EXACTLY,
# https://bitbucket.org/pypy/pypy/issues/2769/systemerror-unexpected-internal-exception
run_alone=(CI & LEAKTEST & PY3) | (PYPY & LIBUV),
# This often takes much longer on PyPy on CI.
options={'timeout': (CI & PYPY, 180)},
)

test_subprocess = Flaky(
test_subprocess = Multi().flaky(
"Unknown, can't reproduce locally; times out one test",
when=PYPY & PY3 & TRAVIS,
ignore_coverage=ALWAYS,
).ignored(
"Tests don't even start before the process times out.",
when=PYPY3 & WIN
)

test__threadpool = Ignored(
Expand Down Expand Up @@ -388,7 +420,7 @@ class Definitions(DefinitionsBase):
off.
""",
when=COVERAGE,
ignore_coverage=ALWAYS
ignore_coverage=ALWAYS,
)

test__hub_join_timeout = Ignored(
Expand Down Expand Up @@ -417,7 +449,7 @@ class Definitions(DefinitionsBase):
"""
On a heavily loaded box, these can all take upwards of 200s.
""",
when=CI & LEAKTEST
when=(CI & LEAKTEST) | (PYPY3 & APPVEYOR)
)

test_socket = RunAlone(
Expand Down
11 changes: 7 additions & 4 deletions src/gevent/tests/test__issues461_471.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ def task():
from gevent.testing.sysinfo import CFFI_BACKEND
from gevent.testing.sysinfo import RUN_COVERAGE
from gevent.testing.sysinfo import WIN
from gevent.testing.sysinfo import PYPY3

class Test(unittest.TestCase):

@unittest.skipIf(CFFI_BACKEND and RUN_COVERAGE,
"Interferes with the timing")
@unittest.skipIf(
(CFFI_BACKEND and RUN_COVERAGE) or (PYPY3 and WIN),
"Interferes with the timing; times out waiting for the child")
def test_hang(self):

# XXX: Why does PyPy3 on Win fail to kill the child? (This was before we switched
# to pypy3w; perhaps that makes a difference?)
if WIN:
from subprocess import CREATE_NEW_PROCESS_GROUP
kwargs = {'creationflags': CREATE_NEW_PROCESS_GROUP}
Expand All @@ -63,7 +66,7 @@ def test_hang(self):
p.send_signal(signal_to_send)
# Wait a few seconds for child process to die. Sometimes signal delivery is delayed
# or even swallowed by Python, so send the signal a few more times if necessary
wait_seconds = 15.0
wait_seconds = 25.0
now = time.time()
midtime = now + (wait_seconds / 2.0)
endtime = time.time() + wait_seconds
Expand Down
5 changes: 5 additions & 0 deletions src/gevent/tests/test__server.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ def send_request_to_fd(self, fd, url='/'):
if greentest.OSX:
# A kernel bug in OS X sometimes results in this
LOCAL_CONN_REFUSED_ERRORS = (errno.EPROTOTYPE,)
elif greentest.WIN and greentest.PYPY3:
# We see WinError 10049: The requested address is not valid
# which is not one of the errors we get anywhere else.
# Not sure which errno constant this is?
LOCAL_CONN_REFUSED_ERRORS = (10049,)

def assertConnectionRefused(self, in_proc_server=True):
try:
Expand Down
12 changes: 10 additions & 2 deletions src/gevent/tests/test__threading_vs_settrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# A deadlock-killer, to prevent the
# testsuite to hang forever
def killer():
time.sleep(0.1)
time.sleep(0.2)
sys.stdout.write('..program blocked; aborting!')
sys.stdout.flush()
os._exit(2)
Expand Down Expand Up @@ -137,7 +137,15 @@ def trace(frame, ev, _arg):
self.assertTrue(isinstance(e, LoopExit))

def run_script(self, more_args=()):
args = [sys.executable, "-c", script]
if (
greentest.PYPY3
and greentest.RUNNING_ON_APPVEYOR
and sys.version_info[:2] == (3, 7)
):
# Somehow launching the subprocess fails with exit code 1, and
# produces no output. It's not clear why.
self.skipTest("Known to hang on AppVeyor")
args = [sys.executable, "-u", "-c", script]
args.extend(more_args)
rc = subprocess.call(args)
self.assertNotEqual(rc, 2, "interpreter was blocked")
Expand Down
Loading

0 comments on commit b7ba2f4

Please sign in to comment.