From 6cd9667e61e7f062c2a87cae9157cd4aaaa6757e Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 6 Jan 2020 12:44:30 -0500 Subject: [PATCH 01/14] Update testing etc for Python 3.8 --- .travis.yml | 3 +++ appveyor.yml | 6 ++++++ setup.py | 1 + tox.ini | 4 ++-- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 19c1151..2b60db6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,9 @@ matrix: - python: 3.7 dist: xenial sudo: true + - python: 3.8 + dist: xenial + sudo: true addons: apt: diff --git a/appveyor.yml b/appveyor.yml index fafa493..e3d8c0b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,6 +26,12 @@ environment: - TOXENV: py37-defaultreactor, win-py37-qt5reactor, py37-asyncioreactor PYTHON: "C:\\Python37-x64" + - TOXENV: py38-defaultreactor, win-py38-qt5reactor, py38-asyncioreactor + PYTHON: "C:\\Python37" + + - TOXENV: py38-defaultreactor, win-py38-qt5reactor, py38-asyncioreactor + PYTHON: "C:\\Python38-x64" + install: # https://github.com/pypa/virtualenv/issues/1050 - pip install -U git+https://github.com/pypa/virtualenv@e8163e83a92c9098f51d390289323232ece15e3b diff --git a/setup.py b/setup.py index 07249fc..5d37155 100755 --- a/setup.py +++ b/setup.py @@ -28,6 +28,7 @@ "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", ], entry_points={"pytest11": ["twisted = pytest_twisted"]}, ) diff --git a/tox.ini b/tox.ini index 112417c..a17e65f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,8 @@ [tox] envlist= py{27,35}-defaultreactor - py{35,36,37}-{default,qt5,asyncio}reactor - win-py{35,36,37}-qt5reactor + py{35,36,37,38}-{default,qt5,asyncio}reactor + win-py{35,36,37,38}-qt5reactor linting [testenv] From 33a1d1a00be1d57ec7383c5b35f9a6dd9ecd9a40 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 17 Feb 2020 19:37:35 -0500 Subject: [PATCH 02/14] Update appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index e3d8c0b..00502fa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,7 +27,7 @@ environment: PYTHON: "C:\\Python37-x64" - TOXENV: py38-defaultreactor, win-py38-qt5reactor, py38-asyncioreactor - PYTHON: "C:\\Python37" + PYTHON: "C:\\Python38" - TOXENV: py38-defaultreactor, win-py38-qt5reactor, py38-asyncioreactor PYTHON: "C:\\Python38-x64" From c6eff3da4433f7e220190475bbe7a91af2f96fda Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 17 Feb 2020 20:42:00 -0500 Subject: [PATCH 03/14] Use asyncio.WindowsSelectorEventLoopPolicy for 3.8+ https://twistedmatrix.com/trac/ticket/9766 --- pytest_twisted.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pytest_twisted.py b/pytest_twisted.py index 1046cd2..9ee0e63 100644 --- a/pytest_twisted.py +++ b/pytest_twisted.py @@ -272,6 +272,12 @@ def init_qt5_reactor(): def init_asyncio_reactor(): + if sys.version_info >= (3, 8): + # If twisted releases a fix/workaround we can check that version too + # https://twistedmatrix.com/trac/ticket/9766 + selector_policy = asyncio.WindowsSelectorEventLoopPolicy() + asyncio.set_event_loop_policy(selector_policy) + from twisted.internet import asyncioreactor _install_reactor( From adb46b6315da2eccc973200f0d5d2b9c0c2ff670 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 17 Feb 2020 20:54:49 -0500 Subject: [PATCH 04/14] Update pytest_twisted.py --- pytest_twisted.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pytest_twisted.py b/pytest_twisted.py index 9ee0e63..94823fc 100644 --- a/pytest_twisted.py +++ b/pytest_twisted.py @@ -272,11 +272,12 @@ def init_qt5_reactor(): def init_asyncio_reactor(): - if sys.version_info >= (3, 8): - # If twisted releases a fix/workaround we can check that version too - # https://twistedmatrix.com/trac/ticket/9766 - selector_policy = asyncio.WindowsSelectorEventLoopPolicy() - asyncio.set_event_loop_policy(selector_policy) + if sys.platform == 'win32': + if sys.version_info >= (3, 8): + # If twisted releases a fix/workaround we can check that version too + # https://twistedmatrix.com/trac/ticket/9766 + selector_policy = asyncio.WindowsSelectorEventLoopPolicy() + asyncio.set_event_loop_policy(selector_policy) from twisted.internet import asyncioreactor From d5f5bf81a991cc838cafce0e4661e2142791be94 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 17 Feb 2020 21:30:21 -0500 Subject: [PATCH 05/14] Update pytest_twisted.py --- pytest_twisted.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pytest_twisted.py b/pytest_twisted.py index 94823fc..38e7ebf 100644 --- a/pytest_twisted.py +++ b/pytest_twisted.py @@ -1,5 +1,6 @@ import functools import inspect +import sys import warnings import decorator From 84fd4073314477c20223987ae942ffbbc2a7bfdd Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 17 Feb 2020 22:05:50 -0500 Subject: [PATCH 06/14] Update pytest_twisted.py --- pytest_twisted.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pytest_twisted.py b/pytest_twisted.py index 38e7ebf..99bf313 100644 --- a/pytest_twisted.py +++ b/pytest_twisted.py @@ -277,6 +277,8 @@ def init_asyncio_reactor(): if sys.version_info >= (3, 8): # If twisted releases a fix/workaround we can check that version too # https://twistedmatrix.com/trac/ticket/9766 + import asyncio + selector_policy = asyncio.WindowsSelectorEventLoopPolicy() asyncio.set_event_loop_policy(selector_policy) From 08bc0175fd81cb5d15cd5d11beb6755211374e44 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 18 Feb 2020 15:29:55 -0500 Subject: [PATCH 07/14] remove asyncio.WindowsSelectorEventLoopPolicy attempt --- pytest_twisted.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pytest_twisted.py b/pytest_twisted.py index e2046e3..b1405a8 100644 --- a/pytest_twisted.py +++ b/pytest_twisted.py @@ -1,6 +1,5 @@ import functools import inspect -import sys import warnings import decorator @@ -273,15 +272,6 @@ def init_qt5_reactor(): def init_asyncio_reactor(): - if sys.platform == 'win32': - if sys.version_info >= (3, 8): - # If twisted releases a fix/workaround we can check that version too - # https://twistedmatrix.com/trac/ticket/9766 - import asyncio - - selector_policy = asyncio.WindowsSelectorEventLoopPolicy() - asyncio.set_event_loop_policy(selector_policy) - from twisted.internet import asyncioreactor _install_reactor( From 277a4e9d47f44849f13fe99a53a44a34360aaf1f Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 18 Feb 2020 15:44:06 -0500 Subject: [PATCH 08/14] Use asyncio.WindowsSelectorEventLoopPolicy() for applicable tests https://twistedmatrix.com/trac/ticket/9766 --- testing/conftest.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/testing/conftest.py b/testing/conftest.py index f0f92c2..cbd47bc 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -1 +1,20 @@ +import sys + +import pytest + + pytest_plugins = "_pytest.pytester" + + +@pytest.hookimpl(tryfirst=True) +def pytest_configure(config): + if ( + config.getoption("reactor") == 'asyncio' + and sys.platform == 'win32' + and sys.version_info >= (3, 8) + ): + # https://twistedmatrix.com/trac/ticket/9766 + import asyncio + + selector_policy = asyncio.WindowsSelectorEventLoopPolicy() + asyncio.set_event_loop_policy(selector_policy) From c0c9a1549c92fdee66cd0ab7e20c639d97fa5d1e Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 18 Feb 2020 18:56:18 -0800 Subject: [PATCH 09/14] Trying again for asyncio on windows on py38 --- pytest_twisted.py | 15 +++++++++++++++ testing/conftest.py | 14 ++------------ testing/test_basic.py | 25 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/pytest_twisted.py b/pytest_twisted.py index b1405a8..e1d730c 100644 --- a/pytest_twisted.py +++ b/pytest_twisted.py @@ -1,5 +1,6 @@ import functools import inspect +import sys import warnings import decorator @@ -326,3 +327,17 @@ def pytest_configure(config): )(blockon) reactor_installers[config.getoption("reactor")]() + + +def use_asyncio_selector_if_required(config): + # https://twistedmatrix.com/trac/ticket/9766 + + if ( + config.getoption("reactor", "default") == "asyncio" + and sys.platform == 'win32' + and sys.version_info >= (3, 8) + ): + import asyncio + + selector_policy = asyncio.WindowsSelectorEventLoopPolicy() + asyncio.set_event_loop_policy(selector_policy) \ No newline at end of file diff --git a/testing/conftest.py b/testing/conftest.py index cbd47bc..b09bece 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -1,6 +1,5 @@ -import sys - import pytest +import pytest_twisted pytest_plugins = "_pytest.pytester" @@ -8,13 +7,4 @@ @pytest.hookimpl(tryfirst=True) def pytest_configure(config): - if ( - config.getoption("reactor") == 'asyncio' - and sys.platform == 'win32' - and sys.version_info >= (3, 8) - ): - # https://twistedmatrix.com/trac/ticket/9766 - import asyncio - - selector_policy = asyncio.WindowsSelectorEventLoopPolicy() - asyncio.set_event_loop_policy(selector_policy) + pytest_twisted.use_asyncio_selector_if_required(config=config) diff --git a/testing/test_basic.py b/testing/test_basic.py index 478345a..3ddba16 100755 --- a/testing/test_basic.py +++ b/testing/test_basic.py @@ -49,6 +49,19 @@ def format_run_result_output_for_assert(run_result): ) +@pytest.fixture(name="default_conftest", autouse=True) +def _default_conftest(testdir): + testdir.makeconftest(textwrap.dedent(""" + import pytest + import pytest_twisted + + + @pytest.hookimpl(tryfirst=True) + def pytest_configure(config): + pytest_twisted.use_asyncio_selector_if_required(config=config) + """)) + + def skip_if_reactor_not(request, expected_reactor): actual_reactor = request.config.getoption("reactor", "default") if actual_reactor != expected_reactor: @@ -627,10 +640,14 @@ def main(): def test_blockon_in_hook_with_asyncio(testdir, cmd_opts, request): skip_if_reactor_not(request, "asyncio") conftest_file = """ + import pytest import pytest_twisted as pt from twisted.internet import defer + @pytest.hookimpl(tryfirst=True) def pytest_configure(config): + pt.use_asyncio_selector_if_required(config=config) + pt.init_asyncio_reactor() d = defer.Deferred() @@ -656,6 +673,14 @@ def test_succeed(): def test_wrong_reactor_with_asyncio(testdir, cmd_opts, request): skip_if_reactor_not(request, "asyncio") conftest_file = """ + import pytest + import pytest_twisted + + + @pytest.hookimpl(tryfirst=True) + def pytest_configure(config): + pytest_twisted.use_asyncio_selector_if_required(config=config) + def pytest_addhooks(): import twisted.internet.default twisted.internet.default.install() From 5e84a28e2a2c4c23fda579159acb933e6dca60ae Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 19 Feb 2020 12:55:14 -0500 Subject: [PATCH 10/14] add missing trailing newline --- pytest_twisted.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_twisted.py b/pytest_twisted.py index e1d730c..932ef66 100644 --- a/pytest_twisted.py +++ b/pytest_twisted.py @@ -340,4 +340,4 @@ def use_asyncio_selector_if_required(config): import asyncio selector_policy = asyncio.WindowsSelectorEventLoopPolicy() - asyncio.set_event_loop_policy(selector_policy) \ No newline at end of file + asyncio.set_event_loop_policy(selector_policy) From 0bdf55271ceb8123e09177caa6bdab3aa2abb4bb Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 19 Feb 2020 16:54:22 -0500 Subject: [PATCH 11/14] Add notes about py3.8/asyncio/proactor to readme --- README.rst | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.rst b/README.rst index 7b1a5d3..b31d64d 100644 --- a/README.rst +++ b/README.rst @@ -18,6 +18,47 @@ which uses the twisted framework. test functions can return Deferred objects and pytest will wait for their completion with this plugin. +NOTICE: Python 3.8 with asyncio support +======================================= + +In Python 3.8, asyncio changed the default loop implementation to use +their proactor. The proactor does not implement some methods used by +Twisted's asyncio support. The result is a ``NotImplementedError`` +exception such as below. + +.. code-block:: pytb + + + File "c:\projects\pytest-twisted\.tox\py38-asyncioreactor\lib\site-packages\twisted\internet\asyncioreactor.py", line 320, in install + reactor = AsyncioSelectorReactor(eventloop) + File "c:\projects\pytest-twisted\.tox\py38-asyncioreactor\lib\site-packages\twisted\internet\asyncioreactor.py", line 69, in __init__ + super().__init__() + File "c:\projects\pytest-twisted\.tox\py38-asyncioreactor\lib\site-packages\twisted\internet\base.py", line 571, in __init__ + self.installWaker() + File "c:\projects\pytest-twisted\.tox\py38-asyncioreactor\lib\site-packages\twisted\internet\posixbase.py", line 286, in installWaker + self.addReader(self.waker) + File "c:\projects\pytest-twisted\.tox\py38-asyncioreactor\lib\site-packages\twisted\internet\asyncioreactor.py", line 151, in addReader + self._asyncioEventloop.add_reader(fd, callWithLogger, reader, + File "C:\Python38-x64\Lib\asyncio\events.py", line 501, in add_reader + raise NotImplementedError + NotImplementedError + +The previous default, the selector loop, still works but you have to +explicitly set it. ``pytest_twisted.use_asyncio_selector_if_required()`` +is provided to help in choosing the selector loop. It must be called +early so the following `conftest.py` is suggested. + +.. code-block:: python3 + + import pytest + import pytest_twisted + + + @pytest.hookimpl(tryfirst=True) + def pytest_configure(config): + pytest_twisted.use_asyncio_selector_if_required(config=config) + + Python 2 support plans ====================== From 41ba6e238b7afe2bc7b44cd2f12fa4146c509dff Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 19 Feb 2020 17:05:44 -0500 Subject: [PATCH 12/14] Make the proactor helper _private for now --- README.rst | 20 ++++++++++++++++---- pytest_twisted.py | 3 ++- testing/conftest.py | 2 +- testing/test_basic.py | 6 +++--- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index b31d64d..76d8c24 100644 --- a/README.rst +++ b/README.rst @@ -44,19 +44,31 @@ exception such as below. NotImplementedError The previous default, the selector loop, still works but you have to -explicitly set it. ``pytest_twisted.use_asyncio_selector_if_required()`` -is provided to help in choosing the selector loop. It must be called -early so the following `conftest.py` is suggested. +explicitly set it and do so early. The following ``conftest.py`` is provided +for reference. .. code-block:: python3 + import sys + import pytest import pytest_twisted @pytest.hookimpl(tryfirst=True) def pytest_configure(config): - pytest_twisted.use_asyncio_selector_if_required(config=config) + # https://twistedmatrix.com/trac/ticket/9766 + # https://github.com/pytest-dev/pytest-twisted/issues/80 + + if ( + config.getoption("reactor", "default") == "asyncio" + and sys.platform == 'win32' + and sys.version_info >= (3, 8) + ): + import asyncio + + selector_policy = asyncio.WindowsSelectorEventLoopPolicy() + asyncio.set_event_loop_policy(selector_policy) Python 2 support plans diff --git a/pytest_twisted.py b/pytest_twisted.py index 932ef66..b2375aa 100644 --- a/pytest_twisted.py +++ b/pytest_twisted.py @@ -329,8 +329,9 @@ def pytest_configure(config): reactor_installers[config.getoption("reactor")]() -def use_asyncio_selector_if_required(config): +def _use_asyncio_selector_if_required(config): # https://twistedmatrix.com/trac/ticket/9766 + # https://github.com/pytest-dev/pytest-twisted/issues/80 if ( config.getoption("reactor", "default") == "asyncio" diff --git a/testing/conftest.py b/testing/conftest.py index b09bece..72dffd2 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -7,4 +7,4 @@ @pytest.hookimpl(tryfirst=True) def pytest_configure(config): - pytest_twisted.use_asyncio_selector_if_required(config=config) + pytest_twisted._use_asyncio_selector_if_required(config=config) diff --git a/testing/test_basic.py b/testing/test_basic.py index 3ddba16..bff360c 100755 --- a/testing/test_basic.py +++ b/testing/test_basic.py @@ -58,7 +58,7 @@ def _default_conftest(testdir): @pytest.hookimpl(tryfirst=True) def pytest_configure(config): - pytest_twisted.use_asyncio_selector_if_required(config=config) + pytest_twisted._use_asyncio_selector_if_required(config=config) """)) @@ -646,7 +646,7 @@ def test_blockon_in_hook_with_asyncio(testdir, cmd_opts, request): @pytest.hookimpl(tryfirst=True) def pytest_configure(config): - pt.use_asyncio_selector_if_required(config=config) + pt._use_asyncio_selector_if_required(config=config) pt.init_asyncio_reactor() d = defer.Deferred() @@ -679,7 +679,7 @@ def test_wrong_reactor_with_asyncio(testdir, cmd_opts, request): @pytest.hookimpl(tryfirst=True) def pytest_configure(config): - pytest_twisted.use_asyncio_selector_if_required(config=config) + pytest_twisted._use_asyncio_selector_if_required(config=config) def pytest_addhooks(): import twisted.internet.default From 22fd7c5ad49d9ad7a662274cfbd040a58654829e Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 19 Feb 2020 17:12:11 -0500 Subject: [PATCH 13/14] Add CPython 3.8 to GitHub Actions --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b781e9..fee322b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,9 @@ jobs: - name: CPython 3.7 tox: py37 action: 3.7 + - name: CPython 3.8 + tox: py38 + action: 3.8 reactor: - name: default tox: default From 44130c8eb68a76e4048876605f8d9c4512c0cc65 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 19 Feb 2020 17:16:01 -0500 Subject: [PATCH 14/14] remove whitespace from blank lines --- testing/test_basic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/test_basic.py b/testing/test_basic.py index 475c5d5..9afbc4c 100755 --- a/testing/test_basic.py +++ b/testing/test_basic.py @@ -678,8 +678,8 @@ def test_wrong_reactor_with_asyncio(testdir, cmd_opts, request): conftest_file = """ import pytest import pytest_twisted - - + + @pytest.hookimpl(tryfirst=True) def pytest_configure(config): pytest_twisted._use_asyncio_selector_if_required(config=config)