]> git.pld-linux.org Git - packages/python-gevent.git/blob - python-gevent-py3.8.patch
c8a858878f4e4695aafe514b75f91a61b2a480bf
[packages/python-gevent.git] / python-gevent-py3.8.patch
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  
This page took 0.25099 seconds and 2 git commands to generate.