[packages/python-gevent] - updated to 1.4.0 - updated known_failures-pld patch - removed outdated tests patch - added py3.8 p

qboosh qboosh at pld-linux.org
Mon Jan 6 19:29:55 CET 2020


commit 5a03dc88f04635646a475c56095a5f1e5ee912b6
Author: Jakub Bogusz <qboosh at pld-linux.org>
Date:   Mon Jan 6 19:29:52 2020 +0100

    - updated to 1.4.0
    - updated known_failures-pld patch
    - removed outdated tests patch
    - added py3.8 patch (partial Python 3.8 patch)
    - added -apidocs package

 known_failures-pld.patch  |   21 +-
 python-gevent-py3.8.patch | 1263 +++++++++++++++++++++++++++++++++++++++++++++
 python-gevent-tests.patch |   16 -
 python-gevent.spec        |  104 ++--
 4 files changed, 1351 insertions(+), 53 deletions(-)
---
diff --git a/python-gevent.spec b/python-gevent.spec
index 54392c6..98d3b5f 100644
--- a/python-gevent.spec
+++ b/python-gevent.spec
@@ -7,9 +7,10 @@
 #	  (now excluded via known_failures-pld.patch)
 
 # Conditional build:
-%bcond_without	tests		# do not run tests
-%bcond_with	system_libev	# build with system libev [test__core_stat.py test fails]
-%bcond_without	system_c_ares	# build with system c_ares
+%bcond_without	doc		# Sphinx documentation
+%bcond_without	tests		# testing
+%bcond_with	system_libev	# system libev [test__core_stat.py test fails]
+%bcond_without	system_c_ares	# system c_ares
 %bcond_without	python2		# CPython 2.x module
 %bcond_without	python3		# CPython 3.x module
 
@@ -17,47 +18,64 @@
 Summary:	A coroutine-based Python 2 networking library
 Summary(pl.UTF-8):	Biblioteka sieciowa dla Pythona 2 oparta na korutynach
 Name:		python-%{module}
-Version:	1.3.7
-Release:	2
+Version:	1.4.0
+Release:	1
 Epoch:		1
 License:	MIT
 Group:		Development/Languages
-#Source0Download: https://pypi.python.org/simple/gevent
+#Source0Download: https://pypi.org/simple/gevent/
 Source0:	https://files.pythonhosted.org/packages/source/g/gevent/%{module}-%{version}.tar.gz
-# Source0-md5:	5d3f61ef4bb40fdbd5cbaac7f0d2e585
+# Source0-md5:	6b9dd98917061803d9158e5258b8f412
 Patch0:		known_failures-pld.patch
-Patch1:		%{name}-tests.patch
+Patch1:		%{name}-py3.8.patch
 URL:		http://www.gevent.org/
 %{?with_system_c_ares:BuildRequires:	c-ares-devel >= 1.10.0}
 %{?with_system_libev:BuildRequires:	libev-devel >= 4.23}
-BuildRequires:	python-Cython >= 0.28.5
 %if %{with python2}
-BuildRequires:	python-cffi >= 1.3.0
+BuildRequires:	python-Cython >= 0.29
+BuildRequires:	python-cffi >= 1.11.5
 BuildRequires:	python-devel >= 1:2.7
 BuildRequires:	python-greenlet-devel >= 0.4.15
 %if %{with tests}
 BuildRequires:	python-coverage >= 4.0
 BuildRequires:	python-devel-src >= 1:2.7
+BuildRequires:	python-dns
+BuildRequires:	python-futures
 BuildRequires:	python-greenlet >= 0.4.15
+BuildRequires:  python-mock
 BuildRequires:  python-objgraph
-BuildRequires:	python-setuptools
+BuildRequires:  python-psutil
+BuildRequires:  python-requests
+BuildRequires:	python-setuptools >= 1:24.2.0
 BuildRequires:	python-test
+BuildRequires:	python-zope.event
+BuildRequires:	python-zope.interface
 %endif
 %endif
 %if %{with python3}
-BuildRequires:	python3-cffi >= 1.3.0
-BuildRequires:	python3-devel >= 1:3.3
+BuildRequires:	python3-Cython >= 0.29
+BuildRequires:	python3-cffi >= 1.11.5
+BuildRequires:	python3-devel >= 1:3.4
 BuildRequires:	python3-greenlet-devel >= 0.4.15
 %if %{with tests}
 BuildRequires:	python3-coverage >= 4.0
-BuildRequires:	python3-greenlet >= 0.4.10
+BuildRequires:	python3-dns
+BuildRequires:	python3-greenlet >= 0.4.15
 BuildRequires:  python3-objgraph
-BuildRequires:	python3-setuptools
+BuildRequires:  python3-psutil
+BuildRequires:  python3-requests
+BuildRequires:	python3-setuptools >= 1:24.2.0
 BuildRequires:	python3-test
+BuildRequires:	python3-zope.event
+BuildRequires:	python3-zope.interface
 %endif
 %endif
 BuildRequires:	rpm-pythonprov
 BuildRequires:	rpmbuild(macros) >= 1.714
+%if %{with doc}
+BuildRequires:	python3-repoze.sphinx.autointerface
+BuildRequires:	sphinx-pdg
+%endif
 %{?with_system_libev:Requires:	libev >= 4.23}
 Requires:	python-greenlet >= 0.4.15
 BuildRoot:	%{tmpdir}/%{name}-%{version}-root-%(id -u -n)
@@ -113,17 +131,29 @@ możliwości to m.in.
 - możliwość wykorzystania biblioteki standardowej lub modułów innych
   producentów napisanych dla standardowych gniazd blokujących
 
+%package apidocs
+Summary:	API documentation for Python gevent module
+Summary(pl.UTF-8):	Dokumentacja API modułu Pythona gevent
+Group:		Documentation
+
+%description apidocs
+API documentation for Python gevent module.
+
+%description apidocs -l pl.UTF-8
+Dokumentacja API modułu Pythona gevent.
+
 %prep
 %setup -q -n %{module}-%{version}
 %patch0 -p1
-%patch1 -p1 -b .orig
+%patch1 -p1
 
-%build
+find . -type f -name '*.orig' | xargs -r %{__rm}
 
 # force rebuild of Cython-generated files
 # they depend on specific deps (e.g. greenlet) versions
-rm src/gevent/{*.c,resolver/cares.c}
+%{__rm} src/gevent/{*.c,resolver/cares.c}
 
+%build
 # must be exported to work (py*_build macro is not single invocation)
 %{?with_system_libev:export LIBEV_EMBED=false}
 %{?with_system_c_ares:export CARES_EMBED=false}
@@ -132,10 +162,8 @@ rm src/gevent/{*.c,resolver/cares.c}
 %py_build
 
 %if %{with tests}
-PKGDIR=$(echo $PWD/build-2/lib.*)
-cd src/greentest
-PYTHONPATH=$PKGDIR %{__python} testrunner.py --config known_failures.py
-cd ../..
+PYTHONPATH=$(echo $PWD/build-2/lib.*) \
+%{__python} -m gevent.tests
 %endif
 %endif
 
@@ -143,13 +171,17 @@ cd ../..
 %py3_build
 
 %if %{with tests}
-PKGDIR=$(echo $PWD/build-3/lib.*)
-cd src/greentest
-PYTHONPATH=$PKGDIR %{__python3} testrunner.py --config known_failures.py
-cd ../..
+PYTHONPATH=$(echo $PWD/build-3/lib.*) \
+%{__python3} -m gevent.tests
 %endif
 %endif
 
+%if %{with doc}
+PYTHONPATH=$(echo $PWD/build-2/lib.*) \
+%{__make} -C doc html \
+	SPHINXBUILD=sphinx-build-2
+%endif
+
 %install
 rm -rf $RPM_BUILD_ROOT
 
@@ -160,15 +192,17 @@ rm -rf $RPM_BUILD_ROOT
 %py_install
 
 %py_postclean
-%{__rm} $RPM_BUILD_ROOT%{py_sitedir}/gevent/*.c
-%{__rm} $RPM_BUILD_ROOT%{py_sitedir}/gevent/*/*.{c,h,pyx}
+%{__rm} $RPM_BUILD_ROOT%{py_sitedir}/gevent/*.{c,html}
+%{__rm} $RPM_BUILD_ROOT%{py_sitedir}/gevent/*/*.{c,h,html,pyx}
+%{__rm} -r $RPM_BUILD_ROOT%{py_sitedir}/gevent/{testing,tests}
 %endif
 
 %if %{with python3}
 %py3_install
 
-%{__rm} $RPM_BUILD_ROOT%{py3_sitedir}/gevent/*.c
-%{__rm} $RPM_BUILD_ROOT%{py3_sitedir}/gevent/*/*.{c,h,pyx}
+%{__rm} $RPM_BUILD_ROOT%{py3_sitedir}/gevent/*.{c,html}
+%{__rm} $RPM_BUILD_ROOT%{py3_sitedir}/gevent/*/*.{c,h,html,pyx}
+%{__rm} -r $RPM_BUILD_ROOT%{py3_sitedir}/gevent/{testing,tests}
 %endif
 
 %clean
