Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-tenacity for openSUSE:Factory
checked in at 2023-06-01 17:19:29
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-tenacity (Old)
and /work/SRC/openSUSE:Factory/.python-tenacity.new.2531 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-tenacity"
Thu Jun 1 17:19:29 2023 rev:19 rq:1090091 version:8.2.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-tenacity/python-tenacity.changes
2023-05-16 14:27:17.379695052 +0200
+++
/work/SRC/openSUSE:Factory/.python-tenacity.new.2531/python-tenacity.changes
2023-06-01 17:19:37.590198127 +0200
@@ -1,0 +2,11 @@
+Wed May 31 19:54:37 UTC 2023 - Dirk Müller <[email protected]>
+
+- update to 8.2.2:
+ * feat: accept datetime.timedelta instances as argument to `stop_after..
+ * fix: docstring for wait_exponential_jitter
+ * fix: remove __iter__ from AsyncRetring
+ * Add retry_if_exception_cause_type and wait_exponential_jitter
+ * better wait.WaitBaseT annotation
+ * CI conversion to GitHub actions
+
+-------------------------------------------------------------------
Old:
----
tenacity-8.1.0.tar.gz
New:
----
tenacity-8.2.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-tenacity.spec ++++++
--- /var/tmp/diff_new_pack.Giz9JJ/_old 2023-06-01 17:19:38.074200996 +0200
+++ /var/tmp/diff_new_pack.Giz9JJ/_new 2023-06-01 17:19:38.078201020 +0200
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-tenacity
-Version: 8.1.0
+Version: 8.2.2
Release: 0
Summary: Python module for retrying code until it succeeeds
License: Apache-2.0
++++++ tenacity-8.1.0.tar.gz -> tenacity-8.2.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/.circleci/config.yml
new/tenacity-8.2.2/.circleci/config.yml
--- old/tenacity-8.1.0/.circleci/config.yml 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/.circleci/config.yml 1970-01-01 01:00:00.000000000
+0100
@@ -1,98 +0,0 @@
-version: 2
-
-jobs:
- pep8:
- docker:
- - image: circleci/python:3.9
- steps:
- - checkout
- - run:
- command: |
- sudo pip install tox
- tox -e pep8
- black:
- docker:
- - image: circleci/python:3.9
- steps:
- - checkout
- - run:
- command: |
- sudo pip install tox
- tox -e black-ci
- py36:
- docker:
- - image: circleci/python:3.6
- steps:
- - checkout
- - run:
- command: |
- sudo pip install tox
- tox -e py36
- py37:
- docker:
- - image: circleci/python:3.7
- steps:
- - checkout
- - run:
- command: |
- sudo pip install tox
- tox -e py37
- py38:
- docker:
- - image: circleci/python:3.8
- steps:
- - checkout
- - run:
- command: |
- sudo pip install tox
- tox -e py38
- py39:
- docker:
- - image: circleci/python:3.9
- steps:
- - checkout
- - run:
- command: |
- sudo pip install tox
- tox -e py39
- deploy:
- docker:
- - image: circleci/python:3.9
- steps:
- - checkout
- - run: |
- python -m venv venv
- - run: |
- venv/bin/pip install twine wheel
- - run:
- name: init .pypirc
- command: |
- echo -e "[pypi]" >> ~/.pypirc
- echo -e "username = __token__" >> ~/.pypirc
- echo -e "password = $PYPI_TOKEN" >> ~/.pypirc
- - run:
- name: create packages
- command: |
- venv/bin/python setup.py sdist bdist_wheel
- - run:
- name: upload to PyPI
- command: |
- venv/bin/twine upload dist/*
-
-workflows:
- version: 2
-
- test:
- jobs:
- - pep8
- - black
- - py36
- - py37
- - py38
- - py39
- - deploy:
- filters:
- tags:
- only: /[0-9]+(\.[0-9]+)*/
- branches:
- ignore: /.*/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/.github/workflows/ci.yaml
new/tenacity-8.2.2/.github/workflows/ci.yaml
--- old/tenacity-8.1.0/.github/workflows/ci.yaml 1970-01-01
01:00:00.000000000 +0100
+++ new/tenacity-8.2.2/.github/workflows/ci.yaml 2023-02-28
15:21:48.000000000 +0100
@@ -0,0 +1,53 @@
+name: Continuous Integration
+permissions: read-all
+
+on:
+ pull_request:
+ branches:
+ - main
+
+concurrency:
+ # yamllint disable-line rule:line-length
+ group: "${{ github.workflow }}-${{ github.head_ref || github.run_id }}"
+ cancel-in-progress: true
+
+jobs:
+ test:
+ timeout-minutes: 20
+ runs-on: ubuntu-20.04
+ strategy:
+ matrix:
+ include:
+ - python: "3.6"
+ tox: py36
+ - python: "3.7"
+ tox: py37
+ - python: "3.8"
+ tox: py38
+ - python: "3.9"
+ tox: py39
+ - python: "3.10"
+ tox: py310
+ - python: "3.11"
+ tox: py311
+ - python: "3.11"
+ tox: pep8
+ - python: "3.11"
+ tox: black-ci
+ - python: "3.11"
+ tox: mypy
+ steps:
+ - name: Checkout ðï¸
+ uses: actions/[email protected]
+ with:
+ fetch-depth: 0
+
+ - name: Setup Python ð§
+ uses: actions/[email protected]
+ with:
+ python-version: ${{Â matrix.python }}
+
+ - name: Build ð§ & Test ð
+ run: |
+ pip install tox
+ tox -e ${{ matrix.tox }}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/.github/workflows/deploy.yaml
new/tenacity-8.2.2/.github/workflows/deploy.yaml
--- old/tenacity-8.1.0/.github/workflows/deploy.yaml 1970-01-01
01:00:00.000000000 +0100
+++ new/tenacity-8.2.2/.github/workflows/deploy.yaml 2023-02-28
15:21:48.000000000 +0100
@@ -0,0 +1,33 @@
+name: Release deploy
+
+on:
+ push:
+ tags:
+
+jobs:
+ test:
+ timeout-minutes: 20
+ runs-on: ubuntu-20.04
+ steps:
+ - name: Checkout ðï¸
+ uses: actions/[email protected]
+ with:
+ fetch-depth: 0
+
+ - name: Setup Python ð§
+ uses: actions/[email protected]
+ with:
+ python-version: 3.11
+
+ - name: Build ð§ & Deploy ð
+ env:
+ PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
+ run: |
+ pip install tox twine wheel
+
+ echo -e "[pypi]" >> ~/.pypirc
+ echo -e "username = __token__" >> ~/.pypirc
+ echo -e "password = $PYPI_TOKEN" >> ~/.pypirc
+
+ python setup.py sdist bdist_wheel
+ twine upload dist/*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/.mergify.yml
new/tenacity-8.2.2/.mergify.yml
--- old/tenacity-8.1.0/.mergify.yml 2022-09-21 14:23:59.000000000 +0200
+++ new/tenacity-8.2.2/.mergify.yml 2023-02-28 15:21:48.000000000 +0100
@@ -1,12 +1,15 @@
queue_rules:
- name: default
- conditions:
- - "status-success=ci/circleci: pep8"
- - "status-success=ci/circleci: black"
- - "status-success=ci/circleci: py36"
- - "status-success=ci/circleci: py37"
- - "status-success=ci/circleci: py38"
- - "status-success=ci/circleci: py39"
+ conditions: &CheckRuns
+ - "check-success=test (3.6, py36)"
+ - "check-success=test (3.7, py37)"
+ - "check-success=test (3.8, py38)"
+ - "check-success=test (3.9, py39)"
+ - "check-success=test (3.10, py310)"
+ - "check-success=test (3.11, py311)"
+ - "check-success=test (3.11, black-ci)"
+ - "check-success=test (3.11, pep8)"
+ - "check-success=test (3.11, mypy)"
pull_request_rules:
- name: warn on no changelog
@@ -22,12 +25,7 @@
a changelog entry.
- name: automatic merge without changelog
conditions:
- - "status-success=ci/circleci: pep8"
- - "status-success=ci/circleci: black"
- - "status-success=ci/circleci: py36"
- - "status-success=ci/circleci: py37"
- - "status-success=ci/circleci: py38"
- - "status-success=ci/circleci: py39"
+ - and: *CheckRuns
- "#approved-reviews-by>=1"
- label=no-changelog
actions:
@@ -36,12 +34,7 @@
method: squash
- name: automatic merge with changelog
conditions:
- - "status-success=ci/circleci: pep8"
- - "status-success=ci/circleci: black"
- - "status-success=ci/circleci: py36"
- - "status-success=ci/circleci: py37"
- - "status-success=ci/circleci: py38"
- - "status-success=ci/circleci: py39"
+ - and: *CheckRuns
- "#approved-reviews-by>=1"
- files~=^releasenotes/notes/
actions:
@@ -51,12 +44,7 @@
- name: automatic merge for jd without changelog
conditions:
- author=jd
- - "status-success=ci/circleci: pep8"
- - "status-success=ci/circleci: black"
- - "status-success=ci/circleci: py36"
- - "status-success=ci/circleci: py37"
- - "status-success=ci/circleci: py38"
- - "status-success=ci/circleci: py39"
+ - and: *CheckRuns
- label=no-changelog
actions:
queue:
@@ -65,12 +53,7 @@
- name: automatic merge for jd with changelog
conditions:
- author=jd
- - "status-success=ci/circleci: pep8"
- - "status-success=ci/circleci: black"
- - "status-success=ci/circleci: py36"
- - "status-success=ci/circleci: py37"
- - "status-success=ci/circleci: py38"
- - "status-success=ci/circleci: py39"
+ - and: *CheckRuns
- files~=^releasenotes/notes/
actions:
queue:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/PKG-INFO new/tenacity-8.2.2/PKG-INFO
--- old/tenacity-8.1.0/PKG-INFO 2022-09-21 14:24:11.075567200 +0200
+++ new/tenacity-8.2.2/PKG-INFO 2023-02-28 15:22:05.633156000 +0100
@@ -1,12 +1,11 @@
Metadata-Version: 2.1
Name: tenacity
-Version: 8.1.0
+Version: 8.2.2
Summary: Retry code until it succeeds
Home-page: https://github.com/jd/tenacity
Author: Julien Danjou
Author-email: [email protected]
License: Apache 2.0
-Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python
@@ -17,10 +16,10 @@
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Utilities
Requires-Python: >=3.6
Provides-Extra: doc
License-File: LICENSE
Tenacity is a general-purpose retrying library to simplify the task of adding
retry behavior to just about anything.
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/README.rst
new/tenacity-8.2.2/README.rst
--- old/tenacity-8.1.0/README.rst 2022-09-21 14:23:59.000000000 +0200
+++ new/tenacity-8.2.2/README.rst 2023-02-28 15:21:48.000000000 +0100
@@ -6,7 +6,7 @@
.. image:: https://circleci.com/gh/jd/tenacity.svg?style=svg
:target: https://circleci.com/gh/jd/tenacity
-.. image::
https://img.shields.io/endpoint.svg?url=https://dashboard.mergify.io/badges/jd/tenacity&style=flat
+.. image::
https://img.shields.io/endpoint.svg?url=https://api.mergify.com/badges/jd/tenacity&style=flat
:target: https://mergify.io
:alt: Mergify Status
@@ -274,8 +274,12 @@
Error Handling
~~~~~~~~~~~~~~
-While callables that "timeout" retrying raise a `RetryError` by default,
-we can reraise the last attempt's exception if needed:
+Normally when your function fails its final time (and will not be retried
again based on your settings),
+a `RetryError` is raised. The exception your code encountered will be shown
somewhere in the *middle*
+of the stack trace.
+
+If you would rather see the exception your code encountered at the *end* of
the stack trace (where it
+is most visible), you can set `reraise=True`.
.. testcode::
@@ -298,6 +302,7 @@
.. testcode::
import logging
+ import sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
@@ -312,6 +317,7 @@
.. testcode::
import logging
+ import sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
@@ -328,6 +334,7 @@
.. testcode::
import logging
+ import sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
@@ -566,6 +573,22 @@
except RetryError:
pass
+In both cases, you may want to set the result to the attempt so it's available
+in retry strategies like ``retry_if_result``. This can be done accessing the
+``retry_state`` property:
+
+.. testcode::
+
+ from tenacity import AsyncRetrying, retry_if_result
+
+ async def function():
+ async for attempt in AsyncRetrying(retry=retry_if_result(lambda x: x <
3)):
+ with attempt:
+ result = 1 # Some complex calculation, function call, etc.
+ if not attempt.retry_state.outcome.failed:
+ attempt.retry_state.set_result(result)
+ return result
+
Async and retry
~~~~~~~~~~~~~~~
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/doc/source/index.rst
new/tenacity-8.2.2/doc/source/index.rst
--- old/tenacity-8.1.0/doc/source/index.rst 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/doc/source/index.rst 2023-02-28 15:21:48.000000000
+0100
@@ -6,7 +6,7 @@
.. image:: https://circleci.com/gh/jd/tenacity.svg?style=svg
:target: https://circleci.com/gh/jd/tenacity
-.. image::
https://img.shields.io/endpoint.svg?url=https://dashboard.mergify.io/badges/jd/tenacity&style=flat
+.. image::
https://img.shields.io/endpoint.svg?url=https://api.mergify.com/badges/jd/tenacity&style=flat
:target: https://mergify.io
:alt: Mergify Status
@@ -274,8 +274,12 @@
Error Handling
~~~~~~~~~~~~~~
-While callables that "timeout" retrying raise a `RetryError` by default,
-we can reraise the last attempt's exception if needed:
+Normally when your function fails its final time (and will not be retried
again based on your settings),
+a `RetryError` is raised. The exception your code encountered will be shown
somewhere in the *middle*
+of the stack trace.
+
+If you would rather see the exception your code encountered at the *end* of
the stack trace (where it
+is most visible), you can set `reraise=True`.
.. testcode::
@@ -298,6 +302,7 @@
.. testcode::
import logging
+ import sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
@@ -312,6 +317,7 @@
.. testcode::
import logging
+ import sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
@@ -328,6 +334,7 @@
.. testcode::
import logging
+ import sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
@@ -566,6 +573,22 @@
except RetryError:
pass
+In both cases, you may want to set the result to the attempt so it's available
+in retry strategies like ``retry_if_result``. This can be done accessing the
+``retry_state`` property:
+
+.. testcode::
+
+ from tenacity import AsyncRetrying, retry_if_result
+
+ async def function():
+ async for attempt in AsyncRetrying(retry=retry_if_result(lambda x: x <
3)):
+ with attempt:
+ result = 1 # Some complex calculation, function call, etc.
+ if not attempt.retry_state.outcome.failed:
+ attempt.retry_state.set_result(result)
+ return result
+
Async and retry
~~~~~~~~~~~~~~~
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/pyproject.toml
new/tenacity-8.2.2/pyproject.toml
--- old/tenacity-8.1.0/pyproject.toml 2022-09-21 14:23:59.000000000 +0200
+++ new/tenacity-8.2.2/pyproject.toml 2023-02-28 15:21:48.000000000 +0100
@@ -11,6 +11,15 @@
[tool.black]
line-length = 120
safe = true
-target-version = ["py36", "py37", "py38", "py39"]
+target-version = ["py36", "py37", "py38", "py39", "py310", "py311"]
+
+[tool.mypy]
+strict = true
+files = ["tenacity"]
+show_error_codes = true
+
+[[tool.mypy.overrides]]
+module = "tornado.*"
+ignore_missing_imports = true
[tool.setuptools_scm]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/tenacity-8.1.0/releasenotes/notes/add_omitted_modules_to_import_all-2ab282f20a2c22f7.yaml
new/tenacity-8.2.2/releasenotes/notes/add_omitted_modules_to_import_all-2ab282f20a2c22f7.yaml
---
old/tenacity-8.1.0/releasenotes/notes/add_omitted_modules_to_import_all-2ab282f20a2c22f7.yaml
1970-01-01 01:00:00.000000000 +0100
+++
new/tenacity-8.2.2/releasenotes/notes/add_omitted_modules_to_import_all-2ab282f20a2c22f7.yaml
2023-02-28 15:21:48.000000000 +0100
@@ -0,0 +1,3 @@
+---
+other:
+ - Add `retry_if_exception_cause_type`and `wait_exponential_jitter` to
__all__ of init.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/tenacity-8.1.0/releasenotes/notes/clarify-reraise-option-6829667eacf4f599.yaml
new/tenacity-8.2.2/releasenotes/notes/clarify-reraise-option-6829667eacf4f599.yaml
---
old/tenacity-8.1.0/releasenotes/notes/clarify-reraise-option-6829667eacf4f599.yaml
1970-01-01 01:00:00.000000000 +0100
+++
new/tenacity-8.2.2/releasenotes/notes/clarify-reraise-option-6829667eacf4f599.yaml
2023-02-28 15:21:48.000000000 +0100
@@ -0,0 +1,3 @@
+---
+prelude: >
+ Clarify usage of `reraise` keyword argument
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/tenacity-8.1.0/releasenotes/notes/export-convenience-symbols-981d9611c8b754f3.yaml
new/tenacity-8.2.2/releasenotes/notes/export-convenience-symbols-981d9611c8b754f3.yaml
---
old/tenacity-8.1.0/releasenotes/notes/export-convenience-symbols-981d9611c8b754f3.yaml
1970-01-01 01:00:00.000000000 +0100
+++
new/tenacity-8.2.2/releasenotes/notes/export-convenience-symbols-981d9611c8b754f3.yaml
2023-02-28 15:21:48.000000000 +0100
@@ -0,0 +1,3 @@
+---
+features:
+ - Explicitly export convenience symbols from tenacity root module
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/tenacity-8.1.0/releasenotes/notes/fix-async-loop-with-result-f68e913ccb425aca.yaml
new/tenacity-8.2.2/releasenotes/notes/fix-async-loop-with-result-f68e913ccb425aca.yaml
---
old/tenacity-8.1.0/releasenotes/notes/fix-async-loop-with-result-f68e913ccb425aca.yaml
1970-01-01 01:00:00.000000000 +0100
+++
new/tenacity-8.2.2/releasenotes/notes/fix-async-loop-with-result-f68e913ccb425aca.yaml
2023-02-28 15:21:48.000000000 +0100
@@ -0,0 +1,4 @@
+---
+fixes:
+ - |
+ Fix async loop with retrying code block when result is available.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/tenacity-8.1.0/releasenotes/notes/fix-wait-typing-b26eecdb6cc0a1de.yaml
new/tenacity-8.2.2/releasenotes/notes/fix-wait-typing-b26eecdb6cc0a1de.yaml
--- old/tenacity-8.1.0/releasenotes/notes/fix-wait-typing-b26eecdb6cc0a1de.yaml
1970-01-01 01:00:00.000000000 +0100
+++ new/tenacity-8.2.2/releasenotes/notes/fix-wait-typing-b26eecdb6cc0a1de.yaml
2023-02-28 15:21:48.000000000 +0100
@@ -0,0 +1,5 @@
+---
+fixes:
+ - |
+ Argument `wait` was improperly annotated, making mypy checks fail.
+ Now it's annotated as `typing.Union[wait_base,
typing.Callable[["RetryCallState"], typing.Union[float, int]]]`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/tenacity-8.1.0/releasenotes/notes/no-async-iter-6132a42e52348a75.yaml
new/tenacity-8.2.2/releasenotes/notes/no-async-iter-6132a42e52348a75.yaml
--- old/tenacity-8.1.0/releasenotes/notes/no-async-iter-6132a42e52348a75.yaml
1970-01-01 01:00:00.000000000 +0100
+++ new/tenacity-8.2.2/releasenotes/notes/no-async-iter-6132a42e52348a75.yaml
2023-02-28 15:21:48.000000000 +0100
@@ -0,0 +1,7 @@
+---
+fixes:
+ - |
+ `AsyncRetrying` was erroneously implementing `__iter__()`, making tenacity
+ retrying mechanism working but in a synchronous fashion and not waiting as
+ expected. This interface has been removed, `__aiter__()` should be used
+ instead.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/tenacity-8.1.0/releasenotes/notes/timedelta-for-stop-ef6bf71b88ce9988.yaml
new/tenacity-8.2.2/releasenotes/notes/timedelta-for-stop-ef6bf71b88ce9988.yaml
---
old/tenacity-8.1.0/releasenotes/notes/timedelta-for-stop-ef6bf71b88ce9988.yaml
1970-01-01 01:00:00.000000000 +0100
+++
new/tenacity-8.2.2/releasenotes/notes/timedelta-for-stop-ef6bf71b88ce9988.yaml
2023-02-28 15:21:48.000000000 +0100
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ - accept ``datetime.timedelta`` instances as argument to
``tenacity.stop.stop_after_delay``
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/setup.cfg new/tenacity-8.2.2/setup.cfg
--- old/tenacity-8.1.0/setup.cfg 2022-09-21 14:24:11.075567200 +0200
+++ new/tenacity-8.2.2/setup.cfg 2023-02-28 15:22:05.637156000 +0100
@@ -18,6 +18,7 @@
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
+ Programming Language :: Python :: 3.11
Topic :: Utilities
[options]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity/__init__.py
new/tenacity-8.2.2/tenacity/__init__.py
--- old/tenacity-8.1.0/tenacity/__init__.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tenacity/__init__.py 2023-02-28 15:21:48.000000000
+0100
@@ -16,6 +16,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+
import functools
import sys
import threading
@@ -79,58 +80,20 @@
from .before_sleep import before_sleep_nothing # noqa
try:
- import tornado # type: ignore
+ import tornado
except ImportError:
- tornado = None # type: ignore
+ tornado = None
if t.TYPE_CHECKING:
import types
- from .wait import wait_base
- from .stop import stop_base
-
-
-WrappedFn = t.TypeVar("WrappedFn", bound=t.Callable)
-_RetValT = t.TypeVar("_RetValT")
-
-
[email protected]
-def retry(fn: WrappedFn) -> WrappedFn:
- pass
-
-
[email protected]
-def retry(*dargs: t.Any, **dkw: t.Any) -> t.Callable[[WrappedFn], WrappedFn]:
# noqa
- pass
+ from .retry import RetryBaseT
+ from .stop import StopBaseT
+ from .wait import WaitBaseT
-def retry(*dargs: t.Any, **dkw: t.Any) -> t.Union[WrappedFn,
t.Callable[[WrappedFn], WrappedFn]]: # noqa
- """Wrap a function with a new `Retrying` object.
-
- :param dargs: positional arguments passed to Retrying object
- :param dkw: keyword arguments passed to the Retrying object
- """
- # support both @retry and @retry() as valid syntax
- if len(dargs) == 1 and callable(dargs[0]):
- return retry()(dargs[0])
- else:
-
- def wrap(f: WrappedFn) -> WrappedFn:
- if isinstance(f, retry_base):
- warnings.warn(
- f"Got retry_base instance ({f.__class__.__name__}) as
callable argument, "
- f"this will probably hang indefinitely (did you mean
retry={f.__class__.__name__}(...)?)"
- )
- if iscoroutinefunction(f):
- r: "BaseRetrying" = AsyncRetrying(*dargs, **dkw)
- elif tornado and hasattr(tornado.gen, "is_coroutine_function") and
tornado.gen.is_coroutine_function(f):
- r = TornadoRetrying(*dargs, **dkw)
- else:
- r = Retrying(*dargs, **dkw)
-
- return r.wraps(f)
-
- return wrap
+WrappedFnReturnT = t.TypeVar("WrappedFnReturnT")
+WrappedFn = t.TypeVar("WrappedFn", bound=t.Callable[..., t.Any])
class TryAgain(Exception):
@@ -214,7 +177,7 @@
exc_value: t.Optional[BaseException],
traceback: t.Optional["types.TracebackType"],
) -> t.Optional[bool]:
- if isinstance(exc_value, BaseException):
+ if exc_type is not None and exc_value is not None:
self.retry_state.set_exception((exc_type, exc_value, traceback))
return True # Swallow exception.
else:
@@ -227,9 +190,9 @@
def __init__(
self,
sleep: t.Callable[[t.Union[int, float]], None] = sleep,
- stop: "stop_base" = stop_never,
- wait: "wait_base" = wait_none(),
- retry: retry_base = retry_if_exception_type(),
+ stop: "StopBaseT" = stop_never,
+ wait: "WaitBaseT" = wait_none(),
+ retry: "RetryBaseT" = retry_if_exception_type(),
before: t.Callable[["RetryCallState"], None] = before_nothing,
after: t.Callable[["RetryCallState"], None] = after_nothing,
before_sleep: t.Optional[t.Callable[["RetryCallState"], None]] = None,
@@ -252,8 +215,8 @@
def copy(
self,
sleep: t.Union[t.Callable[[t.Union[int, float]], None], object] =
_unset,
- stop: t.Union["stop_base", object] = _unset,
- wait: t.Union["wait_base", object] = _unset,
+ stop: t.Union["StopBaseT", object] = _unset,
+ wait: t.Union["WaitBaseT", object] = _unset,
retry: t.Union[retry_base, object] = _unset,
before: t.Union[t.Callable[["RetryCallState"], None], object] = _unset,
after: t.Union[t.Callable[["RetryCallState"], None], object] = _unset,
@@ -310,9 +273,9 @@
statistics from each thread).
"""
try:
- return self._local.statistics
+ return self._local.statistics # type: ignore[no-any-return]
except AttributeError:
- self._local.statistics = {}
+ self._local.statistics = t.cast(t.Dict[str, t.Any], {})
return self._local.statistics
def wraps(self, f: WrappedFn) -> WrappedFn:
@@ -328,10 +291,10 @@
def retry_with(*args: t.Any, **kwargs: t.Any) -> WrappedFn:
return self.copy(*args, **kwargs).wraps(f)
- wrapped_f.retry = self
- wrapped_f.retry_with = retry_with
+ wrapped_f.retry = self # type: ignore[attr-defined]
+ wrapped_f.retry_with = retry_with # type: ignore[attr-defined]
- return wrapped_f
+ return wrapped_f # type: ignore[return-value]
def begin(self) -> None:
self.statistics.clear()
@@ -346,15 +309,15 @@
self.before(retry_state)
return DoAttempt()
- is_explicit_retry = retry_state.outcome.failed and
isinstance(retry_state.outcome.exception(), TryAgain)
- if not (is_explicit_retry or self.retry(retry_state=retry_state)):
+ is_explicit_retry = fut.failed and isinstance(fut.exception(),
TryAgain)
+ if not (is_explicit_retry or self.retry(retry_state)):
return fut.result()
if self.after is not None:
self.after(retry_state)
self.statistics["delay_since_first_attempt"] =
retry_state.seconds_since_start
- if self.stop(retry_state=retry_state):
+ if self.stop(retry_state):
if self.retry_error_callback:
return self.retry_error_callback(retry_state)
retry_exc = self.retry_error_cls(fut)
@@ -363,7 +326,7 @@
raise retry_exc from fut.exception()
if self.wait:
- sleep = self.wait(retry_state=retry_state)
+ sleep = self.wait(retry_state)
else:
sleep = 0.0
retry_state.next_action = RetryAction(sleep)
@@ -391,14 +354,24 @@
break
@abstractmethod
- def __call__(self, fn: t.Callable[..., _RetValT], *args: t.Any, **kwargs:
t.Any) -> _RetValT:
+ def __call__(
+ self,
+ fn: t.Callable[..., WrappedFnReturnT],
+ *args: t.Any,
+ **kwargs: t.Any,
+ ) -> WrappedFnReturnT:
pass
class Retrying(BaseRetrying):
"""Retrying controller."""
- def __call__(self, fn: t.Callable[..., _RetValT], *args: t.Any, **kwargs:
t.Any) -> _RetValT:
+ def __call__(
+ self,
+ fn: t.Callable[..., WrappedFnReturnT],
+ *args: t.Any,
+ **kwargs: t.Any,
+ ) -> WrappedFnReturnT:
self.begin()
retry_state = RetryCallState(retry_object=self, fn=fn, args=args,
kwargs=kwargs)
@@ -408,17 +381,23 @@
try:
result = fn(*args, **kwargs)
except BaseException: # noqa: B902
- retry_state.set_exception(sys.exc_info())
+ retry_state.set_exception(sys.exc_info()) # type:
ignore[arg-type]
else:
retry_state.set_result(result)
elif isinstance(do, DoSleep):
retry_state.prepare_for_next_attempt()
self.sleep(do)
else:
- return do
+ return do # type: ignore[no-any-return]
-class Future(futures.Future):
+if sys.version_info[1] >= 9:
+ FutureGenericT = futures.Future[t.Any]
+else:
+ FutureGenericT = futures.Future
+
+
+class Future(FutureGenericT):
"""Encapsulates a (future or past) attempted call to a target function."""
def __init__(self, attempt_number: int) -> None:
@@ -491,13 +470,15 @@
fut.set_result(val)
self.outcome, self.outcome_timestamp = fut, ts
- def set_exception(self, exc_info: t.Tuple[t.Type[BaseException],
BaseException, "types.TracebackType"]) -> None:
+ def set_exception(
+ self, exc_info: t.Tuple[t.Type[BaseException], BaseException,
"types.TracebackType| None"]
+ ) -> None:
ts = time.monotonic()
fut = Future(self.attempt_number)
fut.set_exception(exc_info[1])
self.outcome, self.outcome_timestamp = fut, ts
- def __repr__(self):
+ def __repr__(self) -> str:
if self.outcome is None:
result = "none yet"
elif self.outcome.failed:
@@ -511,7 +492,115 @@
return f"<{clsname} {id(self)}: attempt #{self.attempt_number}; slept
for {slept}; last result: {result}>"
[email protected]
+def retry(func: WrappedFn) -> WrappedFn:
+ ...
+
+
[email protected]
+def retry(
+ sleep: t.Callable[[t.Union[int, float]], None] = sleep,
+ stop: "StopBaseT" = stop_never,
+ wait: "WaitBaseT" = wait_none(),
+ retry: "RetryBaseT" = retry_if_exception_type(),
+ before: t.Callable[["RetryCallState"], None] = before_nothing,
+ after: t.Callable[["RetryCallState"], None] = after_nothing,
+ before_sleep: t.Optional[t.Callable[["RetryCallState"], None]] = None,
+ reraise: bool = False,
+ retry_error_cls: t.Type["RetryError"] = RetryError,
+ retry_error_callback: t.Optional[t.Callable[["RetryCallState"], t.Any]] =
None,
+) -> t.Callable[[WrappedFn], WrappedFn]:
+ ...
+
+
+def retry(*dargs: t.Any, **dkw: t.Any) -> t.Any:
+ """Wrap a function with a new `Retrying` object.
+
+ :param dargs: positional arguments passed to Retrying object
+ :param dkw: keyword arguments passed to the Retrying object
+ """
+ # support both @retry and @retry() as valid syntax
+ if len(dargs) == 1 and callable(dargs[0]):
+ return retry()(dargs[0])
+ else:
+
+ def wrap(f: WrappedFn) -> WrappedFn:
+ if isinstance(f, retry_base):
+ warnings.warn(
+ f"Got retry_base instance ({f.__class__.__name__}) as
callable argument, "
+ f"this will probably hang indefinitely (did you mean
retry={f.__class__.__name__}(...)?)"
+ )
+ r: "BaseRetrying"
+ if iscoroutinefunction(f):
+ r = AsyncRetrying(*dargs, **dkw)
+ elif tornado and hasattr(tornado.gen, "is_coroutine_function") and
tornado.gen.is_coroutine_function(f):
+ r = TornadoRetrying(*dargs, **dkw)
+ else:
+ r = Retrying(*dargs, **dkw)
+
+ return r.wraps(f)
+
+ return wrap
+
+
from tenacity._asyncio import AsyncRetrying # noqa:E402,I100
if tornado:
from tenacity.tornadoweb import TornadoRetrying
+
+
+__all__ = [
+ "retry_base",
+ "retry_all",
+ "retry_always",
+ "retry_any",
+ "retry_if_exception",
+ "retry_if_exception_type",
+ "retry_if_exception_cause_type",
+ "retry_if_not_exception_type",
+ "retry_if_not_result",
+ "retry_if_result",
+ "retry_never",
+ "retry_unless_exception_type",
+ "retry_if_exception_message",
+ "retry_if_not_exception_message",
+ "sleep",
+ "sleep_using_event",
+ "stop_after_attempt",
+ "stop_after_delay",
+ "stop_all",
+ "stop_any",
+ "stop_never",
+ "stop_when_event_set",
+ "wait_chain",
+ "wait_combine",
+ "wait_exponential",
+ "wait_fixed",
+ "wait_incrementing",
+ "wait_none",
+ "wait_random",
+ "wait_random_exponential",
+ "wait_full_jitter",
+ "wait_exponential_jitter",
+ "before_log",
+ "before_nothing",
+ "after_log",
+ "after_nothing",
+ "before_sleep_log",
+ "before_sleep_nothing",
+ "retry",
+ "WrappedFn",
+ "TryAgain",
+ "NO_RESULT",
+ "DoAttempt",
+ "DoSleep",
+ "BaseAction",
+ "RetryAction",
+ "RetryError",
+ "AttemptManager",
+ "BaseRetrying",
+ "Retrying",
+ "Future",
+ "RetryCallState",
+ "AsyncRetrying",
+]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity/_asyncio.py
new/tenacity-8.2.2/tenacity/_asyncio.py
--- old/tenacity-8.1.0/tenacity/_asyncio.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tenacity/_asyncio.py 2023-02-28 15:21:48.000000000
+0100
@@ -17,7 +17,7 @@
import functools
import sys
-import typing
+import typing as t
from asyncio import sleep
from tenacity import AttemptManager
@@ -26,21 +26,20 @@
from tenacity import DoSleep
from tenacity import RetryCallState
-WrappedFn = typing.TypeVar("WrappedFn", bound=typing.Callable)
-_RetValT = typing.TypeVar("_RetValT")
+WrappedFnReturnT = t.TypeVar("WrappedFnReturnT")
+WrappedFn = t.TypeVar("WrappedFn", bound=t.Callable[..., t.Awaitable[t.Any]])
class AsyncRetrying(BaseRetrying):
- def __init__(self, sleep: typing.Callable[[float], typing.Awaitable] =
sleep, **kwargs: typing.Any) -> None:
+ sleep: t.Callable[[float], t.Awaitable[t.Any]]
+
+ def __init__(self, sleep: t.Callable[[float], t.Awaitable[t.Any]] = sleep,
**kwargs: t.Any) -> None:
super().__init__(**kwargs)
self.sleep = sleep
- async def __call__( # type: ignore # Change signature from supertype
- self,
- fn: typing.Callable[..., typing.Awaitable[_RetValT]],
- *args: typing.Any,
- **kwargs: typing.Any,
- ) -> _RetValT:
+ async def __call__( # type: ignore[override]
+ self, fn: WrappedFn, *args: t.Any, **kwargs: t.Any
+ ) -> WrappedFnReturnT:
self.begin()
retry_state = RetryCallState(retry_object=self, fn=fn, args=args,
kwargs=kwargs)
@@ -50,21 +49,24 @@
try:
result = await fn(*args, **kwargs)
except BaseException: # noqa: B902
- retry_state.set_exception(sys.exc_info())
+ retry_state.set_exception(sys.exc_info()) # type:
ignore[arg-type]
else:
retry_state.set_result(result)
elif isinstance(do, DoSleep):
retry_state.prepare_for_next_attempt()
await self.sleep(do)
else:
- return do
+ return do # type: ignore[no-any-return]
+
+ def __iter__(self) -> t.Generator[AttemptManager, None, None]:
+ raise TypeError("AsyncRetrying object is not iterable")
def __aiter__(self) -> "AsyncRetrying":
self.begin()
self._retry_state = RetryCallState(self, fn=None, args=(), kwargs={})
return self
- async def __anext__(self) -> typing.Union[AttemptManager, typing.Any]:
+ async def __anext__(self) -> AttemptManager:
while True:
do = self.iter(retry_state=self._retry_state)
if do is None:
@@ -75,18 +77,18 @@
self._retry_state.prepare_for_next_attempt()
await self.sleep(do)
else:
- return do
+ raise StopAsyncIteration
def wraps(self, fn: WrappedFn) -> WrappedFn:
fn = super().wraps(fn)
# Ensure wrapper is recognized as a coroutine function.
@functools.wraps(fn)
- async def async_wrapped(*args: typing.Any, **kwargs: typing.Any) ->
typing.Any:
+ async def async_wrapped(*args: t.Any, **kwargs: t.Any) -> t.Any:
return await fn(*args, **kwargs)
# Preserve attributes
- async_wrapped.retry = fn.retry
- async_wrapped.retry_with = fn.retry_with
+ async_wrapped.retry = fn.retry # type: ignore[attr-defined]
+ async_wrapped.retry_with = fn.retry_with # type: ignore[attr-defined]
- return async_wrapped
+ return async_wrapped # type: ignore[return-value]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity/_utils.py
new/tenacity-8.2.2/tenacity/_utils.py
--- old/tenacity-8.1.0/tenacity/_utils.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tenacity/_utils.py 2023-02-28 15:21:48.000000000
+0100
@@ -16,6 +16,7 @@
import sys
import typing
+from datetime import timedelta
# sys.maxsize:
@@ -66,3 +67,10 @@
except AttributeError:
pass
return ".".join(segments)
+
+
+time_unit_type = typing.Union[int, float, timedelta]
+
+
+def to_seconds(time_unit: time_unit_type) -> float:
+ return float(time_unit.total_seconds() if isinstance(time_unit, timedelta)
else time_unit)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity/after.py
new/tenacity-8.2.2/tenacity/after.py
--- old/tenacity-8.1.0/tenacity/after.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tenacity/after.py 2023-02-28 15:21:48.000000000
+0100
@@ -36,9 +36,14 @@
"""After call strategy that logs to some logger the finished attempt."""
def log_it(retry_state: "RetryCallState") -> None:
+ if retry_state.fn is None:
+ # NOTE(sileht): can't really happen, but we must please mypy
+ fn_name = "<unknown>"
+ else:
+ fn_name = _utils.get_callback_name(retry_state.fn)
logger.log(
log_level,
- f"Finished call to '{_utils.get_callback_name(retry_state.fn)}' "
+ f"Finished call to '{fn_name}' "
f"after {sec_format % retry_state.seconds_since_start}(s), "
f"this was the {_utils.to_ordinal(retry_state.attempt_number)}
time calling it.",
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity/before.py
new/tenacity-8.2.2/tenacity/before.py
--- old/tenacity-8.1.0/tenacity/before.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tenacity/before.py 2023-02-28 15:21:48.000000000
+0100
@@ -32,9 +32,14 @@
"""Before call strategy that logs to some logger the attempt."""
def log_it(retry_state: "RetryCallState") -> None:
+ if retry_state.fn is None:
+ # NOTE(sileht): can't really happen, but we must please mypy
+ fn_name = "<unknown>"
+ else:
+ fn_name = _utils.get_callback_name(retry_state.fn)
logger.log(
log_level,
- f"Starting call to '{_utils.get_callback_name(retry_state.fn)}', "
+ f"Starting call to '{fn_name}', "
f"this is the {_utils.to_ordinal(retry_state.attempt_number)} time
calling it.",
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity/before_sleep.py
new/tenacity-8.2.2/tenacity/before_sleep.py
--- old/tenacity-8.1.0/tenacity/before_sleep.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tenacity/before_sleep.py 2023-02-28 15:21:48.000000000
+0100
@@ -36,6 +36,14 @@
"""Before call strategy that logs to some logger the attempt."""
def log_it(retry_state: "RetryCallState") -> None:
+ local_exc_info: BaseException | bool | None
+
+ if retry_state.outcome is None:
+ raise RuntimeError("log_it() called before outcome was set")
+
+ if retry_state.next_action is None:
+ raise RuntimeError("log_it() called before next_action was set")
+
if retry_state.outcome.failed:
ex = retry_state.outcome.exception()
verb, value = "raised", f"{ex.__class__.__name__}: {ex}"
@@ -48,10 +56,15 @@
verb, value = "returned", retry_state.outcome.result()
local_exc_info = False # exc_info does not apply when no exception
+ if retry_state.fn is None:
+ # NOTE(sileht): can't really happen, but we must please mypy
+ fn_name = "<unknown>"
+ else:
+ fn_name = _utils.get_callback_name(retry_state.fn)
+
logger.log(
log_level,
- f"Retrying {_utils.get_callback_name(retry_state.fn)} "
- f"in {retry_state.next_action.sleep} seconds as it {verb}
{value}.",
+ f"Retrying {fn_name} " f"in {retry_state.next_action.sleep}
seconds as it {verb} {value}.",
exc_info=local_exc_info,
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity/retry.py
new/tenacity-8.2.2/tenacity/retry.py
--- old/tenacity-8.1.0/tenacity/retry.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tenacity/retry.py 2023-02-28 15:21:48.000000000
+0100
@@ -36,6 +36,9 @@
return retry_any(self, other)
+RetryBaseT = typing.Union[retry_base, typing.Callable[["RetryCallState"],
bool]]
+
+
class _retry_never(retry_base):
"""Retry strategy that never rejects any result."""
@@ -63,8 +66,14 @@
self.predicate = predicate
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
if retry_state.outcome.failed:
- return self.predicate(retry_state.outcome.exception())
+ exception = retry_state.outcome.exception()
+ if exception is None:
+ raise RuntimeError("outcome failed but the exception is None")
+ return self.predicate(exception)
else:
return False
@@ -111,10 +120,17 @@
super().__init__(lambda e: not isinstance(e, exception_types))
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
# always retry if no exception was raised
if not retry_state.outcome.failed:
return True
- return self.predicate(retry_state.outcome.exception())
+
+ exception = retry_state.outcome.exception()
+ if exception is None:
+ raise RuntimeError("outcome failed but the exception is None")
+ return self.predicate(exception)
class retry_if_exception_cause_type(retry_base):
@@ -134,6 +150,9 @@
self.exception_cause_types = exception_types
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__ called before outcome was set")
+
if retry_state.outcome.failed:
exc = retry_state.outcome.exception()
while exc is not None:
@@ -151,6 +170,9 @@
self.predicate = predicate
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
if not retry_state.outcome.failed:
return self.predicate(retry_state.outcome.result())
else:
@@ -164,6 +186,9 @@
self.predicate = predicate
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
if not retry_state.outcome.failed:
return not self.predicate(retry_state.outcome.result())
else:
@@ -215,9 +240,16 @@
self.predicate = lambda *args_, **kwargs_: not if_predicate(*args_,
**kwargs_)
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
if not retry_state.outcome.failed:
return True
- return self.predicate(retry_state.outcome.exception())
+
+ exception = retry_state.outcome.exception()
+ if exception is None:
+ raise RuntimeError("outcome failed but the exception is None")
+ return self.predicate(exception)
class retry_any(retry_base):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity/stop.py
new/tenacity-8.2.2/tenacity/stop.py
--- old/tenacity-8.1.0/tenacity/stop.py 2022-09-21 14:23:59.000000000 +0200
+++ new/tenacity-8.2.2/tenacity/stop.py 2023-02-28 15:21:48.000000000 +0100
@@ -16,6 +16,8 @@
import abc
import typing
+from tenacity import _utils
+
if typing.TYPE_CHECKING:
import threading
@@ -36,6 +38,9 @@
return stop_any(self, other)
+StopBaseT = typing.Union[stop_base, typing.Callable[["RetryCallState"], bool]]
+
+
class stop_any(stop_base):
"""Stop if any of the stop condition is valid."""
@@ -89,8 +94,10 @@
class stop_after_delay(stop_base):
"""Stop when the time from the first attempt >= limit."""
- def __init__(self, max_delay: float) -> None:
- self.max_delay = max_delay
+ def __init__(self, max_delay: _utils.time_unit_type) -> None:
+ self.max_delay = _utils.to_seconds(max_delay)
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.seconds_since_start is None:
+ raise RuntimeError("__call__() called but seconds_since_start is
not set")
return retry_state.seconds_since_start >= self.max_delay
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity/tornadoweb.py
new/tenacity-8.2.2/tenacity/tornadoweb.py
--- old/tenacity-8.1.0/tenacity/tornadoweb.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tenacity/tornadoweb.py 2023-02-28 15:21:48.000000000
+0100
@@ -33,8 +33,8 @@
super().__init__(**kwargs)
self.sleep = sleep
- @gen.coroutine
- def __call__( # type: ignore # Change signature from supertype
+ @gen.coroutine # type: ignore[misc]
+ def __call__(
self,
fn: "typing.Callable[..., typing.Union[typing.Generator[typing.Any,
typing.Any, _RetValT], Future[_RetValT]]]",
*args: typing.Any,
@@ -49,7 +49,7 @@
try:
result = yield fn(*args, **kwargs)
except BaseException: # noqa: B902
- retry_state.set_exception(sys.exc_info())
+ retry_state.set_exception(sys.exc_info()) # type:
ignore[arg-type]
else:
retry_state.set_result(result)
elif isinstance(do, DoSleep):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity/wait.py
new/tenacity-8.2.2/tenacity/wait.py
--- old/tenacity-8.1.0/tenacity/wait.py 2022-09-21 14:23:59.000000000 +0200
+++ new/tenacity-8.2.2/tenacity/wait.py 2023-02-28 15:21:48.000000000 +0100
@@ -17,19 +17,12 @@
import abc
import random
import typing
-from datetime import timedelta
from tenacity import _utils
if typing.TYPE_CHECKING:
from tenacity import RetryCallState
-wait_unit_type = typing.Union[int, float, timedelta]
-
-
-def to_seconds(wait_unit: wait_unit_type) -> float:
- return float(wait_unit.total_seconds() if isinstance(wait_unit, timedelta)
else wait_unit)
-
class wait_base(abc.ABC):
"""Abstract base class for wait strategies."""
@@ -43,16 +36,19 @@
def __radd__(self, other: "wait_base") -> typing.Union["wait_combine",
"wait_base"]:
# make it possible to use multiple waits with the built-in sum function
- if other == 0:
+ if other == 0: # type: ignore[comparison-overlap]
return self
return self.__add__(other)
+WaitBaseT = typing.Union[wait_base, typing.Callable[["RetryCallState"],
typing.Union[float, int]]]
+
+
class wait_fixed(wait_base):
"""Wait strategy that waits a fixed amount of time between each retry."""
- def __init__(self, wait: wait_unit_type) -> None:
- self.wait_fixed = to_seconds(wait)
+ def __init__(self, wait: _utils.time_unit_type) -> None:
+ self.wait_fixed = _utils.to_seconds(wait)
def __call__(self, retry_state: "RetryCallState") -> float:
return self.wait_fixed
@@ -68,9 +64,9 @@
class wait_random(wait_base):
"""Wait strategy that waits a random amount of time between min/max."""
- def __init__(self, min: wait_unit_type = 0, max: wait_unit_type = 1) ->
None: # noqa
- self.wait_random_min = to_seconds(min)
- self.wait_random_max = to_seconds(max)
+ def __init__(self, min: _utils.time_unit_type = 0, max:
_utils.time_unit_type = 1) -> None: # noqa
+ self.wait_random_min = _utils.to_seconds(min)
+ self.wait_random_max = _utils.to_seconds(max)
def __call__(self, retry_state: "RetryCallState") -> float:
return self.wait_random_min + (random.random() * (self.wait_random_max
- self.wait_random_min))
@@ -120,13 +116,13 @@
def __init__(
self,
- start: wait_unit_type = 0,
- increment: wait_unit_type = 100,
- max: wait_unit_type = _utils.MAX_WAIT, # noqa
+ start: _utils.time_unit_type = 0,
+ increment: _utils.time_unit_type = 100,
+ max: _utils.time_unit_type = _utils.MAX_WAIT, # noqa
) -> None:
- self.start = to_seconds(start)
- self.increment = to_seconds(increment)
- self.max = to_seconds(max)
+ self.start = _utils.to_seconds(start)
+ self.increment = _utils.to_seconds(increment)
+ self.max = _utils.to_seconds(max)
def __call__(self, retry_state: "RetryCallState") -> float:
result = self.start + (self.increment * (retry_state.attempt_number -
1))
@@ -149,13 +145,13 @@
def __init__(
self,
multiplier: typing.Union[int, float] = 1,
- max: wait_unit_type = _utils.MAX_WAIT, # noqa
+ max: _utils.time_unit_type = _utils.MAX_WAIT, # noqa
exp_base: typing.Union[int, float] = 2,
- min: wait_unit_type = 0, # noqa
+ min: _utils.time_unit_type = 0, # noqa
) -> None:
self.multiplier = multiplier
- self.min = to_seconds(min)
- self.max = to_seconds(max)
+ self.min = _utils.to_seconds(min)
+ self.max = _utils.to_seconds(max)
self.exp_base = exp_base
def __call__(self, retry_state: "RetryCallState") -> float:
@@ -206,7 +202,7 @@
This implements the strategy described here:
https://cloud.google.com/storage/docs/retry-strategy
- The wait time is min(initial * (2**n + random.uniform(0, jitter)), maximum)
+ The wait time is min(initial * 2**n + random.uniform(0, jitter), maximum)
where n is the retry count.
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity.egg-info/PKG-INFO
new/tenacity-8.2.2/tenacity.egg-info/PKG-INFO
--- old/tenacity-8.1.0/tenacity.egg-info/PKG-INFO 2022-09-21
14:24:11.000000000 +0200
+++ new/tenacity-8.2.2/tenacity.egg-info/PKG-INFO 2023-02-28
15:22:05.000000000 +0100
@@ -1,12 +1,11 @@
Metadata-Version: 2.1
Name: tenacity
-Version: 8.1.0
+Version: 8.2.2
Summary: Retry code until it succeeds
Home-page: https://github.com/jd/tenacity
Author: Julien Danjou
Author-email: [email protected]
License: Apache 2.0
-Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python
@@ -17,10 +16,10 @@
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Utilities
Requires-Python: >=3.6
Provides-Extra: doc
License-File: LICENSE
Tenacity is a general-purpose retrying library to simplify the task of adding
retry behavior to just about anything.
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tenacity.egg-info/SOURCES.txt
new/tenacity-8.2.2/tenacity.egg-info/SOURCES.txt
--- old/tenacity-8.1.0/tenacity.egg-info/SOURCES.txt 2022-09-21
14:24:11.000000000 +0200
+++ new/tenacity-8.2.2/tenacity.egg-info/SOURCES.txt 2023-02-28
15:22:05.000000000 +0100
@@ -9,7 +9,8 @@
setup.cfg
setup.py
tox.ini
-.circleci/config.yml
+.github/workflows/ci.yaml
+.github/workflows/deploy.yaml
doc/source/api.rst
doc/source/changelog.rst
doc/source/conf.py
@@ -17,21 +18,28 @@
releasenotes/notes/Use--for-formatting-and-validate-using-black-39ec9d57d4691778.yaml
releasenotes/notes/add-reno-d1ab5710f272650a.yaml
releasenotes/notes/add-retry_except_exception_type-31b31da1924d55f4.yaml
+releasenotes/notes/add_omitted_modules_to_import_all-2ab282f20a2c22f7.yaml
releasenotes/notes/add_retry_if_exception_cause_type-d16b918ace4ae0ad.yaml
releasenotes/notes/after_log-50f4d73b24ce9203.yaml
releasenotes/notes/allow-mocking-of-nap-sleep-6679c50e702446f1.yaml
releasenotes/notes/annotate_code-197b93130df14042.yaml
releasenotes/notes/before_sleep_log-improvements-d8149274dfb37d7c.yaml
+releasenotes/notes/clarify-reraise-option-6829667eacf4f599.yaml
releasenotes/notes/do_not_package_tests-fe5ac61940b0a5ed.yaml
releasenotes/notes/drop-deprecated-python-versions-69a05cb2e0f1034c.yaml
releasenotes/notes/drop_deprecated-7ea90b212509b082.yaml
+releasenotes/notes/export-convenience-symbols-981d9611c8b754f3.yaml
+releasenotes/notes/fix-async-loop-with-result-f68e913ccb425aca.yaml
+releasenotes/notes/fix-wait-typing-b26eecdb6cc0a1de.yaml
releasenotes/notes/fix_async-52b6594c8e75c4bc.yaml
releasenotes/notes/make-logger-more-compatible-5da1ddf1bab77047.yaml
+releasenotes/notes/no-async-iter-6132a42e52348a75.yaml
releasenotes/notes/pr320-py3-only-wheel-tag.yaml
releasenotes/notes/py36_plus-c425fb3aa17c6682.yaml
releasenotes/notes/retrycallstate-repr-94947f7b00ee15e1.yaml
releasenotes/notes/sphinx_define_error-642c9cd5c165d39a.yaml
releasenotes/notes/support-timedelta-wait-unit-type-5ba1e9fc0fe45523.yaml
+releasenotes/notes/timedelta-for-stop-ef6bf71b88ce9988.yaml
releasenotes/notes/wait_exponential_jitter-6ffc81dddcbaa6d3.yaml
tenacity/__init__.py
tenacity/_asyncio.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tests/test_after.py
new/tenacity-8.2.2/tests/test_after.py
--- old/tenacity-8.1.0/tests/test_after.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tests/test_after.py 2023-02-28 15:21:48.000000000
+0100
@@ -2,8 +2,8 @@
import random
import unittest.mock
-from tenacity import after_log
from tenacity import _utils # noqa
+from tenacity import after_log
from . import test_tenacity
@@ -24,9 +24,10 @@
retry_state =
test_tenacity.make_retry_state(self.previous_attempt_number,
delay_since_first_attempt)
fun = after_log(logger=logger, log_level=self.log_level) # use
default sec_format
fun(retry_state)
+ fn_name = "<unknown>" if retry_state.fn is None else
_utils.get_callback_name(retry_state.fn)
log.assert_called_once_with(
self.log_level,
- f"Finished call to '{_utils.get_callback_name(retry_state.fn)}' "
+ f"Finished call to '{fn_name}' "
f"after {sec_format % retry_state.seconds_since_start}(s), "
f"this was the {_utils.to_ordinal(retry_state.attempt_number)}
time calling it.",
)
@@ -42,9 +43,10 @@
retry_state =
test_tenacity.make_retry_state(self.previous_attempt_number,
delay_since_first_attempt)
fun = after_log(logger=logger, log_level=self.log_level,
sec_format=sec_format)
fun(retry_state)
+ fn_name = "<unknown>" if retry_state.fn is None else
_utils.get_callback_name(retry_state.fn)
log.assert_called_once_with(
self.log_level,
- f"Finished call to '{_utils.get_callback_name(retry_state.fn)}' "
+ f"Finished call to '{fn_name}' "
f"after {sec_format % retry_state.seconds_since_start}(s), "
f"this was the {_utils.to_ordinal(retry_state.attempt_number)}
time calling it.",
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tests/test_asyncio.py
new/tenacity-8.2.2/tests/test_asyncio.py
--- old/tenacity-8.1.0/tests/test_asyncio.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tests/test_asyncio.py 2023-02-28 15:21:48.000000000
+0100
@@ -18,9 +18,11 @@
import unittest
from functools import wraps
+import pytest
+
from tenacity import AsyncRetrying, RetryError
from tenacity import _asyncio as tasyncio
-from tenacity import retry, stop_after_attempt
+from tenacity import retry, retry_if_result, stop_after_attempt
from tenacity.wait import wait_fixed
from .test_tenacity import NoIOErrorAfterCount, current_time_ms
@@ -88,7 +90,6 @@
@asynctest
async def test_attempt_number_is_correct_for_interleaved_coroutines(self):
-
attempts = []
def after(retry_state):
@@ -156,6 +157,28 @@
t = current_time_ms() - start
self.assertLess(t, 1.1)
+ @asynctest
+ async def test_retry_with_result(self):
+ async def test():
+ attempts = 0
+ async for attempt in
tasyncio.AsyncRetrying(retry=retry_if_result(lambda x: x < 3)):
+ with attempt:
+ attempts += 1
+ attempt.retry_state.set_result(attempts)
+ return attempts
+
+ result = await test()
+
+ self.assertEqual(3, result)
+
+ @asynctest
+ async def test_async_retying_iterator(self):
+ thing = NoIOErrorAfterCount(5)
+ with pytest.raises(TypeError):
+ for attempts in AsyncRetrying():
+ with attempts:
+ await _async_function(thing)
+
if __name__ == "__main__":
unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tests/test_tenacity.py
new/tenacity-8.2.2/tests/test_tenacity.py
--- old/tenacity-8.1.0/tests/test_tenacity.py 2022-09-21 14:23:59.000000000
+0200
+++ new/tenacity-8.2.2/tests/test_tenacity.py 2023-02-28 15:21:48.000000000
+0100
@@ -155,10 +155,12 @@
self.assertTrue(r.stop(make_retry_state(4, 6546)))
def test_stop_after_delay(self):
- r = Retrying(stop=tenacity.stop_after_delay(1))
- self.assertFalse(r.stop(make_retry_state(2, 0.999)))
- self.assertTrue(r.stop(make_retry_state(2, 1)))
- self.assertTrue(r.stop(make_retry_state(2, 1.001)))
+ for delay in (1, datetime.timedelta(seconds=1)):
+ with self.subTest():
+ r = Retrying(stop=tenacity.stop_after_delay(delay))
+ self.assertFalse(r.stop(make_retry_state(2, 0.999)))
+ self.assertTrue(r.stop(make_retry_state(2, 1)))
+ self.assertTrue(r.stop(make_retry_state(2, 1.001)))
def test_legacy_explicit_stop_type(self):
Retrying(stop="stop_after_attempt")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tenacity-8.1.0/tox.ini new/tenacity-8.2.2/tox.ini
--- old/tenacity-8.1.0/tox.ini 2022-09-21 14:23:59.000000000 +0200
+++ new/tenacity-8.2.2/tox.ini 2023-02-28 15:21:48.000000000 +0100
@@ -1,5 +1,5 @@
[tox]
-envlist = py3{6,7,8,9,10}, pep8, pypy3
+envlist = py3{6,7,8,9,10,11}, pep8, pypy3
skip_missing_interpreters = True
[testenv]
@@ -10,9 +10,9 @@
pytest
typeguard
commands =
- py3{6,7,8,9,10},pypy3: pytest {posargs}
- py3{6,7,8,9,10},pypy3: sphinx-build -a -E -W -b doctest doc/source
doc/build
- py3{6,7,8,9,10},pypy3: sphinx-build -a -E -W -b html doc/source doc/build
+ py3{6,7,8,9,10,11},pypy3: pytest {posargs}
+ py3{6,7,8,9,10,11},pypy3: sphinx-build -a -E -W -b doctest doc/source
doc/build
+ py3{6,7,8,9,10,11},pypy3: sphinx-build -a -E -W -b html doc/source
doc/build
[testenv:pep8]
basepython = python3
@@ -31,6 +31,12 @@
commands =
black .
+[testenv:mypy]
+deps =
+ mypy>=1.0.0
+commands =
+ mypy tenacity
+
[testenv:black-ci]
deps =
black