Repository: boto/botocore
Pull request #2612 (2022-02-08 23:22:20)

Removing retries context constraint
Loosening constraints on populating retries context with retry header information.

codecov-commenter: # [Codecov](https://codecov.io/gh/boto/botocore/pull/2612?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto) Report
> Merging [#2612](https://codecov.io/gh/boto/botocore/pull/2612?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto) (9ec3d44) into [develop](https://codecov.io/gh/boto/botocore/commit/00b39e992ce1ff1abf86caed3a4f28603363e716?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto) (00b39e9) will **decrease** coverage by `0.01%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/boto/botocore/pull/2612/graphs/tree.svg?width=650&height=150&src=pr&token=QOLXw6XSza&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto)](https://codecov.io/gh/boto/botocore/pull/2612?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto)

```diff
@@             Coverage Diff             @@
##           develop    #2612      +/-   ##
===========================================
- Coverage    95.41%   95.40%   -0.02%     
===========================================
  Files           59       59              
  Lines        11916    11914       -2     
===========================================
- Hits         11370    11366       -4     
- Misses         546      548       +2     
```


| [Impacted Files](https://codecov.io/gh/boto/botocore/pull/2612?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto) | Coverage Δ | |
|---|---|---|
| [botocore/retries/standard.py](https://codecov.io/gh/boto/botocore/pull/2612/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto#diff-Ym90b2NvcmUvcmV0cmllcy9zdGFuZGFyZC5weQ==) | `99.50% <100.00%> (+0.48%)` | :arrow_up: |
| [botocore/retryhandler.py](https://codecov.io/gh/boto/botocore/pull/2612/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto#diff-Ym90b2NvcmUvcmV0cnloYW5kbGVyLnB5) | `99.39% <100.00%> (+0.60%)` | :arrow_up: |
| [botocore/httpsession.py](https://codecov.io/gh/boto/botocore/pull/2612/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto#diff-Ym90b2NvcmUvaHR0cHNlc3Npb24ucHk=) | `90.94% <0.00%> (-0.42%)` | :arrow_down: |
| [botocore/utils.py](https://codecov.io/gh/boto/botocore/pull/2612/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto#diff-Ym90b2NvcmUvdXRpbHMucHk=) | `95.42% <0.00%> (-0.24%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/boto/botocore/pull/2612?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/boto/botocore/pull/2612?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto). Last update [00b39e9...9ec3d44](https://codecov.io/gh/boto/botocore/pull/2612?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=boto).


Patch:
diff --git a/botocore/retries/standard.py b/botocore/retries/standard.py
index de4b73e44..96c70e7a9 100644
--- a/botocore/retries/standard.py
+++ b/botocore/retries/standard.py
@@ -266,11 +266,11 @@ class MaxAttemptsChecker(BaseRetryableChecker):
 
     def is_retryable(self, context):
         under_max_attempts = context.attempt_number < self._max_attempts
-        retries_context = context.request_context['retries']
-        retries_max_attempts = retries_context.setdefault(
-            'max', self._max_attempts)
-        if self._max_attempts > retries_max_attempts:
-            retries_context['max'] = self._max_attempts
+        retries_context = context.request_context.get('retries')
+        if retries_context:
+            retries_context['max'] = max(
+                retries_context.get('max', 0), self._max_attempts
+            )
         if not under_max_attempts:
             logger.debug("Max attempts of %s reached.", self._max_attempts)
             context.add_retry_metadata(MaxAttemptsReached=True)
diff --git a/botocore/retryhandler.py b/botocore/retryhandler.py
index 76a7027d0..1b1066297 100644
--- a/botocore/retryhandler.py
+++ b/botocore/retryhandler.py
@@ -186,7 +186,7 @@ class RetryHandler(object):
             'caught_exception': caught_exception
         }
         if isinstance(self._checker, MaxAttemptsDecorator):
-            retries_context = kwargs['request_dict']['context']['retries']
+            retries_context = kwargs['request_dict']['context'].get('retries')
             checker_kwargs.update({'retries_context': retries_context})
 
         if self._checker(**checker_kwargs):
@@ -257,10 +257,10 @@ class MaxAttemptsDecorator(BaseChecker):
 
     def __call__(self, attempt_number, response, caught_exception,
                  retries_context):
-        retries_max_attempts = retries_context.setdefault(
-            'max', self._max_attempts)
-        if self._max_attempts > retries_max_attempts:
-            retries_context['max'] = self._max_attempts
+        if retries_context:
+            retries_context['max'] = max(
+                retries_context.get('max', 0), self._max_attempts
+            )
 
         should_retry = self._should_retry(attempt_number, response,
                                           caught_exception)


Test patch:
diff --git a/tests/unit/retries/test_standard.py b/tests/unit/retries/test_standard.py
index 8999a580e..72eee89ac 100644
--- a/tests/unit/retries/test_standard.py
+++ b/tests/unit/retries/test_standard.py
@@ -217,7 +217,6 @@ def _verify_retryable(checker, operation_model,
         parsed_response=parsed_response,
         http_response=http_response,
         caught_exception=caught_exception,
-        request_context={'retries': {}}
     )
     assert checker.is_retryable(context) == is_retryable
 
@@ -232,7 +231,6 @@ def arbitrary_retry_context():
         http_response=AWSResponse(status_code=500,
                                   raw=None, headers={}, url='https://foo'),
         caught_exception=None,
-        request_context={'retries': {}}
     )
 
 
@@ -257,6 +255,14 @@ def test_max_attempts_adds_metadata_key_when_reached():
     assert context.get_retry_metadata() == {'MaxAttemptsReached': True}
 
 
+def test_retries_context_not_on_request_context():
+    checker = standard.MaxAttemptsChecker(max_attempts=3)
+    context = arbitrary_retry_context()
+    context.attempt_number = 3
+    assert checker.is_retryable(context) is False
+    assert context.request_context == {}
+
+
 def test_can_create_default_retry_handler():
     mock_client = mock.Mock()
     mock_client.meta.service_model.service_id = model.ServiceId('my-service')
diff --git a/tests/unit/test_handlers.py b/tests/unit/test_handlers.py
index 201796902..b3add25d4 100644
--- a/tests/unit/test_handlers.py
+++ b/tests/unit/test_handlers.py
@@ -1024,7 +1024,7 @@ class TestRetryHandlerOrder(BaseSessionTest):
         operation = service_model.operation_model('CopyObject')
         responses = client.meta.events.emit(
             'needs-retry.s3.CopyObject',
-            request_dict={'context': {'retries': {}}},
+            request_dict={'context': {}},
             response=(mock.Mock(), mock.Mock()), endpoint=mock.Mock(),
             operation=operation, attempts=1, caught_exception=None)
         # This is implementation specific, but we're trying to verify that
diff --git a/tests/unit/test_retryhandler.py b/tests/unit/test_retryhandler.py
index 76453d1bf..92085c89e 100644
--- a/tests/unit/test_retryhandler.py
+++ b/tests/unit/test_retryhandler.py
@@ -32,7 +32,6 @@ HTTP_200_RESPONSE.status_code = 200
 
 REQUEST_DICT = {
     'context': {
-        'retries': {}
     }
 }