]>
Commit | Line | Data |
---|---|---|
5a03dc88 JB |
1 | Based on https://github.com/gevent/gevent/commit/8224e81425762ad21d3b63ffb9cc0a0c2d789704.patch |
2 | and https://src.fedoraproject.org/rpms/python-gevent/raw/master/f/0001-code-replace.patch | |
3 | ||
4 | From e6e2959184909c6292e0135b709282cd5f96065b Mon Sep 17 00:00:00 2001 | |
5 | From: Jason Madden <jamadden@gmail.com> | |
6 | Date: Fri, 6 Sep 2019 16:29:58 -0500 | |
7 | Subject: [PATCH 1/9] Basic support for CPython 3.8.0b4. | |
8 | ||
9 | Still needs the specific networking test classes added, but all the basics pass for me. Lets see about CI. | |
10 | --- | |
11 | .travis.yml | 11 +++++++ | |
12 | CHANGES.rst | 4 +++ | |
13 | examples/webproxy.py | 7 +++- | |
14 | pyproject.toml | 5 +-- | |
15 | scripts/install.sh | 3 ++ | |
16 | src/gevent/__semaphore.pxd | 2 +- | |
17 | src/gevent/_compat.py | 2 +- | |
18 | src/gevent/_socket2.py | 1 + | |
19 | src/gevent/_socketcommon.py | 12 +++++-- | |
20 | src/gevent/monkey.py | 46 +++++++++++++++++++++++++-- | |
21 | src/gevent/os.py | 29 ++++++++++++++--- | |
22 | src/gevent/subprocess.py | 32 +++++++++++++++++++ | |
23 | src/gevent/testing/testrunner.py | 17 +++++++--- | |
24 | src/gevent/tests/test__core_fork.py | 7 ++-- | |
25 | src/gevent/tests/test__threading_2.py | 26 +++++++++------ | |
26 | src/gevent/thread.py | 6 ++++ | |
27 | src/gevent/threading.py | 46 ++++++++++----------------- | |
28 | 17 files changed, 196 insertions(+), 60 deletions(-) | |
29 | ||
30 | #diff --git a/.travis.yml b/.travis.yml | |
31 | #index bf307df95..05dc24b12 100644 | |
32 | #--- a/.travis.yml | |
33 | #+++ b/.travis.yml | |
34 | #@@ -42,6 +42,7 @@ env: | |
35 | # - TRAVIS_PYTHON_VERSION=3.5 | |
36 | # - TRAVIS_PYTHON_VERSION=3.6 | |
37 | # - TRAVIS_PYTHON_VERSION=3.7 | |
38 | #+ - TRAVIS_PYTHON_VERSION=3.8 | |
39 | # - TRAVIS_PYTHON_VERSION=pypy2.7 | |
40 | # - TRAVIS_PYTHON_VERSION=pypy3.6 | |
41 | # - TRAVIS_PYTHON_VERSION=2.7 GEVENTSETUP_EMBED=0 | |
42 | #@@ -144,6 +145,8 @@ jobs: | |
43 | # script: ccache -s | |
44 | # before_script: true | |
45 | # after_success: true | |
46 | #+ - <<: *build-gevent | |
47 | #+ env: TRAVIS_PYTHON_VERSION=3.8 | |
48 | # - <<: *build-gevent | |
49 | # env: TRAVIS_PYTHON_VERSION=3.5 | |
50 | # - <<: *build-gevent | |
51 | #@@ -278,6 +281,14 @@ jobs: | |
52 | # env: TRAVIS_PYTHON_VERSION=3.7 | |
53 | # name: pure37 | |
54 | # | |
55 | #+ # 3.8 | |
56 | #+ - <<: *test-libuv-jobs | |
57 | #+ env: TRAVIS_PYTHON_VERSION=3.8 | |
58 | #+ name: libuv36 | |
59 | #+ - <<: *test-libev-jobs | |
60 | #+ env: TRAVIS_PYTHON_VERSION=3.8 | |
61 | #+ name: libev-cffi36 | |
62 | #+ | |
63 | # | |
64 | # # 2.7, no-embed. Run the tests that exercise the libraries we | |
65 | # # linked to. | |
66 | #diff --git a/CHANGES.rst b/CHANGES.rst | |
67 | #index 52b5e1c6f..53f4398d2 100644 | |
68 | #--- a/CHANGES.rst | |
69 | #+++ b/CHANGES.rst | |
70 | #@@ -12,6 +12,10 @@ | |
71 | # - Add an ``--module`` option to ``gevent.monkey`` allowing to run a Python | |
72 | # module rather than a script. See :pr:`1440`. | |
73 | # | |
74 | #+- Add support for CPython 3.8.0b4. | |
75 | #+ | |
76 | #+- Improve the way joining the main thread works on Python 3. | |
77 | #+ | |
78 | # 1.5a1 (2019-05-02) | |
79 | # ================== | |
80 | # | |
81 | diff --git a/examples/webproxy.py b/examples/webproxy.py | |
82 | index e381d6bd4..de1eaf8d5 100755 | |
83 | --- a/examples/webproxy.py | |
84 | +++ b/examples/webproxy.py | |
85 | @@ -15,7 +15,12 @@ | |
86 | import sys | |
87 | import re | |
88 | import traceback | |
89 | -from cgi import escape | |
90 | + | |
91 | +try: | |
92 | + from cgi import escape | |
93 | +except ImportError: | |
94 | + # Python 3.8 removed this API | |
95 | + from html import escape | |
96 | ||
97 | try: | |
98 | import urllib2 | |
99 | #diff --git a/pyproject.toml b/pyproject.toml | |
100 | #index 2b611b9a4..f611ef972 100644 | |
101 | #--- a/pyproject.toml | |
102 | #+++ b/pyproject.toml | |
103 | #@@ -12,8 +12,9 @@ requires = [ | |
104 | # # 0.28 is faster, and (important!) lets us specify the target module | |
105 | # # name to be created so that we can have both foo.py and _foo.so | |
106 | # # at the same time. 0.29 fixes some issues with Python 3.7, | |
107 | #- # and adds the 3str mode for transition to Python 3. | |
108 | #- "Cython >= 0.29.7", | |
109 | #+ # and adds the 3str mode for transition to Python 3. 0.29.12+ is | |
110 | #+ # required for Python 3.8 | |
111 | #+ "Cython >= 0.29.13", | |
112 | # # See version requirements in setup.py | |
113 | # "cffi >= 1.12.3 ; platform_python_implementation == 'CPython'", | |
114 | # # Python 3.7 requires at least 0.4.14, which is ABI incompatible with earlier | |
115 | #diff --git a/scripts/install.sh b/scripts/install.sh | |
116 | #index 94bd53058..ef8a6dfbd 100755 | |
117 | #--- a/scripts/install.sh | |
118 | #+++ b/scripts/install.sh | |
119 | #@@ -99,6 +99,9 @@ for var in "$@"; do | |
120 | # 3.7) | |
121 | # install 3.7.2 python3.7 3.7.d | |
122 | # ;; | |
123 | #+ 3.8) | |
124 | #+ install 3.8.0b4 python3.8 3.8.d | |
125 | #+ ;; | |
126 | # pypy2.7) | |
127 | # install pypy2.7-7.1.0 pypy2.7 pypy2.7.d | |
128 | # ;; | |
129 | diff --git a/src/gevent/__semaphore.pxd b/src/gevent/__semaphore.pxd | |
130 | index dc9f11c68..e46778ed7 100644 | |
131 | --- a/src/gevent/__semaphore.pxd | |
132 | +++ b/src/gevent/__semaphore.pxd | |
133 | @@ -13,7 +13,7 @@ cdef class Semaphore(AbstractLinkable): | |
134 | # threadpool uses it | |
135 | cpdef _start_notify(self) | |
136 | cpdef int wait(self, object timeout=*) except -1000 | |
137 | - cpdef bint acquire(self, int blocking=*, object timeout=*) except -1000 | |
138 | + cpdef bint acquire(self, bint blocking=*, object timeout=*) except -1000 | |
139 | cpdef __enter__(self) | |
140 | cpdef __exit__(self, object t, object v, object tb) | |
141 | ||
142 | diff --git a/src/gevent/_compat.py b/src/gevent/_compat.py | |
143 | index 56391459e..e8f5ed4ba 100644 | |
144 | --- a/src/gevent/_compat.py | |
145 | +++ b/src/gevent/_compat.py | |
146 | @@ -21,7 +21,7 @@ | |
147 | PYPY = hasattr(sys, 'pypy_version_info') | |
148 | WIN = sys.platform.startswith("win") | |
149 | LINUX = sys.platform.startswith('linux') | |
150 | -OSX = sys.platform == 'darwin' | |
151 | +OSX = MAC = sys.platform == 'darwin' | |
152 | ||
153 | ||
154 | PURE_PYTHON = PYPY or os.getenv('PURE_PYTHON') | |
155 | diff --git a/src/gevent/_socket2.py b/src/gevent/_socket2.py | |
156 | index 15f470893..7c2f35f3e 100644 | |
157 | --- a/src/gevent/_socket2.py | |
158 | +++ b/src/gevent/_socket2.py | |
159 | @@ -6,6 +6,7 @@ | |
160 | ||
161 | # Our import magic sadly makes this warning useless | |
162 | # pylint: disable=undefined-variable | |
163 | +import sys | |
164 | ||
165 | from gevent import _socketcommon | |
166 | from gevent._util import copy_globals | |
167 | #diff --git a/src/gevent/_socketcommon.py b/src/gevent/_socketcommon.py | |
168 | #index cd12ac1a9..87b9a4f8a 100644 | |
169 | #--- a/src/gevent/_socketcommon.py | |
170 | #+++ b/src/gevent/_socketcommon.py | |
171 | #@@ -69,13 +69,19 @@ | |
172 | # __imports__.extend(__py3_imports__) | |
173 | # | |
174 | # import time | |
175 | #-import sys | |
176 | #+ | |
177 | # from gevent._hub_local import get_hub_noargs as get_hub | |
178 | # from gevent._compat import string_types, integer_types, PY3 | |
179 | #+from gevent._compat import PY38 | |
180 | #+from gevent._compat import WIN as is_windows | |
181 | #+from gevent._compat import OSX as is_macos | |
182 | # from gevent._util import copy_globals | |
183 | # | |
184 | #-is_windows = sys.platform == 'win32' | |
185 | #-is_macos = sys.platform == 'darwin' | |
186 | #+if PY38: | |
187 | #+ __imports__.extend([ | |
188 | #+ 'create_server', | |
189 | #+ 'has_dualstack_ipv6', | |
190 | #+ ]) | |
191 | # | |
192 | # # pylint:disable=no-name-in-module,unused-import | |
193 | # if is_windows: | |
194 | diff --git a/src/gevent/monkey.py b/src/gevent/monkey.py | |
195 | index 5dbfe3f78..f862f879c 100644 | |
196 | --- a/src/gevent/monkey.py | |
197 | +++ b/src/gevent/monkey.py | |
198 | @@ -668,6 +668,22 @@ def join(timeout=None): | |
199 | raise RuntimeError("Cannot join current thread") | |
200 | if thread_greenlet is not None and thread_greenlet.dead: | |
201 | return | |
202 | + # You may ask: Why not call thread_greenlet.join()? | |
203 | + # Well, in the one case we actually have a greenlet, it's the | |
204 | + # low-level greenlet.greenlet object for the main thread, which | |
205 | + # doesn't have a join method. | |
206 | + # | |
207 | + # You may ask: Why not become the main greenlet's *parent* | |
208 | + # so you can get notified when it finishes? Because you can't | |
209 | + # create a greenlet cycle (the current greenlet is a descendent | |
210 | + # of the parent), and nor can you set a greenlet's parent to None, | |
211 | + # so there can only ever be one greenlet with a parent of None: the main | |
212 | + # greenlet, the one we need to watch. | |
213 | + # | |
214 | + # You may ask: why not swizzle out the problematic lock on the main thread | |
215 | + # into a gevent friendly lock? Well, the interpreter actually depends on that | |
216 | + # for the main thread in threading._shutdown; see below. | |
217 | + | |
218 | if not thread.is_alive(): | |
219 | return | |
220 | ||
221 | @@ -700,8 +716,34 @@ def join(timeout=None): | |
222 | if orig_current_thread == threading_mod.main_thread(): | |
223 | main_thread = threading_mod.main_thread() | |
224 | _greenlet = main_thread._greenlet = greenlet.getcurrent() | |
225 | - | |
226 | - main_thread.join = make_join_func(main_thread, _greenlet) | |
227 | + main_thread.__real_tstate_lock = main_thread._tstate_lock | |
228 | + | |
229 | + # The interpreter will call threading._shutdown | |
230 | + # when the main thread exits and is about to | |
231 | + # go away. It is called *in* the main thread. This | |
232 | + # is a perfect place to notify other greenlets that | |
233 | + # the main thread is done. We do this by overriding the | |
234 | + # lock of the main thread during operation, and only restoring | |
235 | + # it to the native blocking version at shutdown time | |
236 | + # (the interpreter also has a reference to this lock in a | |
237 | + # C data structure). | |
238 | + main_thread._tstate_lock = threading_mod.Lock() | |
239 | + main_thread._tstate_lock.acquire() | |
240 | + orig_shutdown = threading_mod._shutdown | |
241 | + def _shutdown(): | |
242 | + # Release anyone trying to join() me, | |
243 | + # and let us switch to them. | |
244 | + if main_thread._tstate_lock: | |
245 | + main_thread._tstate_lock.release() | |
246 | + from gevent import sleep | |
247 | + sleep() | |
248 | + # The only truly blocking native shutdown lock to | |
249 | + # acquire should be our own (hopefully) | |
250 | + main_thread._tstate_lock = main_thread.__real_tstate_lock | |
251 | + main_thread.__real_tstate_lock = None | |
252 | + orig_shutdown() | |
253 | + | |
254 | + threading_mod._shutdown = _shutdown | |
255 | ||
256 | # Patch up the ident of the main thread to match. This | |
257 | # matters if threading was imported before monkey-patching | |
258 | diff --git a/src/gevent/os.py b/src/gevent/os.py | |
259 | index 3980f320c..4dd66abd8 100644 | |
260 | --- a/src/gevent/os.py | |
261 | +++ b/src/gevent/os.py | |
262 | @@ -385,6 +385,12 @@ def waitpid(pid, options): | |
263 | # we're not watching it | |
264 | return _waitpid(pid, options) | |
265 | ||
266 | + def _watch_child(pid, callback=None, loop=None, ref=False): | |
267 | + loop = loop or get_hub().loop | |
268 | + watcher = loop.child(pid, ref=ref) | |
269 | + _watched_children[pid] = watcher | |
270 | + watcher.start(_on_child, watcher, callback) | |
271 | + | |
272 | def fork_and_watch(callback=None, loop=None, ref=False, fork=fork_gevent): | |
273 | """ | |
274 | Fork a child process and start a child watcher for it in the parent process. | |
275 | @@ -413,10 +419,7 @@ def fork_and_watch(callback=None, loop=None, ref=False, fork=fork_gevent): | |
276 | pid = fork() | |
277 | if pid: | |
278 | # parent | |
279 | - loop = loop or get_hub().loop | |
280 | - watcher = loop.child(pid, ref=ref) | |
281 | - _watched_children[pid] = watcher | |
282 | - watcher.start(_on_child, watcher, callback) | |
283 | + _watch_child(pid, callback, loop, ref) | |
284 | return pid | |
285 | ||
286 | __extensions__.append('fork_and_watch') | |
287 | @@ -474,6 +477,23 @@ def forkpty(*args, **kwargs): | |
288 | # take any args to match fork_and_watch | |
289 | return forkpty_and_watch(*args, **kwargs) | |
290 | __implements__.append("waitpid") | |
291 | + | |
292 | + if hasattr(os, 'posix_spawn'): | |
293 | + _raw_posix_spawn = os.posix_spawn | |
294 | + _raw_posix_spawnp = os.posix_spawnp | |
295 | + | |
296 | + def posix_spawn(*args, **kwargs): | |
297 | + pid = _raw_posix_spawn(*args, **kwargs) | |
298 | + _watch_child(pid) | |
299 | + return pid | |
300 | + | |
301 | + def posix_spawnp(*args, **kwargs): | |
302 | + pid = _raw_posix_spawnp(*args, **kwargs) | |
303 | + _watch_child(pid) | |
304 | + return pid | |
305 | + | |
306 | + __implements__.append("posix_spawn") | |
307 | + __implements__.append("posix_spawnp") | |
308 | else: | |
309 | def fork(): | |
310 | """ | |
311 | @@ -503,6 +523,7 @@ def forkpty(): | |
312 | else: | |
313 | __implements__.remove('fork') | |
314 | ||
315 | + | |
316 | __imports__ = copy_globals(os, globals(), | |
317 | names_to_ignore=__implements__ + __extensions__, | |
318 | dunder_names_to_keep=()) | |
319 | #diff --git a/src/gevent/subprocess.py b/src/gevent/subprocess.py | |
320 | #index a9894f1ab..9b4d13cd2 100644 | |
321 | #--- a/src/gevent/subprocess.py | |
322 | #+++ b/src/gevent/subprocess.py | |
323 | #@@ -47,6 +47,7 @@ | |
324 | # from gevent._compat import PY35 | |
325 | # from gevent._compat import PY36 | |
326 | # from gevent._compat import PY37 | |
327 | #+from gevent._compat import PY38 | |
328 | # from gevent._compat import reraise | |
329 | # from gevent._compat import fspath | |
330 | # from gevent._compat import fsencode | |
331 | #@@ -69,6 +70,25 @@ | |
332 | # __implements__.append("_posixsubprocess") | |
333 | # _posixsubprocess = None | |
334 | # | |
335 | #+if PY38: | |
336 | #+ # Using os.posix_spawn() to start subprocesses | |
337 | #+ # bypasses our child watchers on certain operating systems, | |
338 | #+ # and with certain library versions. Possibly the right | |
339 | #+ # fix is to monkey-patch os.posix_spawn like we do os.fork? | |
340 | #+ # These have no effect, they're just here to match the stdlib. | |
341 | #+ # TODO: When available, given a monkey patch on them, I think | |
342 | #+ # we ought to be able to use them if the stdlib has identified them | |
343 | #+ # as suitable. | |
344 | #+ __implements__.extend([ | |
345 | #+ '_use_posix_spawn', | |
346 | #+ '_USE_POSIX_SPAWN' | |
347 | #+ ]) | |
348 | #+ | |
349 | #+ def _use_posix_spawn(): | |
350 | #+ return False | |
351 | #+ | |
352 | #+ _USE_POSIX_SPAWN = False | |
353 | #+ | |
354 | # # Some symbols we define that we expect to export; | |
355 | # # useful for static analysis | |
356 | # PIPE = "PIPE should be imported" | |
357 | #@@ -1720,3 +1740,15 @@ def run(*popenargs, **kwargs): | |
358 | # raise _with_stdout_stderr(CalledProcessError(retcode, process.args, stdout), stderr) | |
359 | # | |
360 | # return CompletedProcess(process.args, retcode, stdout, stderr) | |
361 | #+ | |
362 | #+def _gevent_did_monkey_patch(*_args): | |
363 | #+ # Beginning on 3.8 on Mac, the 'spawn' method became the default | |
364 | #+ # start method. That doesn't fire fork watchers and we can't | |
365 | #+ # easily patch to make it do so: multiprocessing uses the private | |
366 | #+ # c accelerated _subprocess module to implement this. Instead we revert | |
367 | #+ # back to using fork. | |
368 | #+ from gevent._compat import MAC | |
369 | #+ if MAC: | |
370 | #+ import multiprocessing | |
371 | #+ if hasattr(multiprocessing, 'set_start_method'): | |
372 | #+ multiprocessing.set_start_method('fork', force=True) | |
373 | diff --git a/src/gevent/testing/testrunner.py b/src/gevent/testing/testrunner.py | |
374 | index 3c1c711f8..7a3f8c6bb 100644 | |
375 | --- a/src/gevent/testing/testrunner.py | |
376 | +++ b/src/gevent/testing/testrunner.py | |
377 | @@ -480,17 +480,26 @@ def _setup_environ(debug=False): | |
378 | if 'GEVENT_DEBUG' not in os.environ and debug: | |
379 | os.environ['GEVENT_DEBUG'] = 'debug' | |
380 | ||
381 | - if 'PYTHONTRACEMALLOC' not in os.environ: | |
382 | + if 'PYTHONTRACEMALLOC' not in os.environ and debug: | |
383 | + # This slows the tests down quite a bit. Reserve | |
384 | + # for debugging. | |
385 | os.environ['PYTHONTRACEMALLOC'] = '10' | |
386 | ||
387 | if 'PYTHONDEVMODE' not in os.environ: | |
388 | - # Python 3.7 | |
389 | + # Python 3.7 and above. | |
390 | os.environ['PYTHONDEVMODE'] = '1' | |
391 | ||
392 | - if 'PYTHONMALLOC' not in os.environ: | |
393 | - # Python 3.6 | |
394 | + if 'PYTHONMALLOC' not in os.environ and debug: | |
395 | + # Python 3.6 and above. | |
396 | + # This slows the tests down some, but | |
397 | + # can detect memory corruption. Unfortunately | |
398 | + # it can also be flaky, especially in pre-release | |
399 | + # versions of Python (e.g., lots of crashes on Python 3.8b4). | |
400 | os.environ['PYTHONMALLOC'] = 'debug' | |
401 | ||
402 | + if sys.version_info.releaselevel != 'final' and not debug: | |
403 | + os.environ['PYTHONMALLOC'] = 'default' | |
404 | + os.environ['PYTHONDEVMODE'] = '' | |
405 | ||
406 | ||
407 | def main(): | |
408 | diff --git a/src/gevent/tests/test__core_fork.py b/src/gevent/tests/test__core_fork.py | |
409 | index fee42f547..5717cf7d9 100644 | |
410 | --- a/src/gevent/tests/test__core_fork.py | |
411 | +++ b/src/gevent/tests/test__core_fork.py | |
412 | @@ -1,11 +1,13 @@ | |
413 | from __future__ import print_function | |
414 | import gevent.monkey | |
415 | gevent.monkey.patch_all() | |
416 | -import gevent | |
417 | -import os | |
418 | ||
419 | +import os | |
420 | import multiprocessing | |
421 | ||
422 | +import gevent | |
423 | +from gevent._compat import MAC | |
424 | + | |
425 | hub = gevent.get_hub() | |
426 | pid = os.getpid() | |
427 | newpid = None | |
428 | @@ -46,6 +48,7 @@ def test(): | |
429 | if __name__ == '__main__': | |
430 | # Must call for Windows to fork properly; the fork can't be in the top-level | |
431 | multiprocessing.freeze_support() | |
432 | + | |
433 | # fork watchers weren't firing in multi-threading processes. | |
434 | # This test is designed to prove that they are. | |
435 | # However, it fails on Windows: The fork watcher never runs! | |
436 | diff --git a/src/gevent/tests/test__threading_2.py b/src/gevent/tests/test__threading_2.py | |
437 | index b425c88a3..cb7f8b91e 100644 | |
438 | --- a/src/gevent/tests/test__threading_2.py | |
439 | +++ b/src/gevent/tests/test__threading_2.py | |
440 | @@ -33,6 +33,7 @@ | |
441 | from test.support import verbose | |
442 | except ImportError: | |
443 | from test.test_support import verbose | |
444 | + | |
445 | import random | |
446 | import re | |
447 | import sys | |
448 | @@ -46,7 +47,7 @@ | |
449 | import weakref | |
450 | ||
451 | from gevent.tests import lock_tests | |
452 | - | |
453 | +verbose = False | |
454 | # A trivial mutable counter. | |
455 | ||
456 | def skipDueToHang(cls): | |
457 | @@ -132,7 +133,7 @@ def test_various_ops(self): | |
458 | print('waiting for all tasks to complete') | |
459 | for t in threads: | |
460 | t.join(NUMTASKS) | |
461 | - self.assertFalse(t.is_alive()) | |
462 | + self.assertFalse(t.is_alive(), t.__dict__) | |
463 | if hasattr(t, 'ident'): | |
464 | self.assertNotEqual(t.ident, 0) | |
465 | self.assertFalse(t.ident is None) | |
466 | @@ -351,28 +352,33 @@ def test_join_nondaemon_on_shutdown(self): | |
467 | # Issue 1722344 | |
468 | # Raising SystemExit skipped threading._shutdown | |
469 | import subprocess | |
470 | - p = subprocess.Popen([sys.executable, "-W", "ignore", "-c", """if 1: | |
471 | + script = """if 1: | |
472 | %s | |
473 | import threading | |
474 | from time import sleep | |
475 | ||
476 | def child(): | |
477 | - sleep(1) | |
478 | + sleep(0.3) | |
479 | # As a non-daemon thread we SHOULD wake up and nothing | |
480 | # should be torn down yet | |
481 | - print("Woke up, sleep function is: %%r" %% sleep) | |
482 | + print("Woke up, sleep function is: %%s.%%s" %% (sleep.__module__, sleep.__name__)) | |
483 | ||
484 | threading.Thread(target=child).start() | |
485 | raise SystemExit | |
486 | - """ % setup_4], | |
487 | + """ % setup_4 | |
488 | + p = subprocess.Popen([sys.executable, "-W", "ignore", "-c", script], | |
489 | stdout=subprocess.PIPE, | |
490 | stderr=subprocess.PIPE) | |
491 | stdout, stderr = p.communicate() | |
492 | stdout = stdout.strip() | |
493 | stdout = stdout.decode('utf-8') | |
494 | stderr = stderr.decode('utf-8') | |
495 | - assert re.match('^Woke up, sleep function is: <.*?sleep.*?>$', stdout), repr(stdout) | |
496 | - stderr = re.sub(r"^\[\d+ refs\]", "", stderr, re.MULTILINE).strip() | |
497 | + | |
498 | + | |
499 | + self.assertEqual( | |
500 | + 'Woke up, sleep function is: gevent.hub.sleep', | |
501 | + stdout) | |
502 | + | |
503 | # On Python 2, importing pkg_resources tends to result in some 'ImportWarning' | |
504 | # being printed to stderr about packages missing __init__.py; the -W ignore is... | |
505 | # ignored. | |
506 | @@ -410,7 +416,7 @@ def __init__(self, should_raise): | |
507 | self.should_raise = should_raise | |
508 | self.thread = threading.Thread(target=self._run, | |
509 | args=(self,), | |
510 | - kwargs={'yet_another': self}) | |
511 | + kwargs={'_yet_another': self}) | |
512 | self.thread.start() | |
513 | ||
514 | def _run(self, _other_ref, _yet_another): | |
515 | @@ -463,7 +469,7 @@ def test_1_join_on_shutdown(self): | |
516 | t = threading.Thread(target=joiningfunc, | |
517 | args=(threading.current_thread(),)) | |
518 | t.start() | |
519 | - time.sleep(0.1) | |
520 | + time.sleep(0.2) | |
521 | print('end of main') | |
522 | """ | |
523 | self._run_and_join(script) | |
524 | #diff --git a/src/gevent/thread.py b/src/gevent/thread.py | |
525 | #index a1fe41813..14428df3f 100644 | |
526 | #--- a/src/gevent/thread.py | |
527 | #+++ b/src/gevent/thread.py | |
528 | #@@ -41,6 +41,12 @@ | |
529 | # 'interrupt_main', | |
530 | # 'start_new' | |
531 | # ] | |
532 | #+ if sys.version_info[:2] >= (3, 8): | |
533 | #+ # We can't actually produce a value that "may be used | |
534 | #+ # to identify this particular thread system-wide", right? | |
535 | #+ # Even if we could, I imagine people will want to pass this to | |
536 | #+ # non-Python (native) APIs, so we shouldn't mess with it. | |
537 | #+ __imports__.append('get_native_id') | |
538 | # | |
539 | # | |
540 | # error = __thread__.error | |
541 | diff --git a/src/gevent/threading.py b/src/gevent/threading.py | |
542 | index c845fd221..64d989584 100644 | |
543 | --- a/src/gevent/threading.py | |
544 | +++ b/src/gevent/threading.py | |
545 | @@ -160,41 +160,25 @@ def main_native_thread(): | |
546 | if PY3: | |
547 | # XXX: Issue 18808 breaks us on Python 3.4+. | |
548 | # Thread objects now expect a callback from the interpreter itself | |
549 | - # (threadmodule.c:release_sentinel). Because this never happens | |
550 | + # (threadmodule.c:release_sentinel) when the C-level PyThreadState | |
551 | + # object is being deallocated. Because this never happens | |
552 | # when a greenlet exits, join() and friends will block forever. | |
553 | - # The solution below involves capturing the greenlet when it is | |
554 | - # started and deferring the known broken methods to it. | |
555 | + # Fortunately this is easy to fix: just ensure that the allocation of the | |
556 | + # lock, _set_sentinel, creates a *gevent* lock, and release it when | |
557 | + # we're done. The main _shutdown code is in Python and deals with | |
558 | + # this gracefully. | |
559 | ||
560 | class Thread(__threading__.Thread): | |
561 | - _greenlet = None | |
562 | - | |
563 | - def is_alive(self): | |
564 | - return bool(self._greenlet) | |
565 | - | |
566 | - isAlive = is_alive | |
567 | ||
568 | def _set_tstate_lock(self): | |
569 | - self._greenlet = getcurrent() | |
570 | - | |
571 | - def run(self): | |
572 | - try: | |
573 | - super(Thread, self).run() | |
574 | - finally: | |
575 | - # avoid ref cycles, but keep in __dict__ so we can | |
576 | - # distinguish the started/never-started case | |
577 | - self._greenlet = None | |
578 | - self._stop() # mark as finished | |
579 | - | |
580 | - def join(self, timeout=None): | |
581 | - if '_greenlet' not in self.__dict__: | |
582 | - raise RuntimeError("Cannot join an inactive thread") | |
583 | - if self._greenlet is None: | |
584 | - return | |
585 | - self._greenlet.join(timeout=timeout) | |
586 | - | |
587 | - def _wait_for_tstate_lock(self, *args, **kwargs): | |
588 | - # pylint:disable=arguments-differ | |
589 | - raise NotImplementedError() | |
590 | + super(Thread, self)._set_tstate_lock() | |
591 | + greenlet = getcurrent() | |
592 | + greenlet.rawlink(self.__greenlet_finished) | |
593 | + | |
594 | + def __greenlet_finished(self, _): | |
595 | + if self._tstate_lock: | |
596 | + self._tstate_lock.release() | |
597 | + self._stop() | |
598 | ||
599 | __implements__.append('Thread') | |
600 | ||
601 | @@ -203,6 +187,8 @@ class Timer(Thread, __threading__.Timer): # pylint:disable=abstract-method,inher | |
602 | ||
603 | __implements__.append('Timer') | |
604 | ||
605 | + _set_sentinel = allocate_lock | |
606 | + __implements__.append('_set_sentinel') | |
607 | # The main thread is patched up with more care | |
608 | # in _gevent_will_monkey_patch | |
609 | ||
610 | ||
611 | From 632d3c9990f7db27f76245895bb4c2717818c5d5 Mon Sep 17 00:00:00 2001 | |
612 | From: Jason Madden <jamadden@gmail.com> | |
613 | Date: Fri, 6 Sep 2019 18:26:42 -0500 | |
614 | Subject: [PATCH 2/9] Add the 3.8 test cases. | |
615 | ||
616 | --- | |
617 | src/gevent/_ssl3.py | 14 + | |
618 | src/gevent/monkey.py | 37 +- | |
619 | src/gevent/testing/patched_tests_setup.py | 36 +- | |
620 | src/gevent/testing/sysinfo.py | 3 + | |
621 | src/greentest/3.8/allsans.pem | 81 + | |
622 | src/greentest/3.8/badcert.pem | 36 + | |
623 | src/greentest/3.8/badkey.pem | 40 + | |
624 | src/greentest/3.8/capath/4e1295a3.0 | 14 + | |
625 | src/greentest/3.8/capath/5ed36f99.0 | 41 + | |
626 | src/greentest/3.8/capath/6e88d7b8.0 | 14 + | |
627 | src/greentest/3.8/capath/99d0fa06.0 | 41 + | |
628 | src/greentest/3.8/capath/b1930218.0 | 26 + | |
629 | src/greentest/3.8/capath/ceff1710.0 | 26 + | |
630 | src/greentest/3.8/ffdh3072.pem | 41 + | |
631 | src/greentest/3.8/idnsans.pem | 169 + | |
632 | src/greentest/3.8/keycert.passwd.pem | 68 + | |
633 | src/greentest/3.8/keycert.pem | 66 + | |
634 | src/greentest/3.8/keycert2.pem | 66 + | |
635 | src/greentest/3.8/keycert3.pem | 164 + | |
636 | src/greentest/3.8/keycert4.pem | 164 + | |
637 | src/greentest/3.8/keycertecc.pem | 106 + | |
638 | src/greentest/3.8/nokia.pem | 31 + | |
639 | src/greentest/3.8/nullbytecert.pem | 90 + | |
640 | src/greentest/3.8/nullcert.pem | 0 | |
641 | src/greentest/3.8/pycacert.pem | 99 + | |
642 | src/greentest/3.8/pycakey.pem | 40 + | |
643 | src/greentest/3.8/revocation.crl | 14 + | |
644 | src/greentest/3.8/secp384r1.pem | 7 + | |
645 | .../3.8/selfsigned_pythontestdotnet.pem | 34 + | |
646 | src/greentest/3.8/ssl_cert.pem | 26 + | |
647 | src/greentest/3.8/ssl_key.passwd.pem | 42 + | |
648 | src/greentest/3.8/ssl_key.pem | 40 + | |
649 | src/greentest/3.8/talos-2019-0758.pem | 22 + | |
650 | src/greentest/3.8/test_asyncore.py | 834 +++ | |
651 | src/greentest/3.8/test_ftplib.py | 1093 +++ | |
652 | src/greentest/3.8/test_httplib.py | 1977 ++++++ | |
653 | src/greentest/3.8/test_select.py | 81 + | |
654 | src/greentest/3.8/test_selectors.py | 564 ++ | |
655 | src/greentest/3.8/test_smtpd.py | 1013 +++ | |
656 | src/greentest/3.8/test_socket.py | 6278 +++++++++++++++++ | |
657 | src/greentest/3.8/test_ssl.py | 4652 ++++++++++++ | |
658 | src/greentest/3.8/test_subprocess.py | 3330 +++++++++ | |
659 | src/greentest/3.8/test_threading.py | 1382 ++++ | |
660 | src/greentest/3.8/test_wsgiref.py | 867 +++ | |
661 | src/greentest/3.8/version | 1 + | |
662 | 45 files changed, 23756 insertions(+), 14 deletions(-) | |
663 | create mode 100644 src/greentest/3.8/allsans.pem | |
664 | create mode 100644 src/greentest/3.8/badcert.pem | |
665 | create mode 100644 src/greentest/3.8/badkey.pem | |
666 | create mode 100644 src/greentest/3.8/capath/4e1295a3.0 | |
667 | create mode 100644 src/greentest/3.8/capath/5ed36f99.0 | |
668 | create mode 100644 src/greentest/3.8/capath/6e88d7b8.0 | |
669 | create mode 100644 src/greentest/3.8/capath/99d0fa06.0 | |
670 | create mode 100644 src/greentest/3.8/capath/b1930218.0 | |
671 | create mode 100644 src/greentest/3.8/capath/ceff1710.0 | |
672 | create mode 100644 src/greentest/3.8/ffdh3072.pem | |
673 | create mode 100644 src/greentest/3.8/idnsans.pem | |
674 | create mode 100644 src/greentest/3.8/keycert.passwd.pem | |
675 | create mode 100644 src/greentest/3.8/keycert.pem | |
676 | create mode 100644 src/greentest/3.8/keycert2.pem | |
677 | create mode 100644 src/greentest/3.8/keycert3.pem | |
678 | create mode 100644 src/greentest/3.8/keycert4.pem | |
679 | create mode 100644 src/greentest/3.8/keycertecc.pem | |
680 | create mode 100644 src/greentest/3.8/nokia.pem | |
681 | create mode 100644 src/greentest/3.8/nullbytecert.pem | |
682 | create mode 100644 src/greentest/3.8/nullcert.pem | |
683 | create mode 100644 src/greentest/3.8/pycacert.pem | |
684 | create mode 100644 src/greentest/3.8/pycakey.pem | |
685 | create mode 100644 src/greentest/3.8/revocation.crl | |
686 | create mode 100644 src/greentest/3.8/secp384r1.pem | |
687 | create mode 100644 src/greentest/3.8/selfsigned_pythontestdotnet.pem | |
688 | create mode 100644 src/greentest/3.8/ssl_cert.pem | |
689 | create mode 100644 src/greentest/3.8/ssl_key.passwd.pem | |
690 | create mode 100644 src/greentest/3.8/ssl_key.pem | |
691 | create mode 100644 src/greentest/3.8/talos-2019-0758.pem | |
692 | create mode 100644 src/greentest/3.8/test_asyncore.py | |
693 | create mode 100644 src/greentest/3.8/test_ftplib.py | |
694 | create mode 100644 src/greentest/3.8/test_httplib.py | |
695 | create mode 100644 src/greentest/3.8/test_select.py | |
696 | create mode 100644 src/greentest/3.8/test_selectors.py | |
697 | create mode 100644 src/greentest/3.8/test_smtpd.py | |
698 | create mode 100644 src/greentest/3.8/test_socket.py | |
699 | create mode 100644 src/greentest/3.8/test_ssl.py | |
700 | create mode 100644 src/greentest/3.8/test_subprocess.py | |
701 | create mode 100644 src/greentest/3.8/test_threading.py | |
702 | create mode 100644 src/greentest/3.8/test_wsgiref.py | |
703 | create mode 100644 src/greentest/3.8/version | |
704 | ||
705 | === SKIPPED === | |
706 | From e349789fff94418ff363c3d7ba8d4cf4a5bcd798 Mon Sep 17 00:00:00 2001 | |
707 | From: Jason Madden <jamadden@gmail.com> | |
708 | Date: Fri, 6 Sep 2019 18:27:34 -0500 | |
709 | Subject: [PATCH 3/9] Fix lint. | |
710 | ||
711 | --- | |
712 | src/gevent/tests/test__core_fork.py | 1 - | |
713 | 1 file changed, 1 deletion(-) | |
714 | ||
715 | diff --git a/src/gevent/tests/test__core_fork.py b/src/gevent/tests/test__core_fork.py | |
716 | index 5717cf7d9..20dc2a4d1 100644 | |
717 | --- a/src/gevent/tests/test__core_fork.py | |
718 | +++ b/src/gevent/tests/test__core_fork.py | |
719 | @@ -6,7 +6,6 @@ | |
720 | import multiprocessing | |
721 | ||
722 | import gevent | |
723 | -from gevent._compat import MAC | |
724 | ||
725 | hub = gevent.get_hub() | |
726 | pid = os.getpid() | |
727 | ||
728 | From 5c5d2bc660b599256734a9f5c9e58c79ec4f1b1b Mon Sep 17 00:00:00 2001 | |
729 | From: Jason Madden <jamadden@gmail.com> | |
730 | Date: Fri, 6 Sep 2019 18:28:24 -0500 | |
731 | Subject: [PATCH 4/9] Fix the other place that refs the version in .travis.yml. | |
732 | ||
733 | --- | |
734 | .travis.yml | 4 ++-- | |
735 | 1 file changed, 2 insertions(+), 2 deletions(-) | |
736 | ||
737 | #diff --git a/.travis.yml b/.travis.yml | |
738 | #index 05dc24b12..c956f6ae7 100644 | |
739 | #--- a/.travis.yml | |
740 | #+++ b/.travis.yml | |
741 | #@@ -284,10 +284,10 @@ jobs: | |
742 | # # 3.8 | |
743 | # - <<: *test-libuv-jobs | |
744 | # env: TRAVIS_PYTHON_VERSION=3.8 | |
745 | #- name: libuv36 | |
746 | #+ name: libuv38 | |
747 | # - <<: *test-libev-jobs | |
748 | # env: TRAVIS_PYTHON_VERSION=3.8 | |
749 | #- name: libev-cffi36 | |
750 | #+ name: libev-cffi38 | |
751 | # | |
752 | # | |
753 | # # 2.7, no-embed. Run the tests that exercise the libraries we | |
754 | # | |
755 | From 0a45f740f3afce22c88fd7f9dbe5e30aa7d95336 Mon Sep 17 00:00:00 2001 | |
756 | From: Jason Madden <jamadden@gmail.com> | |
757 | Date: Fri, 6 Sep 2019 18:48:09 -0500 | |
758 | Subject: [PATCH 5/9] Fix false detection in test__all__. | |
759 | ||
760 | --- | |
761 | .travis.yml | 7 +++++-- | |
762 | src/gevent/subprocess.py | 45 ++++++++++++++++++++++++---------------- | |
763 | 2 files changed, 32 insertions(+), 20 deletions(-) | |
764 | ||
765 | #diff --git a/.travis.yml b/.travis.yml | |
766 | #index c956f6ae7..f676bb6e7 100644 | |
767 | #--- a/.travis.yml | |
768 | #+++ b/.travis.yml | |
769 | #@@ -198,9 +198,12 @@ jobs: | |
770 | # # We only need to do this on one version, and it should be Python 3, because | |
771 | # # pylint has stopped updating for Python 2. | |
772 | # - stage: test | |
773 | #- # We need pylint, since above we're not installing a requirements file | |
774 | #+ # We need pylint, since above we're not installing a | |
775 | #+ # requirements file. Code added to _ssl3.SSLContext for Python | |
776 | #+ # 3.8 triggers an infinite recursion bug in pylint 2.3.1/astroid 2.2.5 | |
777 | #+ # unless we disable inference. | |
778 | # install: pip install pylint | |
779 | #- script: python -m pylint --rcfile=.pylintrc gevent | |
780 | #+ script: python -m pylint --limit-inference-results=1 --rcfile=.pylintrc gevent | |
781 | # env: TRAVIS_PYTHON_VERSION=3.7 | |
782 | # name: lint37 | |
783 | # | |
784 | #diff --git a/src/gevent/subprocess.py b/src/gevent/subprocess.py | |
785 | #index 9b4d13cd2..ed22d863b 100644 | |
786 | #--- a/src/gevent/subprocess.py | |
787 | #+++ b/src/gevent/subprocess.py | |
788 | #@@ -70,24 +70,6 @@ | |
789 | # __implements__.append("_posixsubprocess") | |
790 | # _posixsubprocess = None | |
791 | # | |
792 | #-if PY38: | |
793 | #- # Using os.posix_spawn() to start subprocesses | |
794 | #- # bypasses our child watchers on certain operating systems, | |
795 | #- # and with certain library versions. Possibly the right | |
796 | #- # fix is to monkey-patch os.posix_spawn like we do os.fork? | |
797 | #- # These have no effect, they're just here to match the stdlib. | |
798 | #- # TODO: When available, given a monkey patch on them, I think | |
799 | #- # we ought to be able to use them if the stdlib has identified them | |
800 | #- # as suitable. | |
801 | #- __implements__.extend([ | |
802 | #- '_use_posix_spawn', | |
803 | #- '_USE_POSIX_SPAWN' | |
804 | #- ]) | |
805 | #- | |
806 | #- def _use_posix_spawn(): | |
807 | #- return False | |
808 | #- | |
809 | #- _USE_POSIX_SPAWN = False | |
810 | # | |
811 | # # Some symbols we define that we expect to export; | |
812 | # # useful for static analysis | |
813 | #@@ -183,6 +165,33 @@ def _use_posix_spawn(): | |
814 | # 'CREATE_BREAKAWAY_FROM_JOB' | |
815 | # ]) | |
816 | # | |
817 | #+if PY38: | |
818 | #+ # Using os.posix_spawn() to start subprocesses | |
819 | #+ # bypasses our child watchers on certain operating systems, | |
820 | #+ # and with certain library versions. Possibly the right | |
821 | #+ # fix is to monkey-patch os.posix_spawn like we do os.fork? | |
822 | #+ # These have no effect, they're just here to match the stdlib. | |
823 | #+ # TODO: When available, given a monkey patch on them, I think | |
824 | #+ # we ought to be able to use them if the stdlib has identified them | |
825 | #+ # as suitable. | |
826 | #+ __implements__.extend([ | |
827 | #+ '_use_posix_spawn', | |
828 | #+ ]) | |
829 | #+ | |
830 | #+ def _use_posix_spawn(): | |
831 | #+ return False | |
832 | #+ | |
833 | #+ _USE_POSIX_SPAWN = False | |
834 | #+ | |
835 | #+ if __subprocess__._USE_POSIX_SPAWN: | |
836 | #+ __implements__.extend([ | |
837 | #+ '_USE_POSIX_SPAWN', | |
838 | #+ ]) | |
839 | #+ else: | |
840 | #+ __imports__.extend([ | |
841 | #+ '_USE_POSIX_SPAWN', | |
842 | #+ ]) | |
843 | #+ | |
844 | # actually_imported = copy_globals(__subprocess__, globals(), | |
845 | # only_names=__imports__, | |
846 | # ignore_missing_names=True) | |
847 | # | |
848 | From 412d59d0889bf0d1221c52d902a98a7648f0a829 Mon Sep 17 00:00:00 2001 | |
849 | From: Jason Madden <jamadden@gmail.com> | |
850 | Date: Sat, 7 Sep 2019 07:04:09 -0500 | |
851 | Subject: [PATCH 6/9] Hmm, why is test__core giving fits on py38/libuv/travis? | |
852 | Can't reproduce locally. | |
853 | ||
854 | --- | |
855 | appveyor.yml | 1 + | |
856 | src/gevent/libuv/_corecffi_source.c | 16 +++++++++------- | |
857 | 2 files changed, 10 insertions(+), 7 deletions(-) | |
858 | ||
859 | #diff --git a/appveyor.yml b/appveyor.yml | |
860 | #index 3e5f84f78..ee660e472 100644 | |
861 | #--- a/appveyor.yml | |
862 | #+++ b/appveyor.yml | |
863 | #@@ -11,6 +11,7 @@ environment: | |
864 | # # too often we get failures to resolve DNS names or failures | |
865 | # # to connect on AppVeyor. | |
866 | # GEVENTTEST_USE_RESOURCES: "-network" | |
867 | #+ PYTHONTRACEMALLOC: 10 | |
868 | # | |
869 | # matrix: | |
870 | # | |
871 | diff --git a/src/gevent/libuv/_corecffi_source.c b/src/gevent/libuv/_corecffi_source.c | |
872 | index 83fe82ee9..3b4b8d156 100644 | |
873 | --- a/src/gevent/libuv/_corecffi_source.c | |
874 | +++ b/src/gevent/libuv/_corecffi_source.c | |
875 | @@ -150,32 +150,34 @@ static void _gevent_fs_poll_callback3(void* handlep, int status, const uv_stat_t | |
876 | ||
877 | static void gevent_uv_walk_callback_close(uv_handle_t* handle, void* arg) | |
878 | { | |
879 | - if( handle && !uv_is_closing(handle) ) { | |
880 | - uv_close(handle, NULL); | |
881 | - } | |
882 | + if( handle && !uv_is_closing(handle) ) { | |
883 | + uv_close(handle, NULL); | |
884 | + } | |
885 | } | |
886 | ||
887 | static void gevent_close_all_handles(uv_loop_t* loop) | |
888 | { | |
889 | + if (loop) { | |
890 | uv_walk(loop, gevent_uv_walk_callback_close, NULL); | |
891 | + } | |
892 | } | |
893 | ||
894 | static void gevent_zero_timer(uv_timer_t* handle) | |
895 | { | |
896 | - memset(handle, 0, sizeof(uv_timer_t)); | |
897 | + memset(handle, 0, sizeof(uv_timer_t)); | |
898 | } | |
899 | ||
900 | static void gevent_zero_check(uv_check_t* handle) | |
901 | { | |
902 | - memset(handle, 0, sizeof(uv_check_t)); | |
903 | + memset(handle, 0, sizeof(uv_check_t)); | |
904 | } | |
905 | ||
906 | static void gevent_zero_prepare(uv_prepare_t* handle) | |
907 | { | |
908 | - memset(handle, 0, sizeof(uv_prepare_t)); | |
909 | + memset(handle, 0, sizeof(uv_prepare_t)); | |
910 | } | |
911 | ||
912 | static void gevent_zero_loop(uv_loop_t* handle) | |
913 | { | |
914 | - memset(handle, 0, sizeof(uv_loop_t)); | |
915 | + memset(handle, 0, sizeof(uv_loop_t)); | |
916 | } | |
917 | ||
918 | From e52ac513ef66dba47f5312f1870fe2e5b020cb19 Mon Sep 17 00:00:00 2001 | |
919 | From: Jason Madden <jamadden@gmail.com> | |
920 | Date: Sat, 7 Sep 2019 07:44:37 -0500 | |
921 | Subject: [PATCH 7/9] Disable that failing test on 3.8b4 for now. | |
922 | ||
923 | --- | |
924 | src/gevent/tests/test__core.py | 7 +++++++ | |
925 | src/gevent/tests/test__socket.py | 21 ++++++++++----------- | |
926 | 2 files changed, 17 insertions(+), 11 deletions(-) | |
927 | ||
928 | diff --git a/src/gevent/tests/test__core.py b/src/gevent/tests/test__core.py | |
929 | index 1816e0f89..c538ee7aa 100644 | |
930 | --- a/src/gevent/tests/test__core.py | |
931 | +++ b/src/gevent/tests/test__core.py | |
932 | @@ -2,6 +2,7 @@ | |
933 | from __future__ import absolute_import, print_function, division | |
934 | ||
935 | import unittest | |
936 | +import sys | |
937 | import gevent.testing as greentest | |
938 | ||
939 | from gevent import core | |
940 | @@ -128,6 +129,12 @@ def destroyOne(self, loop): | |
941 | "See https://ci.appveyor.com/project/denik/gevent/build/1.0.1380/job/lrlvid6mkjtyrhn5#L1103 " | |
942 | "It has also timed out, but only on Appveyor CPython 3.6; local CPython 3.6 does not. " | |
943 | "See https://ci.appveyor.com/project/denik/gevent/build/1.0.1414/job/yn7yi8b53vtqs8lw#L1523") | |
944 | +@greentest.skipIf( | |
945 | + greentest.LIBUV and greentest.RUNNING_ON_TRAVIS and sys.version_info == (3, 8, 0, 'beta', 4), | |
946 | + "Crashes on 3.8.0b4 on TravisCI. " | |
947 | + "(https://travis-ci.org/gevent/gevent/jobs/582031266#L215) " | |
948 | + "Unable to reproduce locally so far on macOS." | |
949 | +) | |
950 | class TestWatchersDefaultDestroyed(TestWatchers): | |
951 | ||
952 | def _makeOne(self): | |
953 | #diff --git a/src/gevent/tests/test__socket.py b/src/gevent/tests/test__socket.py | |
954 | #index 48f6ee3ed..4a670cdb0 100644 | |
955 | #--- a/src/gevent/tests/test__socket.py | |
956 | #+++ b/src/gevent/tests/test__socket.py | |
957 | #@@ -3,15 +3,15 @@ | |
958 | # from gevent import monkey; monkey.patch_all() | |
959 | # | |
960 | # import sys | |
961 | #-import os | |
962 | # import array | |
963 | # import socket | |
964 | #-import traceback | |
965 | # import time | |
966 | # import unittest | |
967 | #-import gevent.testing as greentest | |
968 | # from functools import wraps | |
969 | # | |
970 | #+from gevent import get_hub | |
971 | #+import gevent.testing as greentest | |
972 | #+ | |
973 | # from gevent.testing import six | |
974 | # from gevent.testing import LARGE_TIMEOUT | |
975 | # from gevent.testing import support | |
976 | #@@ -34,8 +34,7 @@ def errors_are_fatal(*args, **kwargs): | |
977 | # try: | |
978 | # return target(*args, **kwargs) | |
979 | # except: # pylint:disable=bare-except | |
980 | #- traceback.print_exc() | |
981 | #- os._exit(2) | |
982 | #+ get_hub().throw(*sys.exc_info()) | |
983 | # | |
984 | # _Thread.__init__(self, target=errors_are_fatal, **kwargs) | |
985 | # self.start() | |
986 | #@@ -91,18 +90,17 @@ def _test_sendall(self, data, match_data=None, client_method='sendall', | |
987 | # | |
988 | # def accept_and_read(): | |
989 | # conn = None | |
990 | #+ r = None | |
991 | # try: | |
992 | # conn, _ = self.listener.accept() | |
993 | # r = conn.makefile(mode='rb') | |
994 | # read_data.append(r.read()) | |
995 | # r.flush() | |
996 | # r.close() | |
997 | #- except: # pylint:disable=bare-except | |
998 | #- server_exc_info.append(sys.exc_info()) | |
999 | # finally: | |
1000 | #- if conn: | |
1001 | #- conn.close() | |
1002 | #- self.listener.close() | |
1003 | #+ for f in (conn, r, self.listener): | |
1004 | #+ if f is not None: | |
1005 | #+ f.close() | |
1006 | # | |
1007 | # server = Thread(target=accept_and_read) | |
1008 | # client = self.create_connection(**client_args) | |
1009 | #@@ -114,9 +112,10 @@ def accept_and_read(): | |
1010 | # client.close() | |
1011 | # | |
1012 | # server.join() | |
1013 | #+ assert not server.is_alive() | |
1014 | # if match_data is None: | |
1015 | # match_data = self.long_data | |
1016 | #- self.assertEqual(read_data[0], match_data) | |
1017 | #+ self.assertEqual(read_data, [match_data]) | |
1018 | # | |
1019 | # if server_exc_info: | |
1020 | # six.reraise(*server_exc_info[0]) | |
1021 | # | |
1022 | From 271e58658f7cc839dcde74239c66d1d396d675b7 Mon Sep 17 00:00:00 2001 | |
1023 | From: Jason Madden <jamadden@gmail.com> | |
1024 | Date: Sat, 7 Sep 2019 09:02:12 -0500 | |
1025 | Subject: [PATCH 8/9] Whoops, fix Python 2. | |
1026 | ||
1027 | --- | |
1028 | src/gevent/tests/test__greenness.py | 23 +++++++++++++---------- | |
1029 | src/gevent/tests/test__socket.py | 13 ++++++++----- | |
1030 | src/gevent/tests/test__ssl.py | 3 ++- | |
1031 | 3 files changed, 23 insertions(+), 16 deletions(-) | |
1032 | ||
1033 | diff --git a/src/gevent/tests/test__greenness.py b/src/gevent/tests/test__greenness.py | |
1034 | index da4fc948e..71392971f 100644 | |
1035 | --- a/src/gevent/tests/test__greenness.py | |
1036 | +++ b/src/gevent/tests/test__greenness.py | |
1037 | @@ -29,13 +29,15 @@ | |
1038 | import gevent.testing as greentest | |
1039 | ||
1040 | try: | |
1041 | - import urllib2 | |
1042 | -except ImportError: | |
1043 | from urllib import request as urllib2 | |
1044 | -try: | |
1045 | - import BaseHTTPServer | |
1046 | -except ImportError: | |
1047 | from http import server as BaseHTTPServer | |
1048 | + from http.server import SimpleHTTPRequestHandler | |
1049 | +except ImportError: | |
1050 | + # Python 2 | |
1051 | + import urllib2 | |
1052 | + import BaseHTTPServer | |
1053 | + from SimpleHTTPServer import SimpleHTTPRequestHandler | |
1054 | + | |
1055 | ||
1056 | import gevent | |
1057 | from gevent.testing import params | |
1058 | @@ -47,7 +49,8 @@ class TestGreenness(greentest.TestCase): | |
1059 | def setUp(self): | |
1060 | server_address = params.DEFAULT_BIND_ADDR_TUPLE | |
1061 | BaseHTTPServer.BaseHTTPRequestHandler.protocol_version = "HTTP/1.0" | |
1062 | - self.httpd = BaseHTTPServer.HTTPServer(server_address, BaseHTTPServer.BaseHTTPRequestHandler) | |
1063 | + self.httpd = BaseHTTPServer.HTTPServer(server_address, | |
1064 | + SimpleHTTPRequestHandler) | |
1065 | self.httpd.request_count = 0 | |
1066 | ||
1067 | def tearDown(self): | |
1068 | @@ -62,10 +65,10 @@ def test_urllib2(self): | |
1069 | server = gevent.spawn(self.serve) | |
1070 | ||
1071 | port = self.httpd.socket.getsockname()[1] | |
1072 | - with self.assertRaises(urllib2.HTTPError) as exc: | |
1073 | - urllib2.urlopen('http://127.0.0.1:%s' % port) | |
1074 | - self.assertEqual(exc.exception.code, 501) | |
1075 | - server.get(0.01) | |
1076 | + rsp = urllib2.urlopen('http://127.0.0.1:%s' % port) | |
1077 | + rsp.read() | |
1078 | + rsp.close() | |
1079 | + server.join() | |
1080 | self.assertEqual(self.httpd.request_count, 1) | |
1081 | ||
1082 | ||
1083 | #diff --git a/src/gevent/tests/test__socket.py b/src/gevent/tests/test__socket.py | |
1084 | #index 4a670cdb0..195ef1af5 100644 | |
1085 | #--- a/src/gevent/tests/test__socket.py | |
1086 | #+++ b/src/gevent/tests/test__socket.py | |
1087 | #@@ -9,7 +9,7 @@ | |
1088 | # import unittest | |
1089 | # from functools import wraps | |
1090 | # | |
1091 | #-from gevent import get_hub | |
1092 | #+from gevent import getcurrent | |
1093 | # import gevent.testing as greentest | |
1094 | # | |
1095 | # from gevent.testing import six | |
1096 | #@@ -34,7 +34,7 @@ def errors_are_fatal(*args, **kwargs): | |
1097 | # try: | |
1098 | # return target(*args, **kwargs) | |
1099 | # except: # pylint:disable=bare-except | |
1100 | #- get_hub().throw(*sys.exc_info()) | |
1101 | #+ getcurrent().parent.throw(*sys.exc_info()) | |
1102 | # | |
1103 | # _Thread.__init__(self, target=errors_are_fatal, **kwargs) | |
1104 | # self.start() | |
1105 | #@@ -95,13 +95,16 @@ def accept_and_read(): | |
1106 | # conn, _ = self.listener.accept() | |
1107 | # r = conn.makefile(mode='rb') | |
1108 | # read_data.append(r.read()) | |
1109 | #- r.flush() | |
1110 | #- r.close() | |
1111 | # finally: | |
1112 | #- for f in (conn, r, self.listener): | |
1113 | #+ # Order matters. On Python 2, if we close the | |
1114 | #+ # connection before closing the makefile, | |
1115 | #+ # test__ssl fails because the underlying socket | |
1116 | #+ # has been deleted. | |
1117 | #+ for f in (r, conn, self.listener): | |
1118 | # if f is not None: | |
1119 | # f.close() | |
1120 | # | |
1121 | #+ | |
1122 | # server = Thread(target=accept_and_read) | |
1123 | # client = self.create_connection(**client_args) | |
1124 | # | |
1125 | #diff --git a/src/gevent/tests/test__ssl.py b/src/gevent/tests/test__ssl.py | |
1126 | #index 97b70bd98..537e70773 100644 | |
1127 | #--- a/src/gevent/tests/test__ssl.py | |
1128 | #+++ b/src/gevent/tests/test__ssl.py | |
1129 | #@@ -1,3 +1,4 @@ | |
1130 | #+from __future__ import print_function, division, absolute_import | |
1131 | # from gevent import monkey; monkey.patch_all() | |
1132 | # import os | |
1133 | # | |
1134 | #@@ -5,7 +6,7 @@ | |
1135 | # import gevent.testing as greentest | |
1136 | # # Be careful not to have TestTCP as a bare attribute in this module, | |
1137 | # # even aliased, to avoid running duplicate tests | |
1138 | #-import test__socket | |
1139 | #+from gevent.tests import test__socket | |
1140 | # import ssl | |
1141 | # | |
1142 | # | |
1143 | # | |
1144 | From 158ccf26ff07af1c0737307f67ed118e7a1d6ac1 Mon Sep 17 00:00:00 2001 | |
1145 | From: Jason Madden <jamadden@gmail.com> | |
1146 | Date: Sat, 7 Sep 2019 09:27:19 -0500 | |
1147 | Subject: [PATCH 9/9] Implement verify_client_post_handshake; appveyor has TLS | |
1148 | 1.3 now so those tests are running there. | |
1149 | ||
1150 | --- | |
1151 | CHANGES.rst | 2 ++ | |
1152 | src/gevent/_ssl3.py | 5 +++++ | |
1153 | src/gevent/tests/known_failures.py | 9 +++++++++ | |
1154 | src/gevent/tests/test__socket.py | 3 ++- | |
1155 | 4 files changed, 18 insertions(+), 1 deletion(-) | |
1156 | ||
1157 | #diff --git a/CHANGES.rst b/CHANGES.rst | |
1158 | #index 53f4398d2..a4ab7a7ab 100644 | |
1159 | #--- a/CHANGES.rst | |
1160 | #+++ b/CHANGES.rst | |
1161 | #@@ -16,6 +16,8 @@ | |
1162 | # | |
1163 | # - Improve the way joining the main thread works on Python 3. | |
1164 | # | |
1165 | #+- Implement ``SSLSocket.verify_client_post_handshake()`` when available. | |
1166 | #+ | |
1167 | # 1.5a1 (2019-05-02) | |
1168 | # ================== | |
1169 | # | |
1170 | diff --git a/src/gevent/_ssl3.py b/src/gevent/_ssl3.py | |
1171 | index d3de81034..29988cff0 100644 | |
1172 | --- a/src/gevent/_ssl3.py | |
1173 | +++ b/src/gevent/_ssl3.py | |
1174 | @@ -678,6 +678,11 @@ def get_channel_binding(self, cb_type="tls-unique"): | |
1175 | return None | |
1176 | return self._sslobj.tls_unique_cb() | |
1177 | ||
1178 | + def verify_client_post_handshake(self): | |
1179 | + # Only present in 3.7.1+; an attributeerror is alright | |
1180 | + if self._sslobj: | |
1181 | + return self._sslobj.verify_client_post_handshake() | |
1182 | + raise ValueError("No SSL wrapper around " + str(self)) | |
1183 | ||
1184 | # Python does not support forward declaration of types | |
1185 | SSLContext.sslsocket_class = SSLSocket | |
1186 | diff --git a/src/gevent/tests/known_failures.py b/src/gevent/tests/known_failures.py | |
1187 | index eb1db0da1..d5f38ba91 100644 | |
1188 | --- a/src/gevent/tests/known_failures.py | |
1189 | +++ b/src/gevent/tests/known_failures.py | |
1190 | @@ -351,6 +351,15 @@ | |
1191 | 'test__example_webproxy.py', | |
1192 | ] | |
1193 | ||
1194 | +if APPVEYOR: | |
1195 | + # Strange failures sometimes, but only on Python 3.7, reporting | |
1196 | + # "ConnectionAbortedError: [WinError 10053] An established | |
1197 | + # connection was aborted by the software in your host machine" | |
1198 | + # when we've done no such thing. Try running not in parallel | |
1199 | + RUN_ALONE += [ | |
1200 | + 'test__ssl.py', | |
1201 | + 'test__server.py', | |
1202 | + ] | |
1203 | ||
1204 | ||
1205 | if APPVEYOR or TRAVIS: | |
1206 | #diff --git a/src/gevent/tests/test__socket.py b/src/gevent/tests/test__socket.py | |
1207 | #index 195ef1af5..4976d5767 100644 | |
1208 | #--- a/src/gevent/tests/test__socket.py | |
1209 | #+++ b/src/gevent/tests/test__socket.py | |
1210 | #@@ -29,12 +29,13 @@ class Thread(_Thread): | |
1211 | # | |
1212 | # def __init__(self, **kwargs): | |
1213 | # target = kwargs.pop('target') | |
1214 | #+ caller = getcurrent() | |
1215 | # @wraps(target) | |
1216 | # def errors_are_fatal(*args, **kwargs): | |
1217 | # try: | |
1218 | # return target(*args, **kwargs) | |
1219 | # except: # pylint:disable=bare-except | |
1220 | #- getcurrent().parent.throw(*sys.exc_info()) | |
1221 | #+ caller.throw(*sys.exc_info()) | |
1222 | # | |
1223 | # _Thread.__init__(self, target=errors_are_fatal, **kwargs) | |
1224 | # self.start() | |
1225 | --- gevent-1.4.0/src/gevent/thread.py.orig 2019-01-04 12:51:44.000000000 +0100 | |
1226 | +++ gevent-1.4.0/src/gevent/thread.py 2020-01-03 21:14:08.922889769 +0100 | |
1227 | @@ -31,6 +31,8 @@ | |
1228 | 'exit_thread', | |
1229 | 'interrupt_main', | |
1230 | 'start_new'] | |
1231 | + if sys.version_info[:2] >= (3, 8): | |
1232 | + __imports__.append('get_native_id') | |
1233 | error = __thread__.error | |
1234 | from gevent._compat import PY3 | |
1235 | from gevent._compat import PYPY | |
1236 | --- gevent-1.4.0/src/gevent/_tblib.py.orig 2019-01-04 12:51:44.000000000 +0100 | |
1237 | +++ gevent-1.4.0/src/gevent/_tblib.py 2020-01-03 21:25:28.152543399 +0100 | |
1238 | @@ -198,6 +198,9 @@ | |
1239 | while current: | |
1240 | f_code = current.tb_frame.f_code | |
1241 | code = compile('\n' * (current.tb_lineno - 1) + 'raise __traceback_maker', current.tb_frame.f_code.co_filename, 'exec') | |
1242 | - if PY3: | |
1243 | + if hasattr(code, "replace"): | |
1244 | + # Python 3.8 and newer | |
1245 | + code = code.replace(co_argcount=0, co_freevars=(), co_cellvars=()) | |
1246 | + elif PY3: | |
1247 | code = CodeType( | |
1248 | 0, code.co_kwonlyargcount, | |
1249 | --- gevent-1.4.0/src/gevent/_socketcommon.py.orig 2019-01-04 12:51:44.000000000 +0100 | |
1250 | +++ gevent-1.4.0/src/gevent/_socketcommon.py 2020-01-06 15:00:51.236688228 +0100 | |
1251 | @@ -74,6 +74,12 @@ | |
1252 | from gevent._compat import string_types, integer_types, PY3 | |
1253 | from gevent._util import copy_globals | |
1254 | ||
1255 | +if sys.version_info[:2] >= (3, 8): | |
1256 | + __imports__.extend([ | |
1257 | + 'create_server', | |
1258 | + 'has_dualstack_ipv6' | |
1259 | + ]) | |
1260 | + | |
1261 | is_windows = sys.platform == 'win32' | |
1262 | is_macos = sys.platform == 'darwin' | |
1263 |