From c254101aba7573667a4a2e0ae8942b11e4461b56 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 15:36:39 -0400 Subject: [PATCH 01/13] Modernize --- .github/workflows/ci.yml | 17 +++++------------ tox.ini | 9 ++++----- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 991e68d..5daf946 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,22 +13,15 @@ jobs: name: "Python ${{ matrix.python-version }} ${{ matrix.platform }} ${{ matrix.architecture }}" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10-dev", "pypy3"] + python-version: ["3.9", "3.10", "3.11", "pypy3"] architecture: ["x64"] - platform: ["ubuntu-latest"] - include: - - python-version: "3.6" - architecture: "x86" - platform: "windows-latest" - - python-version: "3.6" - architecture: "x64" - platform: "windows-latest" + platform: ["ubuntu-latest", "windows-latest"] runs-on: "${{ matrix.platform }}" steps: - - uses: "actions/checkout@v2" - - uses: "actions/setup-python@v2" + - uses: "actions/checkout@v4" + - uses: "actions/setup-python@v4" with: python-version: "${{ matrix.python-version }}" architecture: "${{ matrix.architecture }}" @@ -37,7 +30,7 @@ jobs: python -VV python -m site python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade virtualenv tox tox-gh-actions + python -m pip install --upgrade virtualenv tox tox-gh-actions - name: "Run tox targets for ${{ matrix.python-version }}" run: "python -m tox" diff --git a/tox.ini b/tox.ini index 2927a00..586ff3d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,18 +1,17 @@ [tox] -envlist = lint3,{py36,py37,pypy3,py38,py39,py310} +envlist = lint3,{pypy3,py38,py39,py310,py311} [gh-actions] python = - 3.6: py36-twisted-16,py36 - 3.7: py37-twisted-16,py37 3.8: py38 3.9: py39,lint3 - 3.10-dev: py310 + 3.10: py310 + 3.11: py311 pypy3: pypy3 [testenv] deps = - py36,py37,py38,py39: mypy==0.812 + mypy commands = {envpython} setup.py --version pip install . From 91fc55c244f44dd4bcf60740e66076f6d4efbc24 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 15:37:53 -0400 Subject: [PATCH 02/13] Change minimum version --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 3907c59..550f669 100644 --- a/setup.py +++ b/setup.py @@ -20,10 +20,10 @@ def read(path): 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', ], @@ -31,7 +31,7 @@ def read(path): version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass(), description="Use Twisted anywhere!", - python_requires=">=3.6.0", + python_requires=">=3.8.0", install_requires=[ "Twisted>=16.0", "wrapt", From 7bcdf1cb248747246f803e83f77ee2245ff8db7f Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 15:38:22 -0400 Subject: [PATCH 03/13] No longer supporting old Python --- README.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 2942646..15c1632 100644 --- a/README.rst +++ b/README.rst @@ -37,8 +37,7 @@ Bugs and feature requests should be filed at the project `Github page`_. API and features ================ -Crochet supports Python 3.6, 3.7, 3.8, and 3.9 as well as PyPy3. -Python 2.7 and 3.5 support is available in older releases. +Crochet supports Python 3.8, 3.9, 3.10, and 3.11 as well as PyPy3. Crochet provides the following basic APIs: From a06a5ba90fb3fde4026fa7f141e9ed9b9b3783f1 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 15:56:22 -0400 Subject: [PATCH 04/13] Modernize logging --- crochet/_eventloop.py | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/crochet/_eventloop.py b/crochet/_eventloop.py index fb3f149..0c7bf17 100644 --- a/crochet/_eventloop.py +++ b/crochet/_eventloop.py @@ -10,6 +10,7 @@ import warnings from inspect import iscoroutinefunction from functools import wraps +from queue import SimpleQueue from twisted.python import threadable from twisted.python.runtime import platform @@ -227,30 +228,20 @@ def original_failure(self): return None +_STOP = object() + + class ThreadLogObserver(object): """ A log observer that wraps another observer, and calls it in a thread. In particular, used to wrap PythonLoggingObserver, so that blocking logging.py Handlers don't block the event loop. - - Once Python 3.6 support is dropped, this can use a queue.SimpleQueue object - instead of a whole 'nother event loop. """ def __init__(self, observer): self._observer = observer - if getattr(select, "epoll", None): - from twisted.internet.epollreactor import EPollReactor - reactorFactory = EPollReactor - elif getattr(select, "poll", None): - from twisted.internet.pollreactor import PollReactor - reactorFactory = PollReactor - else: - from twisted.internet.selectreactor import SelectReactor - reactorFactory = SelectReactor - self._logWritingReactor = reactorFactory() - self._logWritingReactor._registerAsIOThread = False + self._queue = SimpleQueue() self._thread = threading.Thread( target=self._reader, name="CrochetLogWriter") self._thread.start() @@ -260,28 +251,28 @@ def _reader(self): Runs in a thread, reads messages from a queue and writes them to the wrapped observer. """ - self._logWritingReactor.run(installSignalHandlers=False) + while True: + msg = self._queue.get() + if msg is _STOP: + return + try: + self._observer(msg) + except Exception: + # Lower-level logging system blew up, nothing we can do, so + # just drop on the floor. + pass def stop(self): """ Stop the thread. """ - self._logWritingReactor.callFromThread(self._logWritingReactor.stop) + self._queue.put(_STOP) def __call__(self, msg): """ A log observer that writes to a queue. """ - - def log(): - try: - self._observer(msg) - except Exception: - # Lower-level logging system blew up, nothing we can do, so - # just drop on the floor. - pass - - self._logWritingReactor.callFromThread(log) + self._queue.put(msg) class EventLoop(object): From bfb648a3a88ef3b8577920b72dbb4592679ff148 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 15:56:33 -0400 Subject: [PATCH 05/13] Get rid of usage of deprecated module --- crochet/tests/test_api.py | 45 --------------------------------------- 1 file changed, 45 deletions(-) diff --git a/crochet/tests/test_api.py b/crochet/tests/test_api.py index 823c447..bc1a1f2 100644 --- a/crochet/tests/test_api.py +++ b/crochet/tests/test_api.py @@ -12,7 +12,6 @@ import weakref import tempfile import os -import imp import inspect from unittest import SkipTest @@ -525,50 +524,6 @@ def test_noWaitingDuringImport(self): """) self.assertRaises(RuntimeError, __import__, "shouldbeunimportable") - def test_waiting_during_different_thread_importing(self): - """ - EventualResult.wait() should work if called while a module is - being imported in a different thread. See - EventualResultTests.test_noWaitingDuringImport for the explanation of - what should happen if an import is happening in the current thread. - """ - test_complete = threading.Event() - lock_held = threading.Event() - er = EventualResult(succeed(123), None) - - def other_thread(): - imp.acquire_lock() - lock_held.set() - test_complete.wait() - imp.release_lock() - - t = threading.Thread(target=other_thread) - t.start() - lock_held.wait() - - # While the imp lock is held by the other thread, we can't - # allow exceptions/assertions to happen because trial will - # try to do an import causing a deadlock instead of a - # failure. We collect all assertion pairs (result, expected), - # wait for the import lock to be released, and then check our - # assertions at the end of the test. - assertions = [] - - # we want to run .wait while the other thread has the lock acquired - assertions.append((imp.lock_held(), True)) - try: - assertions.append((er.wait(0.1), 123)) - finally: - test_complete.set() - - assertions.append((imp.lock_held(), True)) - - test_complete.set() - - t.join() - - [self.assertEqual(result, expected) for result, expected in assertions] - class RunInReactorTests(TestCase): """ From 5792d00db9a5b3308e697c6c2d190e9d72e96b9f Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 16:01:25 -0400 Subject: [PATCH 06/13] Fix pytest --- crochet/tests/test_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crochet/tests/test_api.py b/crochet/tests/test_api.py index bc1a1f2..62c50fe 100644 --- a/crochet/tests/test_api.py +++ b/crochet/tests/test_api.py @@ -25,7 +25,7 @@ EventLoop, EventualResult, TimeoutError, ResultRegistry, ReactorStopped) from .test_setup import FakeReactor from .. import ( - _main, setup, retrieve_result, _store, no_setup, + _main, setup as setup_crochet, retrieve_result, _store, no_setup, run_in_reactor, wait_for) from ..tests import crochet_directory @@ -1055,7 +1055,7 @@ def test_eventloop_api(self): from twisted.python.log import startLoggingWithObserver from crochet import _shutdown self.assertIsInstance(_main, EventLoop) - self.assertEqual(_main.setup, setup) + self.assertEqual(_main.setup, setup_crochet) self.assertEqual(_main.no_setup, no_setup) self.assertEqual(_main.run_in_reactor, run_in_reactor) self.assertEqual(_main.wait_for, wait_for) From f294d5b819e1ed50b9636e3dd9d5312e4fb8a31e Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 16:02:55 -0400 Subject: [PATCH 07/13] News --- docs/news.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/news.rst b/docs/news.rst index 60593fa..5448c37 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -1,6 +1,12 @@ What's New ========== +2.1.0 +^^^^^ + +* Various internal modernizations and maintenance. +* Dropped Python 3.6 and 3.7 support. + 2.0.0 ^^^^^ From 79c41e219e95dcb9dc61656247cb352c519e40b0 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 16:04:17 -0400 Subject: [PATCH 08/13] Went too far --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5daf946..e5b453c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: runs-on: "${{ matrix.platform }}" steps: - - uses: "actions/checkout@v4" + - uses: "actions/checkout@v3" - uses: "actions/setup-python@v4" with: python-version: "${{ matrix.python-version }}" From df6b15100c921c38cc1fdd6699483c53b2fb67ce Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 16:05:40 -0400 Subject: [PATCH 09/13] Correct PyPy version --- .github/workflows/ci.yml | 3 +-- tox.ini | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5b453c..b4d0bbf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,8 +13,7 @@ jobs: name: "Python ${{ matrix.python-version }} ${{ matrix.platform }} ${{ matrix.architecture }}" strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "pypy3"] - architecture: ["x64"] + python-version: ["3.9", "3.10", "3.11", "pypy3.9"] platform: ["ubuntu-latest", "windows-latest"] runs-on: "${{ matrix.platform }}" diff --git a/tox.ini b/tox.ini index 586ff3d..7053f9c 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,7 @@ python = 3.9: py39,lint3 3.10: py310 3.11: py311 - pypy3: pypy3 + pypy3.9: pypy3 [testenv] deps = From 641311ff4b337cc3cd90207e3e8ff1d55b834b94 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 16:27:40 -0400 Subject: [PATCH 10/13] Fix lint --- crochet/_eventloop.py | 1 - 1 file changed, 1 deletion(-) diff --git a/crochet/_eventloop.py b/crochet/_eventloop.py index 0c7bf17..4d269c0 100644 --- a/crochet/_eventloop.py +++ b/crochet/_eventloop.py @@ -4,7 +4,6 @@ from __future__ import absolute_import -import select import threading import weakref import warnings From 57d96dc1ec9bf875587b826dbf5a056de6a67291 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 16:27:46 -0400 Subject: [PATCH 11/13] Run lint on modern Python --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 7053f9c..1a6bac1 100644 --- a/tox.ini +++ b/tox.ini @@ -4,9 +4,9 @@ envlist = lint3,{pypy3,py38,py39,py310,py311} [gh-actions] python = 3.8: py38 - 3.9: py39,lint3 + 3.9: py39 3.10: py310 - 3.11: py311 + 3.11: py311,lint3 pypy3.9: pypy3 [testenv] From 7198afd27eda1a2c226ca0bdaaf46352368eee2b Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 16:27:58 -0400 Subject: [PATCH 12/13] Not needed --- crochet/_eventloop.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/crochet/_eventloop.py b/crochet/_eventloop.py index 4d269c0..d37476e 100644 --- a/crochet/_eventloop.py +++ b/crochet/_eventloop.py @@ -2,8 +2,6 @@ Expose Twisted's event loop to threaded programs. """ -from __future__ import absolute_import - import threading import weakref import warnings From 520f14f5c0d0f2df7815aa1193468d839dfd37b7 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Sat, 1 Jul 2023 16:33:46 -0400 Subject: [PATCH 13/13] Be a little more lenient --- crochet/tests/test_api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crochet/tests/test_api.py b/crochet/tests/test_api.py index 62c50fe..f5faec3 100644 --- a/crochet/tests/test_api.py +++ b/crochet/tests/test_api.py @@ -206,7 +206,8 @@ def test_timeout(self): start = time.time() dr = EventualResult(Deferred(), None) self.assertRaises(TimeoutError, dr.wait, timeout=0.03) - self.assertTrue(abs(time.time() - start - 0.03) < 0.005) + # be a little lenient for slow computers: + self.assertTrue(abs(time.time() - start) < 0.05) def test_timeout_twice(self): """