From a3ebd21b25c29fe8a871ae53967e0ed3f29be5d4 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 17 Mar 2023 15:30:14 -0400 Subject: [PATCH 1/4] implement retry ourselves, don't depend on tenacity --- setup.py | 1 - src/allmydata/test/test_iputil.py | 55 ++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/setup.py b/setup.py index 82ff45764..152c49f0e 100644 --- a/setup.py +++ b/setup.py @@ -413,7 +413,6 @@ setup(name="tahoe-lafs", # also set in __init__.py "beautifulsoup4", "html5lib", "junitxml", - "tenacity", # Pin old version until # https://github.com/paramiko/paramiko/issues/1961 is fixed. "paramiko < 2.9", diff --git a/src/allmydata/test/test_iputil.py b/src/allmydata/test/test_iputil.py index 081c80ee3..c060fcc04 100644 --- a/src/allmydata/test/test_iputil.py +++ b/src/allmydata/test/test_iputil.py @@ -4,18 +4,14 @@ Tests for allmydata.util.iputil. Ported to Python 3. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -from future.utils import PY2, native_str -if PY2: - from builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401 +from __future__ import annotations import os, socket import gc +from functools import wraps +from typing import TypeVar, Callable +from typing_extensions import TypeAlias from testtools.matchers import ( MatchesAll, IsInstance, @@ -25,8 +21,6 @@ from testtools.matchers import ( from twisted.trial import unittest -from tenacity import retry, stop_after_attempt - from foolscap.api import Tub from allmydata.util import iputil, gcutil @@ -39,6 +33,45 @@ from .common import ( SyncTestCase, ) +T = TypeVar("T") + +TestFunction: TypeAlias = Callable[[], T] +Decorator: TypeAlias = Callable[[TestFunction[T]], TestFunction[T]] + +def retry(stop: Callable[[], bool]) -> Decorator[T]: + """ + Call a function until the predicate says to stop or the function stops + raising an exception. + + :param stop: A callable to call after the decorated function raises an + exception. The decorated function will be called again if ``stop`` + returns ``False``. + + :return: A decorator function. + """ + def decorate(f: TestFunction[T]) -> TestFunction[T]: + @wraps(f) + def decorator(self) -> T: + while True: + try: + return f(self) + except Exception: + if stop(): + raise + return decorator + return decorate + +def stop_after_attempt(limit: int) -> Callable[[], bool]: + """ + Stop after ``limit`` calls. + """ + counter = 0 + def check(): + nonlocal counter + counter += 1 + return counter < limit + return check + class ListenOnUsed(unittest.TestCase): """Tests for listenOnUnused.""" @@ -127,7 +160,7 @@ class GetLocalAddressesSyncTests(SyncTestCase): IsInstance(list), AllMatch( MatchesAll( - IsInstance(native_str), + IsInstance(str), MatchesPredicate( lambda addr: socket.inet_pton(socket.AF_INET, addr), "%r is not an IPv4 address.", From a9f34655686764e633be4a6ccb8f2d79b841a291 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 17 Mar 2023 15:31:07 -0400 Subject: [PATCH 2/4] news fragment --- newsfragments/3989.installation | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/3989.installation diff --git a/newsfragments/3989.installation b/newsfragments/3989.installation new file mode 100644 index 000000000..a2155b65c --- /dev/null +++ b/newsfragments/3989.installation @@ -0,0 +1 @@ +tenacity is no longer a dependency. From 5cf892b441daf77ad5efada4a785dfa4a0e2ecf6 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 17 Mar 2023 15:32:13 -0400 Subject: [PATCH 3/4] Also remove it from the Nix packaging --- nix/tahoe-lafs.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/nix/tahoe-lafs.nix b/nix/tahoe-lafs.nix index 380260c70..5986db420 100644 --- a/nix/tahoe-lafs.nix +++ b/nix/tahoe-lafs.nix @@ -58,7 +58,6 @@ let pytest pytest-timeout pytest-twisted - tenacity testtools towncrier ]; From 6a4346587cf06f7603572796daf4851bd98a1415 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 17 Mar 2023 15:46:27 -0400 Subject: [PATCH 4/4] Fix the type annotations --- src/allmydata/test/test_iputil.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/allmydata/test/test_iputil.py b/src/allmydata/test/test_iputil.py index c060fcc04..26274830f 100644 --- a/src/allmydata/test/test_iputil.py +++ b/src/allmydata/test/test_iputil.py @@ -11,7 +11,6 @@ import gc from functools import wraps from typing import TypeVar, Callable -from typing_extensions import TypeAlias from testtools.matchers import ( MatchesAll, IsInstance, @@ -33,12 +32,10 @@ from .common import ( SyncTestCase, ) -T = TypeVar("T") +T = TypeVar("T", contravariant=True) +U = TypeVar("U", covariant=True) -TestFunction: TypeAlias = Callable[[], T] -Decorator: TypeAlias = Callable[[TestFunction[T]], TestFunction[T]] - -def retry(stop: Callable[[], bool]) -> Decorator[T]: +def retry(stop: Callable[[], bool]) -> Callable[[Callable[[T], U]], Callable[[T], U]]: """ Call a function until the predicate says to stop or the function stops raising an exception. @@ -49,9 +46,9 @@ def retry(stop: Callable[[], bool]) -> Decorator[T]: :return: A decorator function. """ - def decorate(f: TestFunction[T]) -> TestFunction[T]: + def decorate(f: Callable[[T], U]) -> Callable[[T], U]: @wraps(f) - def decorator(self) -> T: + def decorator(self: T) -> U: while True: try: return f(self)