From 482f0833884fe490d50eb03a08eebfb19e9ed46d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Sat, 4 Jan 2020 23:59:54 +0100 Subject: [PATCH 1/2] Python 3.9 compatibility Thread.isAlive() is deprecated in 3.8 and removed in 3.9: $ python3.8 -c 'import threading; t = threading.Thread(); t.isAlive()' :1: DeprecationWarning: isAlive() is deprecated, use is_alive() instead $ python3.9 -c 'import threading; t = threading.Thread(); t.isAlive()' Traceback (most recent call last): File "", line 1, in AttributeError: 'Thread' object has no attribute 'isAlive' Fixes https://github.com/micheles/decorator/issues/75 --- src/tests/documentation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/documentation.py b/src/tests/documentation.py index 2888ea1..bd3367c 100644 --- a/src/tests/documentation.py +++ b/src/tests/documentation.py @@ -1531,7 +1531,7 @@ def set_result(): f.thread = threading.Thread(None, set_result) f.thread.start() return msg - elif f.thread.isAlive(): + elif f.thread.is_alive(): return msg else: # the thread is ended, return the stored result del f.thread From 89907e760bdc32c3a6e5169015ded485b4d992fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Sun, 5 Jan 2020 00:13:52 +0100 Subject: [PATCH 2/2] On Python 3.9, we cannot longer avoid using collections.abc Related to https://github.com/micheles/decorator/issues/75#issuecomment-570827328 --- docs/documentation.md | 35 +++++++++++++++++---------------- src/tests/documentation.py | 40 ++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/tests/documentation.py b/src/tests/documentation.py index bd3367c..60a37a2 100644 --- a/src/tests/documentation.py +++ b/src/tests/documentation.py @@ -9,6 +9,7 @@ import collections.abc as c except ImportError: c = collections + collections.abc = collections from decorator import (decorator, decorate, FunctionMaker, contextmanager, dispatch_on, __version__) @@ -1008,15 +1009,16 @@ def coro_to_func(coro, *args, **kw): $$WithLength This class defines a ``__len__`` method, and is therefore -considered to be a subclass of the abstract base class ``collections.Sized``: +considered to be a subclass of the abstract base class +``collections.abc.Sized`` (``collections.Sized`` on Python 2): ```python ->>> issubclass(WithLength, collections.Sized) +>>> issubclass(WithLength, collections.abc.Sized) True ``` -However, ``collections.Sized`` is not in the MRO_ of ``WithLength``; it +However, ``collections.abc.Sized`` is not in the MRO_ of ``WithLength``; it is not a true ancestor. Any implementation of generic functions (even with single dispatch) must go through some contorsion to take into account the virtual ancestors. @@ -1037,7 +1039,7 @@ def coro_to_func(coro, *args, **kw): ``` -...even if ``collections.Sized`` is not a true ancestor of ``WithLength``. +...even if ``collections.abc.Sized`` is not a true ancestor of ``WithLength``. Of course, this is a contrived example--you could just use the builtin ``len``--but you should get the idea. @@ -1053,14 +1055,14 @@ def coro_to_func(coro, *args, **kw): $$SomeSet Here, the author of ``SomeSet`` made a mistake by inheriting from -``collections.Sized`` (instead of ``collections.Set``). +``collections.abc.Sized`` (instead of ``collections.abc.Set``). This is not a problem. You can register *a posteriori* -``collections.Set`` as a virtual ancestor of ``SomeSet``: +``collections.abc.Set`` as a virtual ancestor of ``SomeSet``: ```python ->>> _ = collections.Set.register(SomeSet) ->>> issubclass(SomeSet, collections.Set) +>>> _ = collections.abc.Set.register(SomeSet) +>>> issubclass(SomeSet, collections.abc.Set) True ``` @@ -1080,10 +1082,10 @@ def coro_to_func(coro, *args, **kw): ``` Sometimes it is not clear how to dispatch. For instance, consider a -class ``C`` registered both as ``collections.Iterable`` and -``collections.Sized``, and defines a generic function ``g`` with -implementations for both ``collections.Iterable`` *and* -``collections.Sized``: +class ``C`` registered both as ``collections.abc.Iterable`` and +``collections.abc.Sized``, and defines a generic function ``g`` with +implementations for both ``collections.abc.Iterable`` *and* +``collections.abc.Sized``: $$singledispatch_example1 @@ -1784,7 +1786,7 @@ def __len__(self): return 0 -class SomeSet(collections.Sized): +class SomeSet(collections.abc.Sized): # methods that make SomeSet set-like # not shown ... def __len__(self): @@ -1796,12 +1798,12 @@ def get_length(obj): raise NotImplementedError(type(obj)) -@get_length.register(collections.Sized) +@get_length.register(collections.abc.Sized) def get_length_sized(obj): return len(obj) -@get_length.register(collections.Set) +@get_length.register(collections.abc.Set) def get_length_set(obj): return 1 @@ -1810,8 +1812,8 @@ class C(object): "Registered as Sized and Iterable" -collections.Sized.register(C) -collections.Iterable.register(C) +collections.abc.Sized.register(C) +collections.abc.Iterable.register(C) def singledispatch_example1(): @@ -1821,11 +1823,11 @@ def singledispatch_example1(): def g(obj): raise NotImplementedError(type(g)) - @g.register(collections.Sized) + @g.register(collections.abc.Sized) def g_sized(object): return "sized" - @g.register(collections.Iterable) + @g.register(collections.abc.Iterable) def g_iterable(object): return "iterable"