Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-google-resumable-media for 
openSUSE:Factory checked in at 2022-01-23 18:38:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-google-resumable-media (Old)
 and      /work/SRC/openSUSE:Factory/.python-google-resumable-media.new.1938 
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-google-resumable-media"

Sun Jan 23 18:38:42 2022 rev:12 rq:948235 version:2.1.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-google-resumable-media/python-google-resumable-media.changes
      2021-09-30 23:45:00.992580751 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-google-resumable-media.new.1938/python-google-resumable-media.changes
    2022-01-23 18:38:44.353926393 +0100
@@ -1,0 +2,7 @@
+Sun Jan 23 15:54:35 UTC 2022 - Dirk M??ller <[email protected]>
+
+- update to 2.1.0:
+  * add support for Python 3.10
+  * Include ConnectionError and urllib3 exception as retriable 
+
+-------------------------------------------------------------------

Old:
----
  google-resumable-media-2.0.0.tar.gz

New:
----
  google-resumable-media-2.1.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-google-resumable-media.spec ++++++
--- /var/tmp/diff_new_pack.wqDn2m/_old  2022-01-23 18:38:44.957922328 +0100
+++ /var/tmp/diff_new_pack.wqDn2m/_new  2022-01-23 18:38:44.961922302 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-google-resumable-media
 #
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-google-resumable-media
-Version:        2.0.0
+Version:        2.1.0
 Release:        0
 Summary:        Utilities for Google Media Downloads and Resumable Uploads
 License:        Apache-2.0

++++++ google-resumable-media-2.0.0.tar.gz -> 
google-resumable-media-2.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-resumable-media-2.0.0/PKG-INFO 
new/google-resumable-media-2.1.0/PKG-INFO
--- old/google-resumable-media-2.0.0/PKG-INFO   2021-08-19 22:13:53.599198000 
+0200
+++ new/google-resumable-media-2.1.0/PKG-INFO   2021-10-25 19:36:02.955088000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: google-resumable-media
-Version: 2.0.0
+Version: 2.1.0
 Summary: Utilities for Google Media Downloads and Resumable Uploads
 Home-page: https://github.com/googleapis/google-resumable-media-python
 Author: Google Cloud Platform
@@ -16,6 +16,7 @@
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
 Classifier: Topic :: Internet
 Requires-Python: >= 3.6
 Provides-Extra: requests
@@ -55,6 +56,6 @@
 
 Apache 2.0 - See `the LICENSE`_ for more information.
 
-.. _the LICENSE: 
https://github.com/googleapis/google-resumable-media-python/blob/master/LICENSE
+.. _the LICENSE: 
https://github.com/googleapis/google-resumable-media-python/blob/main/LICENSE
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-resumable-media-2.0.0/README.rst 
new/google-resumable-media-2.1.0/README.rst
--- old/google-resumable-media-2.0.0/README.rst 2021-08-19 22:11:18.000000000 
+0200
+++ new/google-resumable-media-2.1.0/README.rst 2021-10-25 19:33:28.000000000 
+0200
@@ -31,4 +31,4 @@
 
 Apache 2.0 - See `the LICENSE`_ for more information.
 
-.. _the LICENSE: 
https://github.com/googleapis/google-resumable-media-python/blob/master/LICENSE
+.. _the LICENSE: 
https://github.com/googleapis/google-resumable-media-python/blob/main/LICENSE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google/_async_resumable_media/_upload.py 
new/google-resumable-media-2.1.0/google/_async_resumable_media/_upload.py
--- old/google-resumable-media-2.0.0/google/_async_resumable_media/_upload.py   
2021-08-19 22:11:18.000000000 +0200
+++ new/google-resumable-media-2.1.0/google/_async_resumable_media/_upload.py   
2021-10-25 19:33:28.000000000 +0200
@@ -277,7 +277,7 @@
 
         checksum_object = 
sync_helpers._get_checksum_object(self._checksum_type)
 