@@ -177,7 +211,7 @@ rm -rf $RPM_BUILD_ROOT
 %if %{with python2}
 %files
 %defattr(644,root,root,755)
-%doc AUTHORS LICENSE NOTICE README.rst TODO
+%doc AUTHORS CHANGES.rst LICENSE NOTICE README.rst TODO
 %dir %{py_sitedir}/gevent
 %attr(755,root,root) %{py_sitedir}/gevent/*.so
 %{py_sitedir}/gevent/*.pxd
@@ -202,7 +236,7 @@ rm -rf $RPM_BUILD_ROOT
 %if %{with python3}
 %files -n python3-%{module}
 %defattr(644,root,root,755)
-%doc AUTHORS LICENSE NOTICE README.rst TODO
+%doc AUTHORS CHANGES.rst LICENSE NOTICE README.rst TODO
 %dir %{py3_sitedir}/gevent
 %attr(755,root,root) %{py3_sitedir}/gevent/*.cpython-*.so
 %{py3_sitedir}/gevent/__pycache__
@@ -228,3 +262,9 @@ rm -rf $RPM_BUILD_ROOT
 %attr(755,root,root) %{py3_sitedir}/gevent/resolver/cares.*.so
 %{py3_sitedir}/gevent-%{version}-py*.egg-info
 %endif
+
+%if %{with doc}
+%files apidocs
+%defattr(644,root,root,755)
+%doc doc/_build/html/{_modules,_static,api,examples,*.html,*.js}
+%endif
diff --git a/known_failures-pld.patch b/known_failures-pld.patch
index f7c9c74..42d0c83 100644
--- a/known_failures-pld.patch
+++ b/known_failures-pld.patch
@@ -1,7 +1,6 @@
-diff -dur gevent-1.2.2.orig/src/greentest/known_failures.py gevent-1.2.2/src/greentest/known_failures.py
---- gevent-1.2.2.orig/src/greentest/known_failures.py	2017-06-05 13:31:50.000000000 +0200
-+++ gevent-1.2.2/src/greentest/known_failures.py	2018-03-05 12:50:16.000000000 +0100
-@@ -33,8 +33,264 @@
+--- gevent-1.4.0.orig/src/gevent/tests/known_failures.py	2017-06-05 13:31:50.000000000 +0200
++++ gevent-1.4.0/src/gevent/tests/known_failures.py	2018-03-05 12:50:16.000000000 +0100
+@@ -33,8 +33,276 @@
      # we don't have that option without a new commit---and sometimes we really need a build
      # to succeed in order to get a release wheel
      'FLAKY test__issue6.py',
@@ -199,7 +198,7 @@ diff -dur gevent-1.2.2.orig/src/greentest/known_failures.py gevent-1.2.2/src/gre
 +
 +    # depends on external URL accessibility
 +    'FLAKY monkey_test test_urllib2net.py',
-+    'FLAKY monkey_test --Event test_urllib2net.py',
++    #'FLAKY monkey_test --Event test_urllib2net.py',
 +
 +    # requires webpy, not in PLD
 +    # has expectations on local TCP ports availability
@@ -263,6 +262,18 @@ diff -dur gevent-1.2.2.orig/src/greentest/known_failures.py gevent-1.2.2/src/gre
 +    # network
 +    'FLAKY test__server.py',
 +    'FLAKY test__server_pywsgi.py',
++
++    # certificate verify failed
++    'FLAKY test_urllib2_localnet.py', # 'FLAKY monkey_test test_urllib2_localnet.py',
++    # one warning too little?
++    'FLAKY test__monkey.py',
++    # non-deterministic
++    'FLAKY test__hub.py',
++    # "thread_ident=X" vs "thread_ident=-X" on py3.8?
++    'FLAKY test__util.py',
++    # memory corruption under py3.8?
++    'FLAKY test__monkey_sigchld_2.py',
++    'FLAKY test__monkey_sigchld_3.py'
 +]
  
  if sys.platform == 'win32':
diff --git a/python-gevent-py3.8.patch b/python-gevent-py3.8.patch
new file mode 100644
index 0000000..c8a8588
--- /dev/null
+++ b/python-gevent-py3.8.patch
@@ -0,0 +1,1263 @@
+Based on https://github.com/gevent/gevent/commit/8224e81425762ad21d3b63ffb9cc0a0c2d789704.patch
+and https://src.fedoraproject.org/rpms/python-gevent/raw/master/f/0001-code-replace.patch
+
+From e6e2959184909c6292e0135b709282cd5f96065b Mon Sep 17 00:00:00 2001
+From: Jason Madden <jamadden at gmail.com>
+Date: Fri, 6 Sep 2019 16:29:58 -0500
+Subject: [PATCH 1/9] Basic support for CPython 3.8.0b4.
+
+Still needs the specific networking test classes added, but all the basics pass for me. Lets see about CI.
+---
+ .travis.yml                           | 11 +++++++
+ CHANGES.rst                           |  4 +++
+ examples/webproxy.py                  |  7 +++-
+ pyproject.toml                        |  5 +--
+ scripts/install.sh                    |  3 ++
+ src/gevent/__semaphore.pxd            |  2 +-
+ src/gevent/_compat.py                 |  2 +-
+ src/gevent/_socket2.py                |  1 +
+ src/gevent/_socketcommon.py           | 12 +++++--
+ src/gevent/monkey.py                  | 46 +++++++++++++++++++++++++--
+ src/gevent/os.py                      | 29 ++++++++++++++---
+ src/gevent/subprocess.py              | 32 +++++++++++++++++++
+ src/gevent/testing/testrunner.py      | 17 +++++++---
+ src/gevent/tests/test__core_fork.py   |  7 ++--
+ src/gevent/tests/test__threading_2.py | 26 +++++++++------
+ src/gevent/thread.py                  |  6 ++++
+ src/gevent/threading.py               | 46 ++++++++++-----------------
+ 17 files changed, 196 insertions(+), 60 deletions(-)
+
+#diff --git a/.travis.yml b/.travis.yml
+#index bf307df95..05dc24b12 100644
+#--- a/.travis.yml
+#+++ b/.travis.yml
+#@@ -42,6 +42,7 @@ env:
+#       - TRAVIS_PYTHON_VERSION=3.5
+#       - TRAVIS_PYTHON_VERSION=3.6
+#       - TRAVIS_PYTHON_VERSION=3.7
+#+      - TRAVIS_PYTHON_VERSION=3.8
+#       - TRAVIS_PYTHON_VERSION=pypy2.7
+#       - TRAVIS_PYTHON_VERSION=pypy3.6
+#       - TRAVIS_PYTHON_VERSION=2.7 GEVENTSETUP_EMBED=0
+#@@ -144,6 +145,8 @@ jobs:
+#       script: ccache -s
+#       before_script: true
+#       after_success: true
+#+    - <<: *build-gevent
+#+      env: TRAVIS_PYTHON_VERSION=3.8
+#     - <<: *build-gevent
+#       env: TRAVIS_PYTHON_VERSION=3.5
+#     - <<: *build-gevent
+#@@ -278,6 +281,14 @@ jobs:
+#       env: TRAVIS_PYTHON_VERSION=3.7
+#       name: pure37
+# 
+#+    # 3.8
+#+    - <<: *test-libuv-jobs
+#+      env: TRAVIS_PYTHON_VERSION=3.8
+#+      name: libuv36
+#+    - <<: *test-libev-jobs
+#+      env: TRAVIS_PYTHON_VERSION=3.8
+#+      name: libev-cffi36
+#+
+# 
+#     # 2.7, no-embed. Run the tests that exercise the libraries we
+#     # linked to.
+#diff --git a/CHANGES.rst b/CHANGES.rst
+#index 52b5e1c6f..53f4398d2 100644
+#--- a/CHANGES.rst
+#+++ b/CHANGES.rst
+#@@ -12,6 +12,10 @@
+# - Add an ``--module`` option to ``gevent.monkey`` allowing to run a Python
+#   module rather than a script. See :pr:`1440`.
+# 
+#+- Add support for CPython 3.8.0b4.
+#+
+#+- Improve the way joining the main thread works on Python 3.
+#+
+# 1.5a1 (2019-05-02)
+# ==================
+# 
+diff --git a/examples/webproxy.py b/examples/webproxy.py
+index e381d6bd4..de1eaf8d5 100755
+--- a/examples/webproxy.py
++++ b/examples/webproxy.py
+@@ -15,7 +15,12 @@
+ import sys
+ import re
+ import traceback
+-from cgi import escape
++
++try:
++    from cgi import escape
++except ImportError:
++    # Python 3.8 removed this API
++    from html import escape
+ 
+ try:
+     import urllib2
+#diff --git a/pyproject.toml b/pyproject.toml
+#index 2b611b9a4..f611ef972 100644
+#--- a/pyproject.toml
+#+++ b/pyproject.toml
+#@@ -12,8 +12,9 @@ requires = [
+#      # 0.28 is faster, and (important!) lets us specify the target module
+#      # name to be created so that we can have both foo.py and _foo.so
+#      # at the same time. 0.29 fixes some issues with Python 3.7,
+#-     # and adds the 3str mode for transition to Python 3.
+#-     "Cython >= 0.29.7",
+#+     # and adds the 3str mode for transition to Python 3. 0.29.12+ is
+#+     # required for Python 3.8
+#+     "Cython >= 0.29.13",
+#      # See version requirements in setup.py
+#      "cffi >= 1.12.3 ; platform_python_implementation == 'CPython'",
+#      # Python 3.7 requires at least 0.4.14, which is ABI incompatible with earlier
+#diff --git a/scripts/install.sh b/scripts/install.sh
+#index 94bd53058..ef8a6dfbd 100755
+#--- a/scripts/install.sh
+#+++ b/scripts/install.sh
+#@@ -99,6 +99,9 @@ for var in "$@"; do
+#         3.7)
+#             install 3.7.2 python3.7 3.7.d
+#             ;;
+#+        3.8)
+#+            install 3.8.0b4 python3.8 3.8.d
+#+            ;;
+#         pypy2.7)
+#             install pypy2.7-7.1.0 pypy2.7 pypy2.7.d
+#             ;;
+diff --git a/src/gevent/__semaphore.pxd b/src/gevent/__semaphore.pxd
+index dc9f11c68..e46778ed7 100644
+--- a/src/gevent/__semaphore.pxd
++++ b/src/gevent/__semaphore.pxd
+@@ -13,7 +13,7 @@ cdef class Semaphore(AbstractLinkable):
+     # threadpool uses it
+     cpdef _start_notify(self)
+     cpdef int wait(self, object timeout=*) except -1000
+-    cpdef bint acquire(self, int blocking=*, object timeout=*) except -1000
++    cpdef bint acquire(self, bint blocking=*, object timeout=*) except -1000
+     cpdef __enter__(self)
+     cpdef __exit__(self, object t, object v, object tb)
+ 
+diff --git a/src/gevent/_compat.py b/src/gevent/_compat.py
+index 56391459e..e8f5ed4ba 100644
+--- a/src/gevent/_compat.py
++++ b/src/gevent/_compat.py
+@@ -21,7 +21,7 @@
+ PYPY = hasattr(sys, 'pypy_version_info')
+ WIN = sys.platform.startswith("win")
+ LINUX = sys.platform.startswith('linux')
+-OSX = sys.platform == 'darwin'
++OSX = MAC = sys.platform == 'darwin'
+ 
+ 
+ PURE_PYTHON = PYPY or os.getenv('PURE_PYTHON')
+diff --git a/src/gevent/_socket2.py b/src/gevent/_socket2.py
+index 15f470893..7c2f35f3e 100644
+--- a/src/gevent/_socket2.py
++++ b/src/gevent/_socket2.py
+@@ -6,6 +6,7 @@
+ 
+ # Our import magic sadly makes this warning useless
+ # pylint: disable=undefined-variable
++import sys
+ 
+ from gevent import _socketcommon
+ from gevent._util import copy_globals
+#diff --git a/src/gevent/_socketcommon.py b/src/gevent/_socketcommon.py
+#index cd12ac1a9..87b9a4f8a 100644
+#--- a/src/gevent/_socketcommon.py
+#+++ b/src/gevent/_socketcommon.py
+#@@ -69,13 +69,19 @@
+# __imports__.extend(__py3_imports__)
+# 
+# import time
+#-import sys
+#+
+# from gevent._hub_local import get_hub_noargs as get_hub
+# from gevent._compat import string_types, integer_types, PY3
+#+from gevent._compat import PY38
+#+from gevent._compat import WIN as is_windows
+#+from gevent._compat import OSX as is_macos
+# from gevent._util import copy_globals
+# 
+#-is_windows = sys.platform == 'win32'
+#-is_macos = sys.platform == 'darwin'
+#+if PY38:
+#+    __imports__.extend([
+#+        'create_server',
+#+        'has_dualstack_ipv6',
+#+    ])
+# 
+# # pylint:disable=no-name-in-module,unused-import
+# if is_windows:
+diff --git a/src/gevent/monkey.py b/src/gevent/monkey.py
+index 5dbfe3f78..f862f879c 100644
+--- a/src/gevent/monkey.py
++++ b/src/gevent/monkey.py
+@@ -668,6 +668,22 @@ def join(timeout=None):
+                 raise RuntimeError("Cannot join current thread")
+             if thread_greenlet is not None and thread_greenlet.dead:
+                 return
++            # You may ask: Why not call thread_greenlet.join()?
++            # Well, in the one case we actually have a greenlet, it's the
++            # low-level greenlet.greenlet object for the main thread, which
++            # doesn't have a join method.
++            #
++            # You may ask: Why not become the main greenlet's *parent*
++            # so you can get notified when it finishes? Because you can't
++            # create a greenlet cycle (the current greenlet is a descendent
++            # of the parent), and nor can you set a greenlet's parent to None,
++            # so there can only ever be one greenlet with a parent of None: the main
++            # greenlet, the one we need to watch.
++            #
++            # You may ask: why not swizzle out the problematic lock on the main thread
++            # into a gevent friendly lock? Well, the interpreter actually depends on that
++            # for the main thread in threading._shutdown; see below.
++
+             if not thread.is_alive():
+                 return
+ 
+@@ -700,8 +716,34 @@ def join(timeout=None):
+         if orig_current_thread == threading_mod.main_thread():
+             main_thread = threading_mod.main_thread()
+             _greenlet = main_thread._greenlet = greenlet.getcurrent()
+-
+-            main_thread.join = make_join_func(main_thread, _greenlet)
++            main_thread.__real_tstate_lock = main_thread._tstate_lock
++
++            # The interpreter will call threading._shutdown
++            # when the main thread exits and is about to
++            # go away. It is called *in* the main thread. This
++            # is a perfect place to notify other greenlets that
++            # the main thread is done. We do this by overriding the
++            # lock of the main thread during operation, and only restoring
++            # it to the native blocking version at shutdown time
++            # (the interpreter also has a reference to this lock in a
++            # C data structure).
++            main_thread._tstate_lock = threading_mod.Lock()
++            main_thread._tstate_lock.acquire()
++            orig_shutdown = threading_mod._shutdown
++            def _shutdown():
++                # Release anyone trying to join() me,
++                # and let us switch to them.
++                if main_thread._tstate_lock:
++                    main_thread._tstate_lock.release()
++                    from gevent import sleep
++                    sleep()
++                # The only truly blocking native shutdown lock to
++                # acquire should be our own (hopefully)
++                main_thread._tstate_lock = main_thread.__real_tstate_lock
++                main_thread.__real_tstate_lock = None
++                orig_shutdown()
++
++            threading_mod._shutdown = _shutdown
+ 
+             # Patch up the ident of the main thread to match. This
+             # matters if threading was imported before monkey-patching
+diff --git a/src/gevent/os.py b/src/gevent/os.py
+index 3980f320c..4dd66abd8 100644
+--- a/src/gevent/os.py
++++ b/src/gevent/os.py
+@@ -385,6 +385,12 @@ def waitpid(pid, options):
+             # we're not watching it
+             return _waitpid(pid, options)
+ 
++        def _watch_child(pid, callback=None, loop=None, ref=False):
++            loop = loop or get_hub().loop
++            watcher = loop.child(pid, ref=ref)
++            _watched_children[pid] = watcher
++            watcher.start(_on_child, watcher, callback)
++
+         def fork_and_watch(callback=None, loop=None, ref=False, fork=fork_gevent):
+             """
+             Fork a child process and start a child watcher for it in the parent process.
+@@ -413,10 +419,7 @@ def fork_and_watch(callback=None, loop=None, ref=False, fork=fork_gevent):
+             pid = fork()
+             if pid:
+                 # parent
+-                loop = loop or get_hub().loop
+-                watcher = loop.child(pid, ref=ref)
+-                _watched_children[pid] = watcher
+-                watcher.start(_on_child, watcher, callback)
++                _watch_child(pid, callback, loop, ref)
+             return pid
+ 
+         __extensions__.append('fork_and_watch')
+@@ -474,6 +477,23 @@ def forkpty(*args, **kwargs):
+                     # take any args to match fork_and_watch
+                     return forkpty_and_watch(*args, **kwargs)
+             __implements__.append("waitpid")
++
++            if hasattr(os, 'posix_spawn'):
++                _raw_posix_spawn = os.posix_spawn
++                _raw_posix_spawnp = os.posix_spawnp
++
++                def posix_spawn(*args, **kwargs):
++                    pid = _raw_posix_spawn(*args, **kwargs)
++                    _watch_child(pid)
++                    return pid
++
++                def posix_spawnp(*args, **kwargs):
++                    pid = _raw_posix_spawnp(*args, **kwargs)
++                    _watch_child(pid)
++                    return pid
++
++                __implements__.append("posix_spawn")
++                __implements__.append("posix_spawnp")
+         else:
+             def fork():
+                 """
+@@ -503,6 +523,7 @@ def forkpty():
+ else:
+     __implements__.remove('fork')
+ 
++
+ __imports__ = copy_globals(os, globals(),
+                            names_to_ignore=__implements__ + __extensions__,
+                            dunder_names_to_keep=())
+#diff --git a/src/gevent/subprocess.py b/src/gevent/subprocess.py
+#index a9894f1ab..9b4d13cd2 100644
+#--- a/src/gevent/subprocess.py
+#+++ b/src/gevent/subprocess.py
+#@@ -47,6 +47,7 @@
+# from gevent._compat import PY35
+# from gevent._compat import PY36
+# from gevent._compat import PY37
+#+from gevent._compat import PY38
+# from gevent._compat import reraise
+# from gevent._compat import fspath
+# from gevent._compat import fsencode
+#@@ -69,6 +70,25 @@
+#     __implements__.append("_posixsubprocess")
+#     _posixsubprocess = None
+# 
+#+if PY38:
+#+    # Using os.posix_spawn() to start subprocesses
+#+    # bypasses our child watchers on certain operating systems,
+#+    # and with certain library versions. Possibly the right
+#+    # fix is to monkey-patch os.posix_spawn like we do os.fork?
+#+    # These have no effect, they're just here to match the stdlib.
+#+    # TODO: When available, given a monkey patch on them, I think
+#+    # we ought to be able to use them if the stdlib has identified them
+#+    # as suitable.
+#+    __implements__.extend([
+#+        '_use_posix_spawn',
+#+        '_USE_POSIX_SPAWN'
+#+    ])
+#+
+#+    def _use_posix_spawn():
+#+        return False
+#+
+#+    _USE_POSIX_SPAWN = False
+#+
+# # Some symbols we define that we expect to export;
+# # useful for static analysis
+# PIPE = "PIPE should be imported"
+#@@ -1720,3 +1740,15 @@ def run(*popenargs, **kwargs):
+#             raise _with_stdout_stderr(CalledProcessError(retcode, process.args, stdout), stderr)
+# 
+#     return CompletedProcess(process.args, retcode, stdout, stderr)
+#+
+#+def _gevent_did_monkey_patch(*_args):
+#+    # Beginning on 3.8 on Mac, the 'spawn' method became the default
+#+    # start method. That doesn't fire fork watchers and we can't
+#+    # easily patch to make it do so: multiprocessing uses the private
+#+    # c accelerated _subprocess module to implement this. Instead we revert
+#+    # back to using fork.
+#+    from gevent._compat import MAC
+#+    if MAC:
+#+        import multiprocessing
+#+        if hasattr(multiprocessing, 'set_start_method'):
+#+            multiprocessing.set_start_method('fork', force=True)
+diff --git a/src/gevent/testing/testrunner.py b/src/gevent/testing/testrunner.py
+index 3c1c711f8..7a3f8c6bb 100644
+--- a/src/gevent/testing/testrunner.py
++++ b/src/gevent/testing/testrunner.py
+@@ -480,17 +480,26 @@ def _setup_environ(debug=False):
+     if 'GEVENT_DEBUG' not in os.environ and debug:
+         os.environ['GEVENT_DEBUG'] = 'debug'
+ 
+-    if 'PYTHONTRACEMALLOC' not in os.environ:
++    if 'PYTHONTRACEMALLOC' not in os.environ and debug:
++        # This slows the tests down quite a bit. Reserve
++        # for debugging.
+         os.environ['PYTHONTRACEMALLOC'] = '10'
+ 
+     if 'PYTHONDEVMODE' not in os.environ:
+-        # Python 3.7
++        # Python 3.7 and above.
+         os.environ['PYTHONDEVMODE'] = '1'
+ 
+-    if 'PYTHONMALLOC' not in os.environ:
+-        # Python 3.6
++    if 'PYTHONMALLOC' not in os.environ and debug:
++        # Python 3.6 and above.
++        # This slows the tests down some, but
++        # can detect memory corruption. Unfortunately
++        # it can also be flaky, especially in pre-release
++        # versions of Python (e.g., lots of crashes on Python 3.8b4).
+         os.environ['PYTHONMALLOC'] = 'debug'
+ 
++    if sys.version_info.releaselevel != 'final' and not debug:
++        os.environ['PYTHONMALLOC'] = 'default'
++        os.environ['PYTHONDEVMODE'] = ''
+ 
+ 
+ def main():
+diff --git a/src/gevent/tests/test__core_fork.py b/src/gevent/tests/test__core_fork.py
+index fee42f547..5717cf7d9 100644
+--- a/src/gevent/tests/test__core_fork.py
++++ b/src/gevent/tests/test__core_fork.py
+@@ -1,11 +1,13 @@
+ from __future__ import print_function
+ import gevent.monkey
+ gevent.monkey.patch_all()
+-import gevent
+-import os
+ 
++import os
+ import multiprocessing
+ 
++import gevent
++from gevent._compat import MAC
++
+ hub = gevent.get_hub()
+ pid = os.getpid()
+ newpid = None
+@@ -46,6 +48,7 @@ def test():
+ if __name__ == '__main__':
+     # Must call for Windows to fork properly; the fork can't be in the top-level
+     multiprocessing.freeze_support()
++
+     # fork watchers weren't firing in multi-threading processes.
+     # This test is designed to prove that they are.
+     # However, it fails on Windows: The fork watcher never runs!
+diff --git a/src/gevent/tests/test__threading_2.py b/src/gevent/tests/test__threading_2.py
+index b425c88a3..cb7f8b91e 100644
+--- a/src/gevent/tests/test__threading_2.py
++++ b/src/gevent/tests/test__threading_2.py
+@@ -33,6 +33,7 @@
+     from test.support import verbose
+ except ImportError:
+     from test.test_support import verbose
++
+ import random
+ import re
+ import sys
+@@ -46,7 +47,7 @@
+ import weakref
+ 
+ from gevent.tests import lock_tests
+-
++verbose = False
+ # A trivial mutable counter.
+ 
+ def skipDueToHang(cls):
+@@ -132,7 +133,7 @@ def test_various_ops(self):
+             print('waiting for all tasks to complete')
+         for t in threads:
+             t.join(NUMTASKS)
+-            self.assertFalse(t.is_alive())
++            self.assertFalse(t.is_alive(), t.__dict__)
+             if hasattr(t, 'ident'):
+                 self.assertNotEqual(t.ident, 0)
+                 self.assertFalse(t.ident is None)
+@@ -351,28 +352,33 @@ def test_join_nondaemon_on_shutdown(self):
+         # Issue 1722344
+         # Raising SystemExit skipped threading._shutdown
+         import subprocess
+-        p = subprocess.Popen([sys.executable, "-W", "ignore", "-c", """if 1:
++        script = """if 1:
+ %s
+                 import threading
+                 from time import sleep
+ 
+                 def child():
+-                    sleep(1)
++                    sleep(0.3)
+                     # As a non-daemon thread we SHOULD wake up and nothing
+                     # should be torn down yet
+-                    print("Woke up, sleep function is: %%r" %% sleep)
++                    print("Woke up, sleep function is: %%s.%%s" %% (sleep.__module__, sleep.__name__))
+ 
+                 threading.Thread(target=child).start()
+                 raise SystemExit
+-            """ % setup_4],
++        """ % setup_4
++        p = subprocess.Popen([sys.executable, "-W", "ignore", "-c", script],
+                              stdout=subprocess.PIPE,
+                              stderr=subprocess.PIPE)
+         stdout, stderr = p.communicate()
+         stdout = stdout.strip()
+         stdout = stdout.decode('utf-8')
+         stderr = stderr.decode('utf-8')
+-        assert re.match('^Woke up, sleep function is: <.*?sleep.*?>$', stdout), repr(stdout)
+-        stderr = re.sub(r"^\[\d+ refs\]", "", stderr, re.MULTILINE).strip()
++
++
++        self.assertEqual(
++            'Woke up, sleep function is: gevent.hub.sleep',
++            stdout)
++
+         # On Python 2, importing pkg_resources tends to result in some 'ImportWarning'
+         # being printed to stderr about packages missing __init__.py; the -W ignore is...
+         # ignored.
+@@ -410,7 +416,7 @@ def __init__(self, should_raise):
+                     self.should_raise = should_raise
+                     self.thread = threading.Thread(target=self._run,
+                                                    args=(self,),
+-                                                   kwargs={'yet_another': self})
++                                                   kwargs={'_yet_another': self})
+                     self.thread.start()
+ 
+                 def _run(self, _other_ref, _yet_another):
+@@ -463,7 +469,7 @@ def test_1_join_on_shutdown(self):
+             t = threading.Thread(target=joiningfunc,
+                                  args=(threading.current_thread(),))
+             t.start()
+-            time.sleep(0.1)
++            time.sleep(0.2)
+             print('end of main')
+             """
+         self._run_and_join(script)
+#diff --git a/src/gevent/thread.py b/src/gevent/thread.py
+#index a1fe41813..14428df3f 100644
+#--- a/src/gevent/thread.py
+#+++ b/src/gevent/thread.py
+#@@ -41,6 +41,12 @@
+#         'interrupt_main',
+#         'start_new'
+#     ]
+#+    if sys.version_info[:2] >= (3, 8):
+#+        # We can't actually produce a value that "may be used
+#+        # to identify this particular thread system-wide", right?
+#+        # Even if we could, I imagine people will want to pass this to
+#+        # non-Python (native) APIs, so we shouldn't mess with it.
+#+        __imports__.append('get_native_id')
+# 
+# 
+# error = __thread__.error
+diff --git a/src/gevent/threading.py b/src/gevent/threading.py
+index c845fd221..64d989584 100644
+--- a/src/gevent/threading.py
++++ b/src/gevent/threading.py
+@@ -160,41 +160,25 @@ def main_native_thread():
+ if PY3:
+     # XXX: Issue 18808 breaks us on Python 3.4+.
+     # Thread objects now expect a callback from the interpreter itself
+-    # (threadmodule.c:release_sentinel). Because this never happens
++    # (threadmodule.c:release_sentinel) when the C-level PyThreadState
++    # object is being deallocated. Because this never happens
+     # when a greenlet exits, join() and friends will block forever.
+-    # The solution below involves capturing the greenlet when it is
+-    # started and deferring the known broken methods to it.
++    # Fortunately this is easy to fix: just ensure that the allocation of the
++    # lock, _set_sentinel, creates a *gevent* lock, and release it when
++    # we're done. The main _shutdown code is in Python and deals with
++    # this gracefully.
+ 
+     class Thread(__threading__.Thread):
+-        _greenlet = None
+-
+-        def is_alive(self):
+-            return bool(self._greenlet)
+-
+-        isAlive = is_alive
+ 
+         def _set_tstate_lock(self):
+-            self._greenlet = getcurrent()
+-
+-        def run(self):
+-            try:
+-                super(Thread, self).run()
+-            finally:
+-                # avoid ref cycles, but keep in __dict__ so we can
+-                # distinguish the started/never-started case
+-                self._greenlet = None
+-                self._stop() # mark as finished
+-
+-        def join(self, timeout=None):
+-            if '_greenlet' not in self.__dict__:
+-                raise RuntimeError("Cannot join an inactive thread")
+-            if self._greenlet is None:
+-                return
+-            self._greenlet.join(timeout=timeout)
+-
+-        def _wait_for_tstate_lock(self, *args, **kwargs):
+-            # pylint:disable=arguments-differ
+-            raise NotImplementedError()
++            super(Thread, self)._set_tstate_lock()
++            greenlet = getcurrent()
++            greenlet.rawlink(self.__greenlet_finished)
++
++        def __greenlet_finished(self, _):
++            if self._tstate_lock:
++                self._tstate_lock.release()
++                self._stop()
+ 
+     __implements__.append('Thread')
+ 
+@@ -203,6 +187,8 @@ class Timer(Thread, __threading__.Timer): # pylint:disable=abstract-method,inher
+ 
+     __implements__.append('Timer')
+ 
++    _set_sentinel = allocate_lock
++    __implements__.append('_set_sentinel')
+     # The main thread is patched up with more care
+     # in _gevent_will_monkey_patch
+ 
+
+From 632d3c9990f7db27f76245895bb4c2717818c5d5 Mon Sep 17 00:00:00 2001
+From: Jason Madden <jamadden at gmail.com>
+Date: Fri, 6 Sep 2019 18:26:42 -0500
+Subject: [PATCH 2/9] Add the 3.8 test cases.
+
+---
+ src/gevent/_ssl3.py                           |   14 +
+ src/gevent/monkey.py                          |   37 +-
+ src/gevent/testing/patched_tests_setup.py     |   36 +-
+ src/gevent/testing/sysinfo.py                 |    3 +
+ src/greentest/3.8/allsans.pem                 |   81 +
+ src/greentest/3.8/badcert.pem                 |   36 +
+ src/greentest/3.8/badkey.pem                  |   40 +
+ src/greentest/3.8/capath/4e1295a3.0           |   14 +
+ src/greentest/3.8/capath/5ed36f99.0           |   41 +
+ src/greentest/3.8/capath/6e88d7b8.0           |   14 +
+ src/greentest/3.8/capath/99d0fa06.0           |   41 +
+ src/greentest/3.8/capath/b1930218.0           |   26 +
+ src/greentest/3.8/capath/ceff1710.0           |   26 +
+ src/greentest/3.8/ffdh3072.pem                |   41 +
+ src/greentest/3.8/idnsans.pem                 |  169 +
+ src/greentest/3.8/keycert.passwd.pem          |   68 +
+ src/greentest/3.8/keycert.pem                 |   66 +
+ src/greentest/3.8/keycert2.pem                |   66 +
+ src/greentest/3.8/keycert3.pem                |  164 +
+ src/greentest/3.8/keycert4.pem                |  164 +
+ src/greentest/3.8/keycertecc.pem              |  106 +
+ src/greentest/3.8/nokia.pem                   |   31 +
+ src/greentest/3.8/nullbytecert.pem            |   90 +
+ src/greentest/3.8/nullcert.pem                |    0
+ src/greentest/3.8/pycacert.pem                |   99 +
+ src/greentest/3.8/pycakey.pem                 |   40 +
+ src/greentest/3.8/revocation.crl              |   14 +
+ src/greentest/3.8/secp384r1.pem               |    7 +
+ .../3.8/selfsigned_pythontestdotnet.pem       |   34 +
+ src/greentest/3.8/ssl_cert.pem                |   26 +
+ src/greentest/3.8/ssl_key.passwd.pem          |   42 +
+ src/greentest/3.8/ssl_key.pem                 |   40 +
+ src/greentest/3.8/talos-2019-0758.pem         |   22 +
+ src/greentest/3.8/test_asyncore.py            |  834 +++
+ src/greentest/3.8/test_ftplib.py              | 1093 +++
+ src/greentest/3.8/test_httplib.py             | 1977 ++++++
+ src/greentest/3.8/test_select.py              |   81 +
+ src/greentest/3.8/test_selectors.py           |  564 ++
+ src/greentest/3.8/test_smtpd.py               | 1013 +++
+ src/greentest/3.8/test_socket.py              | 6278 +++++++++++++++++
+ src/greentest/3.8/test_ssl.py                 | 4652 ++++++++++++
+ src/greentest/3.8/test_subprocess.py          | 3330 +++++++++
+ src/greentest/3.8/test_threading.py           | 1382 ++++
+ src/greentest/3.8/test_wsgiref.py             |  867 +++
+ src/greentest/3.8/version                     |    1 +
+ 45 files changed, 23756 insertions(+), 14 deletions(-)
+ create mode 100644 src/greentest/3.8/allsans.pem
+ create mode 100644 src/greentest/3.8/badcert.pem
+ create mode 100644 src/greentest/3.8/badkey.pem
+ create mode 100644 src/greentest/3.8/capath/4e1295a3.0
+ create mode 100644 src/greentest/3.8/capath/5ed36f99.0
+ create mode 100644 src/greentest/3.8/capath/6e88d7b8.0
+ create mode 100644 src/greentest/3.8/capath/99d0fa06.0
+ create mode 100644 src/greentest/3.8/capath/b1930218.0
+ create mode 100644 src/greentest/3.8/capath/ceff1710.0
+ create mode 100644 src/greentest/3.8/ffdh3072.pem
+ create mode 100644 src/greentest/3.8/idnsans.pem
+ create mode 100644 src/greentest/3.8/keycert.passwd.pem
+ create mode 100644 src/greentest/3.8/keycert.pem
+ create mode 100644 src/greentest/3.8/keycert2.pem
+ create mode 100644 src/greentest/3.8/keycert3.pem
+ create mode 100644 src/greentest/3.8/keycert4.pem
+ create mode 100644 src/greentest/3.8/keycertecc.pem
+ create mode 100644 src/greentest/3.8/nokia.pem
+ create mode 100644 src/greentest/3.8/nullbytecert.pem
+ create mode 100644 src/greentest/3.8/nullcert.pem
+ create mode 100644 src/greentest/3.8/pycacert.pem
+ create mode 100644 src/greentest/3.8/pycakey.pem
+ create mode 100644 src/greentest/3.8/revocation.crl
+ create mode 100644 src/greentest/3.8/secp384r1.pem
+ create mode 100644 src/greentest/3.8/selfsigned_pythontestdotnet.pem
+ create mode 100644 src/greentest/3.8/ssl_cert.pem
+ create mode 100644 src/greentest/3.8/ssl_key.passwd.pem
+ create mode 100644 src/greentest/3.8/ssl_key.pem
+ create mode 100644 src/greentest/3.8/talos-2019-0758.pem
+ create mode 100644 src/greentest/3.8/test_asyncore.py
+ create mode 100644 src/greentest/3.8/test_ftplib.py
+ create mode 100644 src/greentest/3.8/test_httplib.py
+ create mode 100644 src/greentest/3.8/test_select.py
+ create mode 100644 src/greentest/3.8/test_selectors.py
+ create mode 100644 src/greentest/3.8/test_smtpd.py
+ create mode 100644 src/greentest/3.8/test_socket.py
+ create mode 100644 src/greentest/3.8/test_ssl.py
+ create mode 100644 src/greentest/3.8/test_subprocess.py
+ create mode 100644 src/greentest/3.8/test_threading.py
+ create mode 100644 src/greentest/3.8/test_wsgiref.py
+ create mode 100644 src/greentest/3.8/version
+
+=== SKIPPED ===
+From e349789fff94418ff363c3d7ba8d4cf4a5bcd798 Mon Sep 17 00:00:00 2001
+From: Jason Madden <jamadden at gmail.com>
+Date: Fri, 6 Sep 2019 18:27:34 -0500
+Subject: [PATCH 3/9] Fix lint.
+
+---
+ src/gevent/tests/test__core_fork.py | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/src/gevent/tests/test__core_fork.py b/src/gevent/tests/test__core_fork.py
+index 5717cf7d9..20dc2a4d1 100644
+--- a/src/gevent/tests/test__core_fork.py
++++ b/src/gevent/tests/test__core_fork.py
+@@ -6,7 +6,6 @@
+ import multiprocessing
+ 
+ import gevent
+-from gevent._compat import MAC
+ 
+ hub = gevent.get_hub()
+ pid = os.getpid()
+
+From 5c5d2bc660b599256734a9f5c9e58c79ec4f1b1b Mon Sep 17 00:00:00 2001
+From: Jason Madden <jamadden at gmail.com>
+Date: Fri, 6 Sep 2019 18:28:24 -0500
+Subject: [PATCH 4/9] Fix the other place that refs the version in .travis.yml.
+
+---
+ .travis.yml | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+#diff --git a/.travis.yml b/.travis.yml
+#index 05dc24b12..c956f6ae7 100644
+#--- a/.travis.yml
+#+++ b/.travis.yml
+#@@ -284,10 +284,10 @@ jobs:
+#     # 3.8
+#     - <<: *test-libuv-jobs
+#       env: TRAVIS_PYTHON_VERSION=3.8
+#-      name: libuv36
+#+      name: libuv38
+#     - <<: *test-libev-jobs
+#       env: TRAVIS_PYTHON_VERSION=3.8
+#-      name: libev-cffi36
+#+      name: libev-cffi38
+# 
+# 
+#     # 2.7, no-embed. Run the tests that exercise the libraries we
+#
+From 0a45f740f3afce22c88fd7f9dbe5e30aa7d95336 Mon Sep 17 00:00:00 2001
+From: Jason Madden <jamadden at gmail.com>
+Date: Fri, 6 Sep 2019 18:48:09 -0500
+Subject: [PATCH 5/9] Fix false detection in test__all__.
+
+---
+ .travis.yml              |  7 +++++--
+ src/gevent/subprocess.py | 45 ++++++++++++++++++++++++----------------
+ 2 files changed, 32 insertions(+), 20 deletions(-)
+
+#diff --git a/.travis.yml b/.travis.yml
+#index c956f6ae7..f676bb6e7 100644
+#--- a/.travis.yml
+#+++ b/.travis.yml
+#@@ -198,9 +198,12 @@ jobs:
+#     # We only need to do this on one version, and it should be Python 3, because
+#     # pylint has stopped updating for Python 2.
+#     - stage: test
+#-      # We need pylint, since above we're not installing a requirements file
+#+      # We need pylint, since above we're not installing a
+#+      # requirements file. Code added to _ssl3.SSLContext for Python
+#+      # 3.8 triggers an infinite recursion bug in pylint 2.3.1/astroid 2.2.5
+#+      # unless we disable inference.
+#       install: pip install pylint
+#-      script: python -m pylint --rcfile=.pylintrc gevent
+#+      script: python -m pylint --limit-inference-results=1 --rcfile=.pylintrc gevent
+#       env: TRAVIS_PYTHON_VERSION=3.7
+#       name: lint37
+# 
+#diff --git a/src/gevent/subprocess.py b/src/gevent/subprocess.py
+#index 9b4d13cd2..ed22d863b 100644
+#--- a/src/gevent/subprocess.py
+#+++ b/src/gevent/subprocess.py
+#@@ -70,24 +70,6 @@
+#     __implements__.append("_posixsubprocess")
+#     _posixsubprocess = None
+# 
+#-if PY38:
+#-    # Using os.posix_spawn() to start subprocesses
+#-    # bypasses our child watchers on certain operating systems,
+#-    # and with certain library versions. Possibly the right
+#-    # fix is to monkey-patch os.posix_spawn like we do os.fork?
+#-    # These have no effect, they're just here to match the stdlib.
+#-    # TODO: When available, given a monkey patch on them, I think
+#-    # we ought to be able to use them if the stdlib has identified them
+#-    # as suitable.
+#-    __implements__.extend([
+#-        '_use_posix_spawn',
+#-        '_USE_POSIX_SPAWN'
+#-    ])
+#-
+#-    def _use_posix_spawn():
+#-        return False
+#-
+#-    _USE_POSIX_SPAWN = False
+# 
+# # Some symbols we define that we expect to export;
+# # useful for static analysis
+#@@ -183,6 +165,33 @@ def _use_posix_spawn():
+#         'CREATE_BREAKAWAY_FROM_JOB'
+#     ])
+# 
+#+if PY38:
+#+    # Using os.posix_spawn() to start subprocesses
+#+    # bypasses our child watchers on certain operating systems,
+#+    # and with certain library versions. Possibly the right
+#+    # fix is to monkey-patch os.posix_spawn like we do os.fork?
+#+    # These have no effect, they're just here to match the stdlib.
+#+    # TODO: When available, given a monkey patch on them, I think
+#+    # we ought to be able to use them if the stdlib has identified them
+#+    # as suitable.
+#+    __implements__.extend([
+#+        '_use_posix_spawn',
+#+    ])
+#+
+#+    def _use_posix_spawn():
+#+        return False
+#+
+#+    _USE_POSIX_SPAWN = False
+#+
+#+    if __subprocess__._USE_POSIX_SPAWN:
+#+        __implements__.extend([
+#+            '_USE_POSIX_SPAWN',
+#+        ])
+#+    else:
+#+        __imports__.extend([
+#+            '_USE_POSIX_SPAWN',
+#+        ])
+#+
+# actually_imported = copy_globals(__subprocess__, globals(),
+#                                  only_names=__imports__,
+#                                  ignore_missing_names=True)
+#
+From 412d59d0889bf0d1221c52d902a98a7648f0a829 Mon Sep 17 00:00:00 2001
+From: Jason Madden <jamadden at gmail.com>
+Date: Sat, 7 Sep 2019 07:04:09 -0500
+Subject: [PATCH 6/9] Hmm, why is test__core giving fits on py38/libuv/travis?
+ Can't reproduce locally.
+
+---
+ appveyor.yml                        |  1 +
+ src/gevent/libuv/_corecffi_source.c | 16 +++++++++-------
+ 2 files changed, 10 insertions(+), 7 deletions(-)
+
+#diff --git a/appveyor.yml b/appveyor.yml
+#index 3e5f84f78..ee660e472 100644
+#--- a/appveyor.yml
+#+++ b/appveyor.yml
+#@@ -11,6 +11,7 @@ environment:
+#     # too often we get failures to resolve DNS names or failures
+#     # to connect on AppVeyor.
+#     GEVENTTEST_USE_RESOURCES: "-network"
+#+    PYTHONTRACEMALLOC: 10
+# 
+#   matrix:
+# 
+diff --git a/src/gevent/libuv/_corecffi_source.c b/src/gevent/libuv/_corecffi_source.c
+index 83fe82ee9..3b4b8d156 100644
+--- a/src/gevent/libuv/_corecffi_source.c
++++ b/src/gevent/libuv/_corecffi_source.c
+@@ -150,32 +150,34 @@ static void _gevent_fs_poll_callback3(void* handlep, int status, const uv_stat_t
+ 
+ static void gevent_uv_walk_callback_close(uv_handle_t* handle, void* arg)
+ {
+-	if( handle && !uv_is_closing(handle) ) {
+-		uv_close(handle, NULL);
+-	}
++    if( handle && !uv_is_closing(handle) ) {
++	uv_close(handle, NULL);
++    }
+ }
+ 
+ static void gevent_close_all_handles(uv_loop_t* loop)
+ {
++    if (loop) {
+ 	uv_walk(loop, gevent_uv_walk_callback_close, NULL);
++    }
+ }
+ 
+ static void gevent_zero_timer(uv_timer_t* handle)
+ {
+-	memset(handle, 0, sizeof(uv_timer_t));
++    memset(handle, 0, sizeof(uv_timer_t));
+ }
+ 
+ static void gevent_zero_check(uv_check_t* handle)
+ {
+-	memset(handle, 0, sizeof(uv_check_t));
++    memset(handle, 0, sizeof(uv_check_t));
+ }
+ 
+ static void gevent_zero_prepare(uv_prepare_t* handle)
+ {
+-	memset(handle, 0, sizeof(uv_prepare_t));
++    memset(handle, 0, sizeof(uv_prepare_t));
+ }
+ 
+ static void gevent_zero_loop(uv_loop_t* handle)
+ {
+-	memset(handle, 0, sizeof(uv_loop_t));
++    memset(handle, 0, sizeof(uv_loop_t));
+ }
+
+From e52ac513ef66dba47f5312f1870fe2e5b020cb19 Mon Sep 17 00:00:00 2001
+From: Jason Madden <jamadden at gmail.com>
+Date: Sat, 7 Sep 2019 07:44:37 -0500
+Subject: [PATCH 7/9] Disable that failing test on 3.8b4 for now.
+
+---
+ src/gevent/tests/test__core.py   |  7 +++++++
+ src/gevent/tests/test__socket.py | 21 ++++++++++-----------
+ 2 files changed, 17 insertions(+), 11 deletions(-)
+
+diff --git a/src/gevent/tests/test__core.py b/src/gevent/tests/test__core.py
+index 1816e0f89..c538ee7aa 100644
+--- a/src/gevent/tests/test__core.py
++++ b/src/gevent/tests/test__core.py
+@@ -2,6 +2,7 @@
+ from __future__ import absolute_import, print_function, division
+ 
+ import unittest
++import sys
+ import gevent.testing as greentest
+ 
+ from gevent import core
+@@ -128,6 +129,12 @@ def destroyOne(self, loop):
+     "See https://ci.appveyor.com/project/denik/gevent/build/1.0.1380/job/lrlvid6mkjtyrhn5#L1103 "
+     "It has also timed out, but only on Appveyor CPython 3.6; local CPython 3.6 does not. "
+     "See https://ci.appveyor.com/project/denik/gevent/build/1.0.1414/job/yn7yi8b53vtqs8lw#L1523")
++ at greentest.skipIf(
++    greentest.LIBUV and greentest.RUNNING_ON_TRAVIS and sys.version_info == (3, 8, 0, 'beta', 4),
++    "Crashes on 3.8.0b4 on TravisCI. "
++    "(https://travis-ci.org/gevent/gevent/jobs/582031266#L215) "
++    "Unable to reproduce locally so far on macOS."
++)
+ class TestWatchersDefaultDestroyed(TestWatchers):
+ 
+     def _makeOne(self):
+#diff --git a/src/gevent/tests/test__socket.py b/src/gevent/tests/test__socket.py
+#index 48f6ee3ed..4a670cdb0 100644
+#--- a/src/gevent/tests/test__socket.py
+#+++ b/src/gevent/tests/test__socket.py
+#@@ -3,15 +3,15 @@
+# from gevent import monkey; monkey.patch_all()
+# 
+# import sys
+#-import os
+# import array
+# import socket
+#-import traceback
+# import time
+# import unittest
+#-import gevent.testing as greentest
+# from functools import wraps
+# 
+#+from gevent import get_hub
+#+import gevent.testing as greentest
+#+
+# from gevent.testing import six
+# from gevent.testing import LARGE_TIMEOUT
+# from gevent.testing import support
+#@@ -34,8 +34,7 @@ def errors_are_fatal(*args, **kwargs):
+#             try:
+#                 return target(*args, **kwargs)
+#             except: # pylint:disable=bare-except
+#-                traceback.print_exc()
+#-                os._exit(2)
+#+                get_hub().throw(*sys.exc_info())
+# 
+#         _Thread.__init__(self, target=errors_are_fatal, **kwargs)
+#         self.start()
+#@@ -91,18 +90,17 @@ def _test_sendall(self, data, match_data=None, client_method='sendall',
+# 
+#         def accept_and_read():
+#             conn = None
+#+            r = None
+#             try:
+#                 conn, _ = self.listener.accept()
+#                 r = conn.makefile(mode='rb')
+#                 read_data.append(r.read())
+#                 r.flush()
+#                 r.close()
+#-            except: # pylint:disable=bare-except
+#-                server_exc_info.append(sys.exc_info())
+#             finally:
+#-                if conn:
+#-                    conn.close()
+#-                self.listener.close()
+#+                for f in (conn, r, self.listener):
+#+                    if f is not None:
+#+                        f.close()
+# 
+#         server = Thread(target=accept_and_read)
+#         client = self.create_connection(**client_args)
+#@@ -114,9 +112,10 @@ def accept_and_read():
+#             client.close()
+# 
+#         server.join()
+#+        assert not server.is_alive()
+#         if match_data is None:
+#             match_data = self.long_data
+#-        self.assertEqual(read_data[0], match_data)
+#+        self.assertEqual(read_data, [match_data])
+# 
+#         if server_exc_info:
+#             six.reraise(*server_exc_info[0])
+#
+From 271e58658f7cc839dcde74239c66d1d396d675b7 Mon Sep 17 00:00:00 2001
+From: Jason Madden <jamadden at gmail.com>
+Date: Sat, 7 Sep 2019 09:02:12 -0500
+Subject: [PATCH 8/9] Whoops, fix Python 2.
+
+---
+ src/gevent/tests/test__greenness.py | 23 +++++++++++++----------
+ src/gevent/tests/test__socket.py    | 13 ++++++++-----
+ src/gevent/tests/test__ssl.py       |  3 ++-
+ 3 files changed, 23 insertions(+), 16 deletions(-)
+
+diff --git a/src/gevent/tests/test__greenness.py b/src/gevent/tests/test__greenness.py
+index da4fc948e..71392971f 100644
+--- a/src/gevent/tests/test__greenness.py
++++ b/src/gevent/tests/test__greenness.py
+@@ -29,13 +29,15 @@
+ import gevent.testing as greentest
+ 
+ try:
+-    import urllib2
+-except ImportError:
+     from urllib import request as urllib2
+-try:
+-    import BaseHTTPServer
+-except ImportError:
+     from http import server as BaseHTTPServer
++    from http.server import SimpleHTTPRequestHandler
++except ImportError:
++    # Python 2
++    import urllib2
++    import BaseHTTPServer
++    from SimpleHTTPServer import SimpleHTTPRequestHandler
++
+ 
+ import gevent
+ from gevent.testing import params
+@@ -47,7 +49,8 @@ class TestGreenness(greentest.TestCase):
+     def setUp(self):
+         server_address = params.DEFAULT_BIND_ADDR_TUPLE
+         BaseHTTPServer.BaseHTTPRequestHandler.protocol_version = "HTTP/1.0"
+-        self.httpd = BaseHTTPServer.HTTPServer(server_address, BaseHTTPServer.BaseHTTPRequestHandler)
++        self.httpd = BaseHTTPServer.HTTPServer(server_address,
++                                               SimpleHTTPRequestHandler)
+         self.httpd.request_count = 0
+ 
+     def tearDown(self):
+@@ -62,10 +65,10 @@ def test_urllib2(self):
+         server = gevent.spawn(self.serve)
+ 
+         port = self.httpd.socket.getsockname()[1]
+-        with self.assertRaises(urllib2.HTTPError) as exc:
+-            urllib2.urlopen('http://127.0.0.1:%s' % port)
+-        self.assertEqual(exc.exception.code, 501)
+-        server.get(0.01)
++        rsp = urllib2.urlopen('http://127.0.0.1:%s' % port)
++        rsp.read()
++        rsp.close()
++        server.join()
+         self.assertEqual(self.httpd.request_count, 1)
+ 
+ 
+#diff --git a/src/gevent/tests/test__socket.py b/src/gevent/tests/test__socket.py
+#index 4a670cdb0..195ef1af5 100644
+#--- a/src/gevent/tests/test__socket.py
+#+++ b/src/gevent/tests/test__socket.py
+#@@ -9,7 +9,7 @@
+# import unittest
+# from functools import wraps
+# 
+#-from gevent import get_hub
+#+from gevent import getcurrent
+# import gevent.testing as greentest
+# 
+# from gevent.testing import six
+#@@ -34,7 +34,7 @@ def errors_are_fatal(*args, **kwargs):
+#             try:
+#                 return target(*args, **kwargs)
+#             except: # pylint:disable=bare-except
+#-                get_hub().throw(*sys.exc_info())
+#+                getcurrent().parent.throw(*sys.exc_info())
+# 
+#         _Thread.__init__(self, target=errors_are_fatal, **kwargs)
+#         self.start()
+#@@ -95,13 +95,16 @@ def accept_and_read():
+#                 conn, _ = self.listener.accept()
+#                 r = conn.makefile(mode='rb')
+#                 read_data.append(r.read())
+#-                r.flush()
+#-                r.close()
+#             finally:
+#-                for f in (conn, r, self.listener):
+#+                # Order matters. On Python 2, if we close the
+#+                # connection before closing the makefile,
+#+                # test__ssl fails because the underlying socket
+#+                # has been deleted.
+#+                for f in (r, conn, self.listener):
+#                     if f is not None:
+#                         f.close()
+# 
+#+
+#         server = Thread(target=accept_and_read)
+#         client = self.create_connection(**client_args)
+# 
+#diff --git a/src/gevent/tests/test__ssl.py b/src/gevent/tests/test__ssl.py
+#index 97b70bd98..537e70773 100644
+#--- a/src/gevent/tests/test__ssl.py
+#+++ b/src/gevent/tests/test__ssl.py
+#@@ -1,3 +1,4 @@
+#+from __future__ import print_function, division, absolute_import
+# from gevent import monkey; monkey.patch_all()
+# import os
+# 
+#@@ -5,7 +6,7 @@
+# import gevent.testing as greentest
+# # Be careful not to have TestTCP as a bare attribute in this module,
+# # even aliased, to avoid running duplicate tests
+#-import test__socket
+#+from gevent.tests import test__socket
+# import ssl
+# 
+# 
+#
+From 158ccf26ff07af1c0737307f67ed118e7a1d6ac1 Mon Sep 17 00:00:00 2001
+From: Jason Madden <jamadden at gmail.com>
+Date: Sat, 7 Sep 2019 09:27:19 -0500
+Subject: [PATCH 9/9] Implement verify_client_post_handshake; appveyor has TLS
+ 1.3 now so those tests are running there.
+
+---
+ CHANGES.rst                        | 2 ++
+ src/gevent/_ssl3.py                | 5 +++++
+ src/gevent/tests/known_failures.py | 9 +++++++++
+ src/gevent/tests/test__socket.py   | 3 ++-
+ 4 files changed, 18 insertions(+), 1 deletion(-)
+
+#diff --git a/CHANGES.rst b/CHANGES.rst
+#index 53f4398d2..a4ab7a7ab 100644
+#--- a/CHANGES.rst
+#+++ b/CHANGES.rst
+#@@ -16,6 +16,8 @@
+# 
+# - Improve the way joining the main thread works on Python 3.
+# 
+#+- Implement ``SSLSocket.verify_client_post_handshake()`` when available.
+#+
+# 1.5a1 (2019-05-02)
+# ==================
+# 
+diff --git a/src/gevent/_ssl3.py b/src/gevent/_ssl3.py
+index d3de81034..29988cff0 100644
+--- a/src/gevent/_ssl3.py
++++ b/src/gevent/_ssl3.py
+@@ -678,6 +678,11 @@ def get_channel_binding(self, cb_type="tls-unique"):
+             return None
+         return self._sslobj.tls_unique_cb()
+ 
++    def verify_client_post_handshake(self):
++        # Only present in 3.7.1+; an attributeerror is alright
++        if self._sslobj:
++            return self._sslobj.verify_client_post_handshake()
++        raise ValueError("No SSL wrapper around " + str(self))
+ 
+ # Python does not support forward declaration of types
+ SSLContext.sslsocket_class = SSLSocket
+diff --git a/src/gevent/tests/known_failures.py b/src/gevent/tests/known_failures.py
+index eb1db0da1..d5f38ba91 100644
+--- a/src/gevent/tests/known_failures.py
++++ b/src/gevent/tests/known_failures.py
+@@ -351,6 +351,15 @@
+     'test__example_webproxy.py',
+ ]
+ 
++if APPVEYOR:
++    # Strange failures sometimes, but only on Python 3.7, reporting
++    # "ConnectionAbortedError: [WinError 10053] An established
++    # connection was aborted by the software in your host machine"
++    # when we've done no such thing. Try running not in parallel
++    RUN_ALONE += [
++        'test__ssl.py',
++        'test__server.py',
++    ]
+ 
+ 
+ if APPVEYOR or TRAVIS:
+#diff --git a/src/gevent/tests/test__socket.py b/src/gevent/tests/test__socket.py
+#index 195ef1af5..4976d5767 100644
+#--- a/src/gevent/tests/test__socket.py
+#+++ b/src/gevent/tests/test__socket.py
+#@@ -29,12 +29,13 @@ class Thread(_Thread):
+# 
+#     def __init__(self, **kwargs):
+#         target = kwargs.pop('target')
+#+        caller = getcurrent()
+#         @wraps(target)
+#         def errors_are_fatal(*args, **kwargs):
+#             try:
+#                 return target(*args, **kwargs)
+#             except: # pylint:disable=bare-except
+#-                getcurrent().parent.throw(*sys.exc_info())
+#+                caller.throw(*sys.exc_info())
+# 
+#         _Thread.__init__(self, target=errors_are_fatal, **kwargs)
+#         self.start()
+--- gevent-1.4.0/src/gevent/thread.py.orig	2019-01-04 12:51:44.000000000 +0100
++++ gevent-1.4.0/src/gevent/thread.py	2020-01-03 21:14:08.922889769 +0100
+@@ -31,6 +31,8 @@
+                     'exit_thread',
+                     'interrupt_main',
+                     'start_new']
++    if sys.version_info[:2] >= (3, 8):
++        __imports__.append('get_native_id')
+ error = __thread__.error
+ from gevent._compat import PY3
+ from gevent._compat import PYPY
+--- gevent-1.4.0/src/gevent/_tblib.py.orig	2019-01-04 12:51:44.000000000 +0100
++++ gevent-1.4.0/src/gevent/_tblib.py	2020-01-03 21:25:28.152543399 +0100
+@@ -198,6 +198,9 @@
+         while current:
+             f_code = current.tb_frame.f_code
+             code = compile('\n' * (current.tb_lineno - 1) + 'raise __traceback_maker', current.tb_frame.f_code.co_filename, 'exec')
+-            if PY3:
++            if hasattr(code, "replace"):
++                # Python 3.8 and newer
++                code = code.replace(co_argcount=0, co_freevars=(), co_cellvars=())
++            elif PY3:
+                 code = CodeType(
+                     0, code.co_kwonlyargcount,
+--- gevent-1.4.0/src/gevent/_socketcommon.py.orig	2019-01-04 12:51:44.000000000 +0100
++++ gevent-1.4.0/src/gevent/_socketcommon.py	2020-01-06 15:00:51.236688228 +0100
+@@ -74,6 +74,12 @@
+ from gevent._compat import string_types, integer_types, PY3
+ from gevent._util import copy_globals
+ 
++if sys.version_info[:2] >= (3, 8):
++    __imports__.extend([
++        'create_server',
++        'has_dualstack_ipv6'
++    ])
++
+ is_windows = sys.platform == 'win32'
+ is_macos = sys.platform == 'darwin'
+ 
diff --git a/python-gevent-tests.patch b/python-gevent-tests.patch
deleted file mode 100644
index 04a07c3..0000000
--- a/python-gevent-tests.patch
+++ /dev/null
@@ -1,16 +0,0 @@
---- gevent-1.2.1/src/greentest/test__doctests.py.orig	2017-01-12 14:15:25.000000000 +0100
-+++ gevent-1.2.1/src/greentest/test__doctests.py	2017-03-14 22:18:48.660258016 +0100
-@@ -68,9 +68,12 @@
-             # 'cannot access'
-             (re.compile('cannot access non_existent_file: No such file or directory'),
-              'non_existent_file: No such file or directory'),
-+            (re.compile("cannot access 'non_existent_file': No such file or directory"),
-+             'non_existent_file: No such file or directory'),
-             # Python 3 bytes add a "b".
-             (re.compile(r'b(".*?")'), r"\1"),
-             (re.compile(r"b('.*?')"), r"\1"),
-+            (re.compile(r'^"(.*?)"$'), r"'\1'"),
-         ))
- 
-         tests_count = 0
-
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/python-gevent.git/commitdiff/5a03dc88f04635646a475c56095a5f1e5ee912b6



More information about the pld-cvs-commit mailing list