-        if checksum_object:
+        if checksum_object is not None:
             checksum_object.update(data)
             actual_checksum = sync_helpers.prepare_checksum_digest(
                 checksum_object.digest()
@@ -635,7 +635,7 @@
         """
         status_code = _helpers.require_status_code(
             response,
-            (http.client.OK, _async_resumable_media.PERMANENT_REDIRECT),
+            (http.client.OK, http.client.PERMANENT_REDIRECT),
             self._get_status_code,
             callback=self._make_invalid,
         )
@@ -776,7 +776,7 @@
         """
         _helpers.require_status_code(
             response,
-            (_async_resumable_media.PERMANENT_REDIRECT,),
+            (http.client.PERMANENT_REDIRECT,),
             self._get_status_code,
         )
         headers = self._get_headers(response)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google/_async_resumable_media/requests/__init__.py
 
new/google-resumable-media-2.1.0/google/_async_resumable_media/requests/__init__.py
--- 
old/google-resumable-media-2.0.0/google/_async_resumable_media/requests/__init__.py
 2021-08-19 22:11:18.000000000 +0200
+++ 
new/google-resumable-media-2.1.0/google/_async_resumable_media/requests/__init__.py
 2021-10-25 19:33:28.000000000 +0200
@@ -604,11 +604,11 @@
    upload._chunk_size = 4
    # Make three fake responses.
    fake_response0 = requests.Response()
-   fake_response0.status_code = resumable_media.PERMANENT_REDIRECT
+   fake_response0.status_code = http.client.PERMANENT_REDIRECT
    fake_response0.headers['range'] = 'bytes=0-3'
 
    fake_response1 = requests.Response()
-   fake_response1.status_code = resumable_media.PERMANENT_REDIRECT
+   fake_response1.status_code = http.client.PERMANENT_REDIRECT
    fake_response1.headers['range'] = 'bytes=0-7'
 
    fake_response2 = requests.Response()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google/_async_resumable_media/requests/download.py
 
new/google-resumable-media-2.1.0/google/_async_resumable_media/requests/download.py
--- 
old/google-resumable-media-2.0.0/google/_async_resumable_media/requests/download.py
 2021-08-19 22:11:18.000000000 +0200
+++ 
new/google-resumable-media-2.1.0/google/_async_resumable_media/requests/download.py
 2021-10-25 19:33:28.000000000 +0200
@@ -90,10 +90,7 @@
             self._stream.write(chunk)
             local_checksum_object.update(chunk)
 
-        if expected_checksum is None:
-            return
-
-        else:
+        if expected_checksum is not None:
             actual_checksum = sync_helpers.prepare_checksum_digest(
                 checksum_object.digest()
             )
@@ -216,9 +213,7 @@
             self._stream.write(chunk)
             checksum_object.update(chunk)
 
-        if expected_checksum is None:
-            return
-        else:
+        if expected_checksum is not None:
             actual_checksum = sync_helpers.prepare_checksum_digest(
                 checksum_object.digest()
             )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google/resumable_media/_helpers.py 
new/google-resumable-media-2.1.0/google/resumable_media/_helpers.py
--- old/google-resumable-media-2.0.0/google/resumable_media/_helpers.py 
2021-08-19 22:11:18.000000000 +0200
+++ new/google-resumable-media-2.1.0/google/resumable_media/_helpers.py 
2021-10-25 19:33:28.000000000 +0200
@@ -20,7 +20,6 @@
 import hashlib
 import logging
 import random
-import time
 import warnings
 
 from google.resumable_media import common
@@ -95,7 +94,8 @@
     """
     status_code = get_status_code(response)
     if status_code not in status_codes:
-        callback()
+        if status_code not in common.RETRYABLE:
+            callback()
         raise common.InvalidResponse(
             response,
             "Request failed with status code",
@@ -134,78 +134,6 @@
     return new_base_wait, new_base_wait + 0.001 * jitter_ms
 
 
-def wait_and_retry(func, get_status_code, retry_strategy):
-    """Attempts to retry a call to ``func`` until success.
-
-    Expects ``func`` to return an HTTP response and uses ``get_status_code``
-    to check if the response is retry-able.
-
-    ``func`` is expected to raise a failure status code as a
-    common.InvalidResponse, at which point this method will check the code
-    against the common.RETRIABLE list of retriable status codes.
-
-    Will retry until :meth:`~.RetryStrategy.retry_allowed` (on the current
-    ``retry_strategy``) returns :data:`False`. Uses
-    :func:`calculate_retry_wait` to double the wait time (with jitter) after
-    each attempt.
-
-    Args:
-        func (Callable): A callable that takes no arguments and produces
-            an HTTP response which will be checked as retry-able.
-        get_status_code (Callable[Any, int]): Helper to get a status code
-            from a response.
-        retry_strategy (~google.resumable_media.common.RetryStrategy): The
-            strategy to use if the request fails and must be retried.
-
-    Returns:
-        object: The return value of ``func``.
-    """
-    total_sleep = 0.0
-    num_retries = 0
-    # base_wait will be multiplied by the multiplier on the first retry.
-    base_wait = float(retry_strategy.initial_delay) / retry_strategy.multiplier
-
-    # Set the retriable_exception_type if possible. We expect requests to be
-    # present here and the transport to be using requests.exceptions errors,
-    # but due to loose coupling with the transport layer we can't guarantee it.
-    try:
-        connection_error_exceptions = _get_connection_error_classes()
-    except ImportError:
-        # We don't know the correct classes to use to catch connection errors,
-        # so an empty tuple here communicates "catch no exceptions".
-        connection_error_exceptions = ()
-
-    while True:  # return on success or when retries exhausted.
-        error = None
-        try:
-            response = func()
-        except connection_error_exceptions as e:
-            error = e  # Fall through to retry, if there are retries left.
-        except common.InvalidResponse as e:
-            # An InvalidResponse is only retriable if its status code matches.
-            # The `process_response()` method on a Download or Upload method
-            # will convert the status code into an exception.
-            if get_status_code(e.response) in common.RETRYABLE:
-                error = e  # Fall through to retry, if there are retries left.
-            else:
-                raise  # If the status code is not retriable, raise w/o retry.
-        else:
-            return response
-
-        if not retry_strategy.retry_allowed(total_sleep, num_retries):
-            # Retries are exhausted and no acceptable response was received.
-            # Raise the retriable_error.
-            raise error
-
-        base_wait, wait_time = calculate_retry_wait(
-            base_wait, retry_strategy.max_sleep, retry_strategy.multiplier
-        )
-
-        num_retries += 1
-        total_sleep += wait_time
-        time.sleep(wait_time)
-
-
 def _get_crc32c_object():
     """Get crc32c object
     Attempt to use the Google-CRC32c package. If it isn't available, try
@@ -374,22 +302,6 @@
         raise ValueError("checksum must be ``'md5'``, ``'crc32c'`` or 
``None``")
 
 
-def _get_connection_error_classes():
-    """Get the exception error classes.
-
-    Requests is a soft dependency here so that multiple transport layers can be
-    added in the future. This code is in a separate function here so that the
-    test framework can override its behavior to simulate requests being
-    unavailable."""
-
-    import requests.exceptions
-
-    return (
-        requests.exceptions.ConnectionError,
-        requests.exceptions.ChunkedEncodingError,
-    )
-
-
 class _DoNothingHash(object):
     """Do-nothing hash object.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google/resumable_media/_upload.py 
new/google-resumable-media-2.1.0/google/resumable_media/_upload.py
--- old/google-resumable-media-2.0.0/google/resumable_media/_upload.py  
2021-08-19 22:11:18.000000000 +0200
+++ new/google-resumable-media-2.1.0/google/resumable_media/_upload.py  
2021-10-25 19:33:28.000000000 +0200
@@ -289,7 +289,7 @@
             raise TypeError("`data` must be bytes, received", type(data))
 
         checksum_object = _helpers._get_checksum_object(self._checksum_type)
-        if checksum_object:
+        if checksum_object is not None:
             checksum_object.update(data)
             actual_checksum = 
_helpers.prepare_checksum_digest(checksum_object.digest())
             metadata_key = _helpers._get_metadata_key(self._checksum_type)
@@ -670,7 +670,7 @@
         """
         status_code = _helpers.require_status_code(
             response,
-            (http.client.OK, resumable_media.PERMANENT_REDIRECT),
+            (http.client.OK, http.client.PERMANENT_REDIRECT),
             self._get_status_code,
             callback=self._make_invalid,
         )
@@ -814,7 +814,7 @@
         .. _sans-I/O: https://sans-io.readthedocs.io/
         """
         _helpers.require_status_code(
-            response, (resumable_media.PERMANENT_REDIRECT,), 
self._get_status_code
+            response, (http.client.PERMANENT_REDIRECT,), self._get_status_code
         )
         headers = self._get_headers(response)
         if _helpers.RANGE_HEADER in headers:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google/resumable_media/common.py 
new/google-resumable-media-2.1.0/google/resumable_media/common.py
--- old/google-resumable-media-2.0.0/google/resumable_media/common.py   
2021-08-19 22:11:18.000000000 +0200
+++ new/google-resumable-media-2.1.0/google/resumable_media/common.py   
2021-10-25 19:33:28.000000000 +0200
@@ -25,35 +25,39 @@
 
 UPLOAD_CHUNK_SIZE = 262144  # 256 * 1024
 """int: Chunks in a resumable upload must come in multiples of 256 KB."""
-PERMANENT_REDIRECT = 308
+
+PERMANENT_REDIRECT = http.client.PERMANENT_REDIRECT
 """int: Permanent redirect status code.
 
+.. note::
+   This is a backward-compatibility alias.
+
 It is used by Google services to indicate some (but not all) of
 a resumable upload has been completed.
 
-``http.client.PERMANENT_REDIRECT`` was added in Python 3.5, so
-can't be used in a "general" code base.
-
 For more information, see `RFC 7238`_.
 
 .. _RFC 7238: https://tools.ietf.org/html/rfc7238
 """
-TOO_MANY_REQUESTS = 429
+
+TOO_MANY_REQUESTS = http.client.TOO_MANY_REQUESTS
 """int: Status code indicating rate-limiting.
 
-``http.client.TOO_MANY_REQUESTS`` was added in Python 3.3, so
-can't be used in a "general" code base.
+.. note::
+   This is a backward-compatibility alias.
 
 For more information, see `RFC 6585`_.
 
 .. _RFC 6585: https://tools.ietf.org/html/rfc6585#section-4
 """
+
 MAX_SLEEP = 64.0
 """float: Maximum amount of time allowed between requests.
 
 Used during the retry process for sleep after a failed request.
 Chosen since it is the power of two nearest to one minute.
 """
+
 MAX_CUMULATIVE_RETRY = 600.0
 """float: Maximum total sleep time allowed during retry process.
 
@@ -62,7 +66,8 @@
 """
 
 RETRYABLE = (
-    TOO_MANY_REQUESTS,  # 429
+    http.client.TOO_MANY_REQUESTS,  # 429
+    http.client.REQUEST_TIMEOUT,  # 408
     http.client.INTERNAL_SERVER_ERROR,  # 500
     http.client.BAD_GATEWAY,  # 502
     http.client.SERVICE_UNAVAILABLE,  # 503
@@ -158,9 +163,10 @@
         """Check if another retry is allowed.
 
         Args:
-            total_sleep (float): The amount of sleep accumulated by the caller.
-            num_retries (int): The number of retries already attempted by
-                the caller.
+            total_sleep (float): With another retry, the amount of sleep that
+                will be accumulated by the caller.
+            num_retries (int): With another retry, the number of retries that
+                will be attempted by the caller.
 
         Returns:
             bool: Indicating if another retry is allowed (depending on either
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google/resumable_media/requests/__init__.py 
new/google-resumable-media-2.1.0/google/resumable_media/requests/__init__.py
--- 
old/google-resumable-media-2.0.0/google/resumable_media/requests/__init__.py    
    2021-08-19 22:11:18.000000000 +0200
+++ 
new/google-resumable-media-2.1.0/google/resumable_media/requests/__init__.py    
    2021-10-25 19:33:28.000000000 +0200
@@ -604,11 +604,11 @@
    upload._chunk_size = 4
    # Make three fake responses.
    fake_response0 = requests.Response()
-   fake_response0.status_code = resumable_media.PERMANENT_REDIRECT
+   fake_response0.status_code = http.client.PERMANENT_REDIRECT
    fake_response0.headers['range'] = 'bytes=0-3'
 
    fake_response1 = requests.Response()
-   fake_response1.status_code = resumable_media.PERMANENT_REDIRECT
+   fake_response1.status_code = http.client.PERMANENT_REDIRECT
    fake_response1.headers['range'] = 'bytes=0-7'
 
    fake_response2 = requests.Response()
@@ -631,7 +631,7 @@
 
    >>> response0 = upload.transmit_next_chunk(transport)
    >>> response0
-   <Response [308]>
+   <Response [HTTPStatus.PERMANENT_REDIRECT]>
    >>> upload.finished
    False
    >>> upload.bytes_uploaded == upload.chunk_size
@@ -639,7 +639,7 @@
    >>>
    >>> response1 = upload.transmit_next_chunk(transport)
    >>> response1
-   <Response [308]>
+   <Response [HTTPStatus.PERMANENT_REDIRECT]>
    >>> upload.finished
    False
    >>> upload.bytes_uploaded == 2 * upload.chunk_size
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google/resumable_media/requests/_request_helpers.py
 
new/google-resumable-media-2.1.0/google/resumable_media/requests/_request_helpers.py
--- 
old/google-resumable-media-2.0.0/google/resumable_media/requests/_request_helpers.py
        2021-08-19 22:11:18.000000000 +0200
+++ 
new/google-resumable-media-2.1.0/google/resumable_media/requests/_request_helpers.py
        2021-10-25 19:33:28.000000000 +0200
@@ -17,9 +17,13 @@
 This utilities are explicitly catered to ``requests``-like transports.
 """
 
+import requests.exceptions
+import urllib3.exceptions
 
-from google.resumable_media import common
+import time
 
+from google.resumable_media import common
+from google.resumable_media import _helpers
 
 _DEFAULT_RETRY_STRATEGY = common.RetryStrategy()
 _SINGLE_GET_CHUNK_SIZE = 8192
@@ -30,6 +34,13 @@
 # The number of seconds to wait between bytes sent from the server.
 _DEFAULT_READ_TIMEOUT = 60
 
+_CONNECTION_ERROR_CLASSES = (
+    requests.exceptions.ConnectionError,
+    requests.exceptions.ChunkedEncodingError,
+    urllib3.exceptions.ProtocolError,
+    ConnectionError,  # Python 3.x only, superclass of ConnectionResetError.
+)
+
 
 class RequestsMixin(object):
     """Mix-in class implementing ``requests``-specific behavior.
@@ -93,3 +104,69 @@
             )
             response._content_consumed = True
         return response._content
+
+
+def wait_and_retry(func, get_status_code, retry_strategy):
+    """Attempts to retry a call to ``func`` until success.
+
+    Expects ``func`` to return an HTTP response and uses ``get_status_code``
+    to check if the response is retry-able.
+
+    ``func`` is expected to raise a failure status code as a
+    common.InvalidResponse, at which point this method will check the code
+    against the common.RETRIABLE list of retriable status codes.
+
+    Will retry until :meth:`~.RetryStrategy.retry_allowed` (on the current
+    ``retry_strategy``) returns :data:`False`. Uses
+    :func:`_helpers.calculate_retry_wait` to double the wait time (with jitter)
+    after each attempt.
+
+    Args:
+        func (Callable): A callable that takes no arguments and produces
+            an HTTP response which will be checked as retry-able.
+        get_status_code (Callable[Any, int]): Helper to get a status code
+            from a response.
+        retry_strategy (~google.resumable_media.common.RetryStrategy): The
+            strategy to use if the request fails and must be retried.
+
+    Returns:
+        object: The return value of ``func``.
+    """
+    total_sleep = 0.0
+    num_retries = 0
+    # base_wait will be multiplied by the multiplier on the first retry.
+    base_wait = float(retry_strategy.initial_delay) / retry_strategy.multiplier
+
+    # Set the retriable_exception_type if possible. We expect requests to be
+    # present here and the transport to be using requests.exceptions errors,
+    # but due to loose coupling with the transport layer we can't guarantee it.
+
+    while True:  # return on success or when retries exhausted.
+        error = None
+        try:
+            response = func()
+        except _CONNECTION_ERROR_CLASSES as e:
+            error = e  # Fall through to retry, if there are retries left.
+        except common.InvalidResponse as e:
+            # An InvalidResponse is only retriable if its status code matches.
+            # The `process_response()` method on a Download or Upload method
+            # will convert the status code into an exception.
+            if get_status_code(e.response) in common.RETRYABLE:
+                error = e  # Fall through to retry, if there are retries left.
+            else:
+                raise  # If the status code is not retriable, raise w/o retry.
+        else:
+            return response
+
+        base_wait, wait_time = _helpers.calculate_retry_wait(
+            base_wait, retry_strategy.max_sleep, retry_strategy.multiplier
+        )
+        num_retries += 1
+        total_sleep += wait_time
+
+        # Check if (another) retry is allowed. If retries are exhausted and
+        # no acceptable response was received, raise the retriable error.
+        if not retry_strategy.retry_allowed(total_sleep, num_retries):
+            raise error
+
+        time.sleep(wait_time)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google/resumable_media/requests/download.py 
new/google-resumable-media-2.1.0/google/resumable_media/requests/download.py
--- 
old/google-resumable-media-2.0.0/google/resumable_media/requests/download.py    
    2021-08-19 22:11:18.000000000 +0200
+++ 
new/google-resumable-media-2.1.0/google/resumable_media/requests/download.py    
    2021-10-25 19:33:28.000000000 +0200
@@ -106,9 +106,7 @@
                 self._stream.write(chunk)
                 local_checksum_object.update(chunk)
 
-        if expected_checksum is None:
-            return
-        else:
+        if expected_checksum is not None:
             actual_checksum = 
_helpers.prepare_checksum_digest(checksum_object.digest())
             if actual_checksum != expected_checksum:
                 msg = _CHECKSUM_MISMATCH.format(
@@ -173,7 +171,7 @@
 
             return result
 
-        return _helpers.wait_and_retry(
+        return _request_helpers.wait_and_retry(
             retriable_request, self._get_status_code, self._retry_strategy
         )
 
@@ -242,9 +240,7 @@
                 checksum_object.update(chunk)
             response._content_consumed = True
 
-        if expected_checksum is None:
-            return
-        else:
+        if expected_checksum is not None:
             actual_checksum = 
_helpers.prepare_checksum_digest(checksum_object.digest())
 
             if actual_checksum != expected_checksum:
@@ -310,7 +306,7 @@
 
             return result
 
-        return _helpers.wait_and_retry(
+        return _request_helpers.wait_and_retry(
             retriable_request, self._get_status_code, self._retry_strategy
         )
 
@@ -385,7 +381,7 @@
             self._process_response(result)
             return result
 
-        return _helpers.wait_and_retry(
+        return _request_helpers.wait_and_retry(
             retriable_request, self._get_status_code, self._retry_strategy
         )
 
@@ -461,7 +457,7 @@
             self._process_response(result)
             return result
 
-        return _helpers.wait_and_retry(
+        return _request_helpers.wait_and_retry(
             retriable_request, self._get_status_code, self._retry_strategy
         )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google/resumable_media/requests/upload.py 
new/google-resumable-media-2.1.0/google/resumable_media/requests/upload.py
--- old/google-resumable-media-2.0.0/google/resumable_media/requests/upload.py  
2021-08-19 22:11:18.000000000 +0200
+++ new/google-resumable-media-2.1.0/google/resumable_media/requests/upload.py  
2021-10-25 19:33:28.000000000 +0200
@@ -20,7 +20,6 @@
 
 
 from google.resumable_media import _upload
-from google.resumable_media import _helpers
 from google.resumable_media.requests import _request_helpers
 
 
@@ -80,7 +79,7 @@
 
             return result
 
-        return _helpers.wait_and_retry(
+        return _request_helpers.wait_and_retry(
             retriable_request, self._get_status_code, self._retry_strategy
         )
 
@@ -151,7 +150,7 @@
 
             return result
 
-        return _helpers.wait_and_retry(
+        return _request_helpers.wait_and_retry(
             retriable_request, self._get_status_code, self._retry_strategy
         )
 
@@ -418,7 +417,7 @@
 
             return result
 
-        return _helpers.wait_and_retry(
+        return _request_helpers.wait_and_retry(
             retriable_request, self._get_status_code, self._retry_strategy
         )
 
@@ -476,7 +475,7 @@
            ...
            >>> error
            InvalidResponse('Request failed with status code', 400,
-                           'Expected one of', <HTTPStatus.OK: 200>, 308)
+                           'Expected one of', <HTTPStatus.OK: 200>, 
<HTTPStatus.PERMANENT_REDIRECT: 308>)
            >>> error.response
            <Response [400]>
 
@@ -496,7 +495,7 @@
 
         Raises:
             ~google.resumable_media.common.InvalidResponse: If the status
-                code is not 200 or 308.
+                code is not 200 or http.client.PERMANENT_REDIRECT.
             ~google.resumable_media.common.DataCorruption: If this is the final
                 chunk, a checksum validation was requested, and the checksum
                 does not match or is not available.
@@ -513,7 +512,7 @@
 
             return result
 
-        return _helpers.wait_and_retry(
+        return _request_helpers.wait_and_retry(
             retriable_request, self._get_status_code, self._retry_strategy
         )
 
@@ -552,6 +551,6 @@
 
             return result
 
-        return _helpers.wait_and_retry(
+        return _request_helpers.wait_and_retry(
             retriable_request, self._get_status_code, self._retry_strategy
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/google_resumable_media.egg-info/PKG-INFO 
new/google-resumable-media-2.1.0/google_resumable_media.egg-info/PKG-INFO
--- old/google-resumable-media-2.0.0/google_resumable_media.egg-info/PKG-INFO   
2021-08-19 22:13:53.000000000 +0200
+++ new/google-resumable-media-2.1.0/google_resumable_media.egg-info/PKG-INFO   
2021-10-25 19:36:02.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: google-resumable-media
-Version: 2.0.0
+Version: 2.1.0
 Summary: Utilities for Google Media Downloads and Resumable Uploads
 Home-page: https://github.com/googleapis/google-resumable-media-python
 Author: Google Cloud Platform
@@ -16,6 +16,7 @@
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
 Classifier: Topic :: Internet
 Requires-Python: >= 3.6
 Provides-Extra: requests
@@ -55,6 +56,6 @@
 
 Apache 2.0 - See `the LICENSE`_ for more information.
 
-.. _the LICENSE: 
https://github.com/googleapis/google-resumable-media-python/blob/master/LICENSE
+.. _the LICENSE: 
https://github.com/googleapis/google-resumable-media-python/blob/main/LICENSE
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-resumable-media-2.0.0/setup.py 
new/google-resumable-media-2.1.0/setup.py
--- old/google-resumable-media-2.0.0/setup.py   2021-08-19 22:11:18.000000000 
+0200
+++ new/google-resumable-media-2.1.0/setup.py   2021-10-25 19:33:28.000000000 
+0200
@@ -35,7 +35,7 @@
 
 setuptools.setup(
     name='google-resumable-media',
-    version = "2.0.0",
+    version = "2.1.0",
     description='Utilities for Google Media Downloads and Resumable Uploads',
     author='Google Cloud Platform',
     author_email='[email protected]',
@@ -61,6 +61,7 @@
         'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
+        'Programming Language :: Python :: 3.10',
         'Topic :: Internet',
     ],
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/tests/system/requests/test_upload.py 
new/google-resumable-media-2.1.0/tests/system/requests/test_upload.py
--- old/google-resumable-media-2.0.0/tests/system/requests/test_upload.py       
2021-08-19 22:11:18.000000000 +0200
+++ new/google-resumable-media-2.1.0/tests/system/requests/test_upload.py       
2021-10-25 19:33:28.000000000 +0200
@@ -182,7 +182,7 @@
             )
         else:
             assert upload.bytes_uploaded == num_chunks * upload.chunk_size
-            assert response.status_code == resumable_media.PERMANENT_REDIRECT
+            assert response.status_code == http.client.PERMANENT_REDIRECT
 
     return num_chunks
 
@@ -427,7 +427,7 @@
     upload._bytes_uploaded = 0  # Make ``bytes_uploaded`` wrong as well.
     # Recover the (artifically) invalid upload.
     response = upload.recover(transport)
-    assert response.status_code == resumable_media.PERMANENT_REDIRECT
+    assert response.status_code == http.client.PERMANENT_REDIRECT
     assert not upload.invalid
     assert upload.bytes_uploaded == chunk_size
     assert stream.tell() == chunk_size
@@ -456,7 +456,7 @@
     check_initiate(response, upload, stream, authorized_transport, metadata)
     # Make the first request.
     response = upload.transmit_next_chunk(authorized_transport)
-    assert response.status_code == resumable_media.PERMANENT_REDIRECT
+    assert response.status_code == http.client.PERMANENT_REDIRECT
     # Call upload.recover().
     sabotage_and_recover(upload, stream, authorized_transport, chunk_size)
     # Now stream what remains.
@@ -508,7 +508,7 @@
 
         assert not upload.finished
         assert upload.bytes_uploaded == end_byte + 1
-        assert response.status_code == resumable_media.PERMANENT_REDIRECT
+        assert response.status_code == http.client.PERMANENT_REDIRECT
         assert response.content == b""
 
         self._check_range_sent(response, start_byte, end_byte, "*")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/tests/unit/requests/test__helpers.py 
new/google-resumable-media-2.1.0/tests/unit/requests/test__helpers.py
--- old/google-resumable-media-2.0.0/tests/unit/requests/test__helpers.py       
2021-08-19 22:11:18.000000000 +0200
+++ new/google-resumable-media-2.1.0/tests/unit/requests/test__helpers.py       
2021-10-25 19:33:28.000000000 +0200
@@ -15,7 +15,12 @@
 import http.client
 
 import mock
+import pytest
 
+import requests.exceptions
+import urllib3.exceptions
+
+from google.resumable_media import common
 from google.resumable_media.requests import _request_helpers
 
 EXPECTED_TIMEOUT = (61, 60)
@@ -57,3 +62,309 @@
 
 def _make_response(status_code):
     return mock.Mock(status_code=status_code, spec=["status_code"])
+
+
+def _get_status_code(response):
+    return response.status_code
+
+
+class Test_wait_and_retry(object):
+    def test_success_no_retry(self):
+        truthy = http.client.OK
+        assert truthy not in common.RETRYABLE
+        response = _make_response(truthy)
+
+        func = mock.Mock(return_value=response, spec=[])
+        retry_strategy = common.RetryStrategy()
+        ret_val = _request_helpers.wait_and_retry(
+            func, _get_status_code, retry_strategy
+        )
+
+        assert ret_val is response
+        func.assert_called_once_with()
+
+    @mock.patch("time.sleep")
+    @mock.patch("random.randint")
+    def test_success_with_retry(self, randint_mock, sleep_mock):
+        randint_mock.side_effect = [125, 625, 375]
+
+        status_codes = (
+            http.client.INTERNAL_SERVER_ERROR,
+            http.client.BAD_GATEWAY,
+            http.client.SERVICE_UNAVAILABLE,
+            http.client.NOT_FOUND,
+        )
+        responses = [_make_response(status_code) for status_code in 
status_codes]
+
+        def raise_response():
+            raise common.InvalidResponse(responses.pop(0))
+
+        func = mock.Mock(side_effect=raise_response)
+
+        retry_strategy = common.RetryStrategy()
+        try:
+            _request_helpers.wait_and_retry(func, _get_status_code, 
retry_strategy)
+        except common.InvalidResponse as e:
+            ret_val = e.response
+
+        assert ret_val.status_code == status_codes[-1]
+        assert status_codes[-1] not in common.RETRYABLE
+
+        assert func.call_count == 4
+        assert func.mock_calls == [mock.call()] * 4
+
+        assert randint_mock.call_count == 3
+        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 3
+
+        assert sleep_mock.call_count == 3
+        sleep_mock.assert_any_call(1.125)
+        sleep_mock.assert_any_call(2.625)
+        sleep_mock.assert_any_call(4.375)
+
+    @mock.patch("time.sleep")
+    @mock.patch("random.randint")
+    def test_success_with_retry_custom_delay(self, randint_mock, sleep_mock):
+        randint_mock.side_effect = [125, 625, 375]
+
+        status_codes = (
+            http.client.INTERNAL_SERVER_ERROR,
+            http.client.BAD_GATEWAY,
+            http.client.SERVICE_UNAVAILABLE,
+            http.client.NOT_FOUND,
+        )
+        responses = [_make_response(status_code) for status_code in 
status_codes]
+
+        def raise_response():
+            raise common.InvalidResponse(responses.pop(0))
+
+        func = mock.Mock(side_effect=raise_response)
+
+        retry_strategy = common.RetryStrategy(initial_delay=3.0, multiplier=4)
+        try:
+            _request_helpers.wait_and_retry(func, _get_status_code, 
retry_strategy)
+        except common.InvalidResponse as e:
+            ret_val = e.response
+
+        assert ret_val.status_code == status_codes[-1]
+        assert status_codes[-1] not in common.RETRYABLE
+
+        assert func.call_count == 4
+        assert func.mock_calls == [mock.call()] * 4
+
+        assert randint_mock.call_count == 3
+        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 3
+
+        assert sleep_mock.call_count == 3
+        sleep_mock.assert_any_call(3.125)  # initial delay 3 + jitter 0.125
+        sleep_mock.assert_any_call(
+            12.625
+        )  # previous delay 3 * multiplier 4 + jitter 0.625
+        sleep_mock.assert_any_call(
+            48.375
+        )  # previous delay 12 * multiplier 4 + jitter 0.375
+
+    @mock.patch("time.sleep")
+    @mock.patch("random.randint")
+    def test_success_with_retry_connection_error(self, randint_mock, 
sleep_mock):
+        randint_mock.side_effect = [125, 625, 375]
+
+        response = _make_response(http.client.NOT_FOUND)
+        responses = [
+            ConnectionResetError,  # Subclass of ConnectionError
+            urllib3.exceptions.ConnectionError,
+            requests.exceptions.ConnectionError,
+            response,
+        ]
+        func = mock.Mock(side_effect=responses, spec=[])
+
+        retry_strategy = common.RetryStrategy()
+        ret_val = _request_helpers.wait_and_retry(
+            func, _get_status_code, retry_strategy
+        )
+
+        assert ret_val == responses[-1]
+
+        assert func.call_count == 4
+        assert func.mock_calls == [mock.call()] * 4
+
+        assert randint_mock.call_count == 3
+        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 3
+
+        assert sleep_mock.call_count == 3
+        sleep_mock.assert_any_call(1.125)
+        sleep_mock.assert_any_call(2.625)
+        sleep_mock.assert_any_call(4.375)
+
+    @mock.patch(u"time.sleep")
+    @mock.patch(u"random.randint")
+    def test_success_with_retry_chunked_encoding_error(self, randint_mock, 
sleep_mock):
+        randint_mock.side_effect = [125, 625, 375]
+
+        response = _make_response(http.client.NOT_FOUND)
+        responses = [
+            requests.exceptions.ChunkedEncodingError,
+            requests.exceptions.ChunkedEncodingError,
+            response,
+        ]
+        func = mock.Mock(side_effect=responses, spec=[])
+
+        retry_strategy = common.RetryStrategy()
+        ret_val = _request_helpers.wait_and_retry(
+            func, _get_status_code, retry_strategy
+        )
+
+        assert ret_val == responses[-1]
+
+        assert func.call_count == 3
+        assert func.mock_calls == [mock.call()] * 3
+
+        assert randint_mock.call_count == 2
+        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 2
+
+        assert sleep_mock.call_count == 2
+        sleep_mock.assert_any_call(1.125)
+        sleep_mock.assert_any_call(2.625)
+
+    @mock.patch("time.sleep")
+    @mock.patch("random.randint")
+    def test_retry_exceeds_max_cumulative(self, randint_mock, sleep_mock):
+        randint_mock.side_effect = [875, 0, 375, 500, 500, 250, 125]
+
+        status_codes = (
+            http.client.SERVICE_UNAVAILABLE,
+            http.client.GATEWAY_TIMEOUT,
+            common.TOO_MANY_REQUESTS,
+            http.client.INTERNAL_SERVER_ERROR,
+            http.client.SERVICE_UNAVAILABLE,
+            http.client.BAD_GATEWAY,
+            common.TOO_MANY_REQUESTS,
+        )
+        responses = [_make_response(status_code) for status_code in 
status_codes]
+
+        def raise_response():
+            raise common.InvalidResponse(responses.pop(0))
+
+        func = mock.Mock(side_effect=raise_response)
+
+        retry_strategy = common.RetryStrategy(max_cumulative_retry=100.0)
+        try:
+            _request_helpers.wait_and_retry(func, _get_status_code, 
retry_strategy)
+        except common.InvalidResponse as e:
+            ret_val = e.response
+
+        assert ret_val.status_code == status_codes[-1]
+        assert status_codes[-1] in common.RETRYABLE
+
+        assert func.call_count == 7
+        assert func.mock_calls == [mock.call()] * 7
+
+        assert randint_mock.call_count == 7
+        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 7
+
+        assert sleep_mock.call_count == 6
+        sleep_mock.assert_any_call(1.875)
+        sleep_mock.assert_any_call(2.0)
+        sleep_mock.assert_any_call(4.375)
+        sleep_mock.assert_any_call(8.5)
+        sleep_mock.assert_any_call(16.5)
+        sleep_mock.assert_any_call(32.25)
+
+    @mock.patch("time.sleep")
+    @mock.patch("random.randint")
+    def test_retry_exceeds_max_retries(self, randint_mock, sleep_mock):
+        randint_mock.side_effect = [875, 0, 375, 500, 500, 250, 125]
+
+        status_codes = (
+            http.client.SERVICE_UNAVAILABLE,
+            http.client.GATEWAY_TIMEOUT,
+            common.TOO_MANY_REQUESTS,
+            http.client.INTERNAL_SERVER_ERROR,
+            http.client.SERVICE_UNAVAILABLE,
+            http.client.BAD_GATEWAY,
+            common.TOO_MANY_REQUESTS,
+        )
+        responses = [_make_response(status_code) for status_code in 
status_codes]
+
+        def raise_response():
+            raise common.InvalidResponse(responses.pop(0))
+
+        func = mock.Mock(side_effect=raise_response)
+
+        retry_strategy = common.RetryStrategy(max_retries=6)
+        try:
+            _request_helpers.wait_and_retry(func, _get_status_code, 
retry_strategy)
+        except common.InvalidResponse as e:
+            ret_val = e.response
+
+        assert ret_val.status_code == status_codes[-1]
+        assert status_codes[-1] in common.RETRYABLE
+
+        assert func.call_count == 7
+        assert func.mock_calls == [mock.call()] * 7
+
+        assert randint_mock.call_count == 7
+        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 7
+
+        assert sleep_mock.call_count == 6
+        sleep_mock.assert_any_call(1.875)
+        sleep_mock.assert_any_call(2.0)
+        sleep_mock.assert_any_call(4.375)
+        sleep_mock.assert_any_call(8.5)
+        sleep_mock.assert_any_call(16.5)
+        sleep_mock.assert_any_call(32.25)
+
+    @mock.patch("time.sleep")
+    @mock.patch("random.randint")
+    def test_retry_zero_max_retries(self, randint_mock, sleep_mock):
+        randint_mock.side_effect = [875, 0, 375]
+
+        status_codes = (
+            http.client.SERVICE_UNAVAILABLE,
+            http.client.GATEWAY_TIMEOUT,
+            common.TOO_MANY_REQUESTS,
+        )
+        responses = [_make_response(status_code) for status_code in 
status_codes]
+
+        def raise_response():
+            raise common.InvalidResponse(responses.pop(0))
+
+        func = mock.Mock(side_effect=raise_response)
+
+        retry_strategy = common.RetryStrategy(max_retries=0)
+        try:
+            _request_helpers.wait_and_retry(func, _get_status_code, 
retry_strategy)
+        except common.InvalidResponse as e:
+            ret_val = e.response
+
+        assert func.call_count == 1
+        assert func.mock_calls == [mock.call()] * 1
+        assert ret_val.status_code == status_codes[0]
+
+        assert randint_mock.call_count == 1
+        assert sleep_mock.call_count == 0
+
+    @mock.patch("time.sleep")
+    @mock.patch("random.randint")
+    def test_retry_exceeded_reraises_connection_error(self, randint_mock, 
sleep_mock):
+        randint_mock.side_effect = [875, 0, 375, 500, 500, 250, 125]
+
+        responses = [requests.exceptions.ConnectionError] * 7
+        func = mock.Mock(side_effect=responses, spec=[])
+
+        retry_strategy = common.RetryStrategy(max_cumulative_retry=100.0)
+        with pytest.raises(requests.exceptions.ConnectionError):
+            _request_helpers.wait_and_retry(func, _get_status_code, 
retry_strategy)
+
+        assert func.call_count == 7
+        assert func.mock_calls == [mock.call()] * 7
+
+        assert randint_mock.call_count == 7
+        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 7
+
+        assert sleep_mock.call_count == 6
+        sleep_mock.assert_any_call(1.875)
+        sleep_mock.assert_any_call(2.0)
+        sleep_mock.assert_any_call(4.375)
+        sleep_mock.assert_any_call(8.5)
+        sleep_mock.assert_any_call(16.5)
+        sleep_mock.assert_any_call(32.25)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/tests/unit/requests/test_upload.py 
new/google-resumable-media-2.1.0/tests/unit/requests/test_upload.py
--- old/google-resumable-media-2.0.0/tests/unit/requests/test_upload.py 
2021-08-19 22:11:18.000000000 +0200
+++ new/google-resumable-media-2.1.0/tests/unit/requests/test_upload.py 
2021-10-25 19:33:28.000000000 +0200
@@ -18,7 +18,6 @@
 
 import mock
 
-from google import resumable_media
 import google.resumable_media.requests.upload as upload_mod
 
 
@@ -254,9 +253,7 @@
         upload._chunk_size = chunk_size
         # Make a fake 308 response.
         response_headers = {"range": "bytes=0-{:d}".format(chunk_size - 1)}
-        transport = self._chunk_mock(
-            resumable_media.PERMANENT_REDIRECT, response_headers
-        )
+        transport = self._chunk_mock(http.client.PERMANENT_REDIRECT, 
response_headers)
         # Check the state before the request.
         assert upload._bytes_uploaded == 0
 
@@ -290,9 +287,7 @@
 
         # Make a fake 308 response.
         response_headers = {"range": "bytes=0-{:d}".format(chunk_size - 1)}
-        transport = self._chunk_mock(
-            resumable_media.PERMANENT_REDIRECT, response_headers
-        )
+        transport = self._chunk_mock(http.client.PERMANENT_REDIRECT, 
response_headers)
 
         # Make request and check the return value (against the mock).
         upload.transmit_next_chunk(transport, timeout=12.6)
@@ -320,7 +315,7 @@
 
         end = 55555
         headers = {"range": "bytes=0-{:d}".format(end)}
-        transport = self._chunk_mock(resumable_media.PERMANENT_REDIRECT, 
headers)
+        transport = self._chunk_mock(http.client.PERMANENT_REDIRECT, headers)
 
         ret_val = upload.recover(transport)
         assert ret_val is transport.request.return_value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/tests/unit/test__helpers.py 
new/google-resumable-media-2.1.0/tests/unit/test__helpers.py
--- old/google-resumable-media-2.0.0/tests/unit/test__helpers.py        
2021-08-19 22:11:18.000000000 +0200
+++ new/google-resumable-media-2.1.0/tests/unit/test__helpers.py        
2021-10-25 19:33:28.000000000 +0200
@@ -19,7 +19,6 @@
 
 import mock
 import pytest
-import requests.exceptions
 
 from google.resumable_media import _helpers
 from google.resumable_media import common
@@ -125,6 +124,28 @@
         assert error.args[3:] == status_codes
         callback.assert_called_once_with()
 
+    def test_retryable_failure_without_callback(self):
+        status_codes = (http.client.OK,)
+        retryable_responses = [
+            _make_response(status_code) for status_code in common.RETRYABLE
+        ]
+        callback = mock.Mock(spec=[])
+        for retryable_response in retryable_responses:
+            with pytest.raises(common.InvalidResponse) as exc_info:
+                _helpers.require_status_code(
+                    retryable_response,
+                    status_codes,
+                    self._get_status_code,
+                    callback=callback,
+                )
+
+            error = exc_info.value
+            assert error.response is retryable_response
+            assert len(error.args) == 4
+            assert error.args[1] == retryable_response.status_code
+            assert error.args[3:] == status_codes
+            callback.assert_not_called()
+
 
 class Test_calculate_retry_wait(object):
     @mock.patch("random.randint", return_value=125)
@@ -160,262 +181,10 @@
         randint_mock.assert_called_once_with(0, 1000)
 
 
-class Test_wait_and_retry(object):
-    def test_success_no_retry(self):
-        truthy = http.client.OK
-        assert truthy not in common.RETRYABLE
-        response = _make_response(truthy)
-
-        func = mock.Mock(return_value=response, spec=[])
-        retry_strategy = common.RetryStrategy()
-        ret_val = _helpers.wait_and_retry(func, _get_status_code, 
retry_strategy)
-
-        assert ret_val is response
-        func.assert_called_once_with()
-
-    @mock.patch("time.sleep")
-    @mock.patch("random.randint")
-    def test_success_with_retry(self, randint_mock, sleep_mock):
-        randint_mock.side_effect = [125, 625, 375]
-
-        status_codes = (
-            http.client.INTERNAL_SERVER_ERROR,
-            http.client.BAD_GATEWAY,
-            http.client.SERVICE_UNAVAILABLE,
-            http.client.NOT_FOUND,
-        )
-        responses = [_make_response(status_code) for status_code in 
status_codes]
-
-        def raise_response():
-            raise common.InvalidResponse(responses.pop(0))
-
-        func = mock.Mock(side_effect=raise_response)
-
-        retry_strategy = common.RetryStrategy()
-        try:
-            _helpers.wait_and_retry(func, _get_status_code, retry_strategy)
-        except common.InvalidResponse as e:
-            ret_val = e.response
-
-        assert ret_val.status_code == status_codes[-1]
-        assert status_codes[-1] not in common.RETRYABLE
-
-        assert func.call_count == 4
-        assert func.mock_calls == [mock.call()] * 4
-
-        assert randint_mock.call_count == 3
-        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 3
-
-        assert sleep_mock.call_count == 3
-        sleep_mock.assert_any_call(1.125)
-        sleep_mock.assert_any_call(2.625)
-        sleep_mock.assert_any_call(4.375)
-
-    @mock.patch("time.sleep")
-    @mock.patch("random.randint")
-    def test_success_with_retry_custom_delay(self, randint_mock, sleep_mock):
-        randint_mock.side_effect = [125, 625, 375]
-
-        status_codes = (
-            http.client.INTERNAL_SERVER_ERROR,
-            http.client.BAD_GATEWAY,
-            http.client.SERVICE_UNAVAILABLE,
-            http.client.NOT_FOUND,
-        )
-        responses = [_make_response(status_code) for status_code in 
status_codes]
-
-        def raise_response():
-            raise common.InvalidResponse(responses.pop(0))
-
-        func = mock.Mock(side_effect=raise_response)
-
-        retry_strategy = common.RetryStrategy(initial_delay=3.0, multiplier=4)
-        try:
-            _helpers.wait_and_retry(func, _get_status_code, retry_strategy)
-        except common.InvalidResponse as e:
-            ret_val = e.response
-
-        assert ret_val.status_code == status_codes[-1]
-        assert status_codes[-1] not in common.RETRYABLE
-
-        assert func.call_count == 4
-        assert func.mock_calls == [mock.call()] * 4
-
-        assert randint_mock.call_count == 3
-        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 3
-
-        assert sleep_mock.call_count == 3
-        sleep_mock.assert_any_call(3.125)  # initial delay 3 + jitter 0.125
-        sleep_mock.assert_any_call(
-            12.625
-        )  # previous delay 3 * multiplier 4 + jitter 0.625
-        sleep_mock.assert_any_call(
-            48.375
-        )  # previous delay 12 * multiplier 4 + jitter 0.375
-
-    @mock.patch("time.sleep")
-    @mock.patch("random.randint")
-    def test_success_with_retry_connection_error(self, randint_mock, 
sleep_mock):
-        randint_mock.side_effect = [125, 625, 375]
-
-        response = _make_response(http.client.NOT_FOUND)
-        responses = [
-            requests.exceptions.ConnectionError,
-            requests.exceptions.ConnectionError,
-            requests.exceptions.ConnectionError,
-            response,
-        ]
-        func = mock.Mock(side_effect=responses, spec=[])
-
-        retry_strategy = common.RetryStrategy()
-        ret_val = _helpers.wait_and_retry(func, _get_status_code, 
retry_strategy)
-
-        assert ret_val == responses[-1]
-
-        assert func.call_count == 4
-        assert func.mock_calls == [mock.call()] * 4
-
-        assert randint_mock.call_count == 3
-        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 3
-
-        assert sleep_mock.call_count == 3
-        sleep_mock.assert_any_call(1.125)
-        sleep_mock.assert_any_call(2.625)
-        sleep_mock.assert_any_call(4.375)
-
-    @mock.patch(u"time.sleep")
-    @mock.patch(u"random.randint")
-    def test_success_with_retry_chunked_encoding_error(self, randint_mock, 
sleep_mock):
-        randint_mock.side_effect = [125, 625, 375]
-
-        response = _make_response(http.client.NOT_FOUND)
-        responses = [
-            requests.exceptions.ChunkedEncodingError,
-            requests.exceptions.ChunkedEncodingError,
-            response,
-        ]
-        func = mock.Mock(side_effect=responses, spec=[])
-
-        retry_strategy = common.RetryStrategy()
-        ret_val = _helpers.wait_and_retry(func, _get_status_code, 
retry_strategy)
-
-        assert ret_val == responses[-1]
-
-        assert func.call_count == 3
-        assert func.mock_calls == [mock.call()] * 3
-
-        assert randint_mock.call_count == 2
-        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 2
-
-        assert sleep_mock.call_count == 2
-        sleep_mock.assert_any_call(1.125)
-        sleep_mock.assert_any_call(2.625)
-
-    @mock.patch(u"time.sleep")
-    @mock.patch(u"random.randint")
-    def test_connection_import_error_failure(self, randint_mock, sleep_mock):
-        randint_mock.side_effect = [125, 625, 375]
-
-        response = _make_response(http.client.NOT_FOUND)
-        responses = [
-            requests.exceptions.ConnectionError,
-            requests.exceptions.ConnectionError,
-            requests.exceptions.ConnectionError,
-            response,
-        ]
-
-        with mock.patch(
-            "google.resumable_media._helpers._get_connection_error_classes",
-            side_effect=ImportError,
-        ):
-            with pytest.raises(requests.exceptions.ConnectionError):
-                func = mock.Mock(side_effect=responses, spec=[])
-
-                retry_strategy = common.RetryStrategy()
-                _helpers.wait_and_retry(func, _get_status_code, retry_strategy)
-
-    @mock.patch("time.sleep")
-    @mock.patch("random.randint")
-    def test_retry_exceeds_max_cumulative(self, randint_mock, sleep_mock):
-        randint_mock.side_effect = [875, 0, 375, 500, 500, 250, 125, 0]
-
-        status_codes = (
-            http.client.SERVICE_UNAVAILABLE,
-            http.client.GATEWAY_TIMEOUT,
-            common.TOO_MANY_REQUESTS,
-            http.client.INTERNAL_SERVER_ERROR,
-            http.client.SERVICE_UNAVAILABLE,
-            http.client.BAD_GATEWAY,
-            http.client.GATEWAY_TIMEOUT,
-            common.TOO_MANY_REQUESTS,
-        )
-        responses = [_make_response(status_code) for status_code in 
status_codes]
-
-        def raise_response():
-            raise common.InvalidResponse(responses.pop(0))
-
-        func = mock.Mock(side_effect=raise_response)
-
-        retry_strategy = common.RetryStrategy(max_cumulative_retry=100.0)
-        try:
-            _helpers.wait_and_retry(func, _get_status_code, retry_strategy)
-        except common.InvalidResponse as e:
-            ret_val = e.response
-
-        assert ret_val.status_code == status_codes[-1]
-        assert status_codes[-1] in common.RETRYABLE
-
-        assert func.call_count == 8
-        assert func.mock_calls == [mock.call()] * 8
-
-        assert randint_mock.call_count == 7
-        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 7
-
-        assert sleep_mock.call_count == 7
-        sleep_mock.assert_any_call(1.875)
-        sleep_mock.assert_any_call(2.0)
-        sleep_mock.assert_any_call(4.375)
-        sleep_mock.assert_any_call(8.5)
-        sleep_mock.assert_any_call(16.5)
-        sleep_mock.assert_any_call(32.25)
-        sleep_mock.assert_any_call(64.125)
-
-    @mock.patch("time.sleep")
-    @mock.patch("random.randint")
-    def test_retry_exceeded_reraises_connection_error(self, randint_mock, 
sleep_mock):
-        randint_mock.side_effect = [875, 0, 375, 500, 500, 250, 125]
-
-        responses = [requests.exceptions.ConnectionError] * 8
-        func = mock.Mock(side_effect=responses, spec=[])
-
-        retry_strategy = common.RetryStrategy(max_cumulative_retry=100.0)
-        with pytest.raises(requests.exceptions.ConnectionError):
-            _helpers.wait_and_retry(func, _get_status_code, retry_strategy)
-
-        assert func.call_count == 8
-        assert func.mock_calls == [mock.call()] * 8
-
-        assert randint_mock.call_count == 7
-        assert randint_mock.mock_calls == [mock.call(0, 1000)] * 7
-
-        assert sleep_mock.call_count == 7
-        sleep_mock.assert_any_call(1.875)
-        sleep_mock.assert_any_call(2.0)
-        sleep_mock.assert_any_call(4.375)
-        sleep_mock.assert_any_call(8.5)
-        sleep_mock.assert_any_call(16.5)
-        sleep_mock.assert_any_call(32.25)
-        sleep_mock.assert_any_call(64.125)
-
-
 def _make_response(status_code):
     return mock.Mock(status_code=status_code, spec=["status_code"])
 
 
-def _get_status_code(response):
-    return response.status_code
-
-
 def _get_headers(response):
     return response.headers
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-resumable-media-2.0.0/tests/unit/test__upload.py 
new/google-resumable-media-2.1.0/tests/unit/test__upload.py
--- old/google-resumable-media-2.0.0/tests/unit/test__upload.py 2021-08-19 
22:11:18.000000000 +0200
+++ new/google-resumable-media-2.1.0/tests/unit/test__upload.py 2021-10-25 
19:33:28.000000000 +0200
@@ -19,7 +19,6 @@
 import mock
 import pytest
 
-from google import resumable_media
 from google.resumable_media import _helpers
 from google.resumable_media import _upload
 from google.resumable_media import common
@@ -721,7 +720,7 @@
         assert len(error.args) == 5
         assert error.args[1] == response.status_code
         assert error.args[3] == http.client.OK
-        assert error.args[4] == resumable_media.PERMANENT_REDIRECT
+        assert error.args[4] == http.client.PERMANENT_REDIRECT
         # Make sure the upload is invalid after the failure.
         assert upload.invalid
 
@@ -754,7 +753,7 @@
         upload = _upload.ResumableUpload(RESUMABLE_URL, ONE_MB)
         _fix_up_virtual(upload)
 
-        response = 
_make_response(status_code=resumable_media.PERMANENT_REDIRECT)
+        response = _make_response(status_code=http.client.PERMANENT_REDIRECT)
         # Make sure the upload is valid before the failure.
         assert not upload.invalid
         with pytest.raises(common.InvalidResponse) as exc_info:
@@ -776,7 +775,7 @@
         assert not upload.invalid
         headers = {"range": "nights 1-81"}
         response = _make_response(
-            status_code=resumable_media.PERMANENT_REDIRECT, headers=headers
+            status_code=http.client.PERMANENT_REDIRECT, headers=headers
         )
         with pytest.raises(common.InvalidResponse) as exc_info:
             upload._process_response(response, 81)
@@ -797,7 +796,7 @@
         assert upload._bytes_uploaded == 0
         headers = {"range": "bytes=0-171"}
         response = _make_response(
-            status_code=resumable_media.PERMANENT_REDIRECT, headers=headers
+            status_code=http.client.PERMANENT_REDIRECT, headers=headers
         )
         ret_val = upload._process_response(response, 172)
         assert ret_val is None
@@ -975,7 +974,7 @@
         assert error.response is response
         assert len(error.args) == 4
         assert error.args[1] == response.status_code
-        assert error.args[3] == resumable_media.PERMANENT_REDIRECT
+        assert error.args[3] == http.client.PERMANENT_REDIRECT
         # Make sure still invalid.
         assert upload.invalid
 
@@ -988,7 +987,7 @@
         upload._bytes_uploaded = mock.sentinel.not_zero
         assert upload.bytes_uploaded != 0
 
-        response = 
_make_response(status_code=resumable_media.PERMANENT_REDIRECT)
+        response = _make_response(status_code=http.client.PERMANENT_REDIRECT)
         ret_val = upload._process_recover_response(response)
         assert ret_val is None
         # Check the state of ``upload`` after.
@@ -1006,7 +1005,7 @@
 
         headers = {"range": "bites=9-11"}
         response = _make_response(
-            status_code=resumable_media.PERMANENT_REDIRECT, headers=headers
+            status_code=http.client.PERMANENT_REDIRECT, headers=headers
         )
         with pytest.raises(common.InvalidResponse) as exc_info:
             upload._process_recover_response(response)
@@ -1032,7 +1031,7 @@
         end = 11
         headers = {"range": "bytes=0-{:d}".format(end)}
         response = _make_response(
-            status_code=resumable_media.PERMANENT_REDIRECT, headers=headers
+            status_code=http.client.PERMANENT_REDIRECT, headers=headers
         )
         ret_val = upload._process_recover_response(response)
         assert ret_val is None

Reply via email to