diff --git a/CHANGES b/CHANGES
index 2675334..662cfc3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,14 +1,19 @@
 0.22.0
 ------
 
+* Update `requests` dependency to the version of 2.22.0 or higher. See #584.
 * [BETA] Added possibility to record responses to TOML files via `@_recorder.record(file_path="out.toml")` decorator.
+* [BETA] Added possibility to replay responses (populate registry) from TOML files
+  via `responses._add_from_file(file_path="out.toml")` method.
 * Fix type for the `mock`'s patcher object. See #556
+* Fix type annotation for `CallList`
 * Add `passthrough` argument to `BaseResponse` object. See #557
 * Fix `registries` leak. See #563
 * Add support for the `loose` version of `json_params_matcher` via named argument `strict_match`. See #551
 * Add lists support as JSON objects in `json_params_matcher`. See #559
 * Added project links to pypi listing.
 * Fix `MaxRetryError` exception. Replace exception by `RetryError` according to `requests` implementation. See #572.
+* Adjust error message when `Retry` is exhausted. See #580.
 
 0.21.0
 ------
diff --git a/README.rst b/README.rst
index 357bd76..d03dad4 100644
--- a/README.rst
+++ b/README.rst
@@ -17,7 +17,7 @@ A utility library for mocking out the ``requests`` Python library.
 
 ..  note::
 
-    Responses requires Python 3.7 or newer, and requests >= 2.0
+    Responses requires Python 3.7 or newer, and requests >= 2.22.0
 
 
 Table of Contents
diff --git a/responses/__init__.py b/responses/__init__.py
index 3cfafb8..24d664b 100644
--- a/responses/__init__.py
+++ b/responses/__init__.py
@@ -2,8 +2,6 @@ import inspect
 import json as json_module
 import logging
 from collections import namedtuple
-from collections.abc import Sequence
-from collections.abc import Sized
 from functools import wraps
 from http import client
 from itertools import groupby
@@ -18,12 +16,15 @@ from typing import Iterator
 from typing import List
 from typing import Mapping
 from typing import Optional
+from typing import Sequence
+from typing import Sized
 from typing import Tuple
 from typing import Type
 from typing import Union
 from typing import overload
 from warnings import warn
 
+import toml as _toml
 from requests.adapters import HTTPAdapter
 from requests.adapters import MaxRetryError
 from requests.exceptions import ConnectionError
@@ -64,6 +65,7 @@ from urllib.parse import urlunsplit
 
 if TYPE_CHECKING:  # pragma: no cover
     # import only for linter run
+    import os
     from unittest.mock import _patch as _mock_patcher
 
     from requests import PreparedRequest
@@ -217,7 +219,7 @@ def get_wrapped(
     return wrapper
 
 
-class CallList(Sequence, Sized):  # type: ignore[type-arg]
+class CallList(Sequence[Any], Sized):
     def __init__(self) -> None:
         self._calls: List[Call] = []
 
@@ -227,7 +229,7 @@ class CallList(Sequence, Sized):  # type: ignore[type-arg]
     def __len__(self) -> int:
         return len(self._calls)
 
-    def __getitem__(self, idx: int) -> Call:  # type: ignore[override]
+    def __getitem__(self, idx: Union[int, slice]) -> Union[Call, List[Call]]:
         return self._calls[idx]
 
     def add(self, request: "PreparedRequest", response: _Body) -> None:
@@ -415,6 +417,25 @@ class BaseResponse(object):
         return bool(urlsplit(self.url).query)
 
     def _url_matches(self, url: _URLPatternType, other: str) -> bool:
+        """Compares two URLs.
+
+        Compares only scheme, netloc and path. If 'url' is a re.Pattern, then checks that
+        'other' matches the pattern.
+
+        Parameters
+        ----------
+        url : Union["Pattern[str]", str]
+            Reference URL or Pattern to compare.
+
+        other : str
+            URl that should be compared.
+
+        Returns
+        -------
+        bool
+            True, if URLs are identical or 'other' matches the pattern.
+
+        """
         if isinstance(url, str):
             if _has_unicode(url):
                 url = _clean_unicode(url)
@@ -661,9 +682,25 @@ class RequestsMock(object):
         self._thread_lock = _ThreadingLock()
 
     def get_registry(self) -> FirstMatchRegistry:
+        """Returns current registry instance with responses.
+
+        Returns
+        -------
+        FirstMatchRegistry
+            Current registry instance with responses.
+
+        """
         return self._registry
 
     def _set_registry(self, new_registry: Type[FirstMatchRegistry]) -> None:
+        """Replaces current registry with `new_registry`.
+
+        Parameters
+        ----------
+        new_registry : Type[FirstMatchRegistry]
+            Class reference of the registry that should be set, eg OrderedRegistry
+
+        """
         if self.registered():
             err_msg = (
                 "Cannot replace Registry, current registry has responses.\n"
@@ -674,6 +711,7 @@ class RequestsMock(object):
         self._registry = new_registry()
 
     def reset(self) -> None:
+        """Resets registry (including type), calls, passthru_prefixes to default values."""
         self._registry = FirstMatchRegistry()
         self._calls.reset()
         self.passthru_prefixes = ()
@@ -733,6 +771,21 @@ class RequestsMock(object):
         response = Response(method=method, url=url, body=body, **kwargs)
         return self._registry.add(response)
 
+    def _add_from_file(self, file_path: "Union[str, bytes, os.PathLike[Any]]") -> None:
+        with open(file_path) as file:
+            data = _toml.load(file)
+
+        for rsp in data["responses"]:
+            rsp = rsp["response"]
+            self.add(
+                method=rsp["method"],
+                url=rsp["url"],
+                body=rsp["body"],
+                status=rsp["status"],
+                content_type=rsp["content_type"],
+                auto_calculate_content_length=rsp["auto_calculate_content_length"],
+            )
+
     def delete(self, *args: Any, **kwargs: Any) -> BaseResponse:
         return self.add(DELETE, *args, **kwargs)
 
@@ -1029,7 +1082,7 @@ class RequestsMock(object):
                 retries = retries.increment(
                     method=response.request.method,  # type: ignore[misc]
                     url=response.url,  # type: ignore[misc]
-                    response=response,  # type: ignore[misc]
+                    response=response.raw,  # type: ignore[misc]
                 )
                 return self._on_request(adapter, request, retries=retries, **kwargs)
             except MaxRetryError as e:
@@ -1110,6 +1163,7 @@ __all__ = [
     # Exposed by the RequestsMock class:
     "activate",
     "add",
+    "_add_from_file",
     "add_callback",
     "add_passthru",
     "_deprecated_assert_all_requests_are_fired",
@@ -1144,6 +1198,7 @@ __all__ = [
 # expose only methods and/or read-only methods
 activate = _default_mock.activate
 add = _default_mock.add
+_add_from_file = _default_mock._add_from_file
 add_callback = _default_mock.add_callback
 add_passthru = _default_mock.add_passthru
 _deprecated_assert_all_requests_are_fired = _default_mock.assert_all_requests_are_fired
diff --git a/responses/registries.py b/responses/registries.py
index 049df23..4b7e233 100644
--- a/responses/registries.py
+++ b/responses/registries.py
@@ -75,9 +75,32 @@ class FirstMatchRegistry(object):
 
 
 class OrderedRegistry(FirstMatchRegistry):
+    """Registry where `Response` objects are dependent on the insertion order and invocation index.
+
+    OrderedRegistry applies the rule of first in - first out. Responses should be invoked in
+    the same order in which they were added to the registry. Otherwise, an error is returned.
+    """
+
     def find(
         self, request: "PreparedRequest"
     ) -> Tuple[Optional["BaseResponse"], List[str]]:
+        """Find the next registered `Response` and check if it matches the request.
+
+        Search is performed by taking the first element of the registered responses list
+        and removing this object (popping from the list).
+
+        Parameters
+        ----------
+        request : PreparedRequest
+            Request that was caught by the custom adapter.
+
+        Returns
+        -------
+        Tuple[Optional["BaseResponse"], List[str]]
+            Matched `Response` object and empty list in case of match.
+            Otherwise, None and a list with reasons for not finding a match.
+
+        """
 
         if not self.registered:
             return None, ["No more registered responses"]
diff --git a/setup.py b/setup.py
index 115d183..03e980c 100644
--- a/setup.py
+++ b/setup.py
@@ -17,7 +17,7 @@ from setuptools.command.test import test as TestCommand
 setup_requires = []
 
 install_requires = [
-    "requests>=2.0,<3.0",
+    "requests>=2.22.0,<3.0",
     "urllib3>=1.25.10",
     "toml",
     "types-toml",

diff --git a/responses/tests/test_recorder.py b/responses/tests/test_recorder.py
index 0d73379..d70d60f 100644
--- a/responses/tests/test_recorder.py
+++ b/responses/tests/test_recorder.py
@@ -3,9 +3,58 @@ from pathlib import Path
 import requests
 import toml
 
+import responses
 from responses import _recorder
 
 
+def get_data(host, port):
+    data = {
+        "responses": [
+            {
+                "response": {
+                    "method": "GET",
+                    "url": f"http://{host}:{port}/404",
+                    "body": "404 Not Found",
+                    "status": 404,
+                    "content_type": "text/plain",
+                    "auto_calculate_content_length": False,
+                }
+            },
+            {
+                "response": {
+                    "method": "GET",
+                    "url": f"http://{host}:{port}/status/wrong",
+                    "body": "Invalid status code",
+                    "status": 400,
+                    "content_type": "text/plain",
+                    "auto_calculate_content_length": False,
+                }
+            },
+            {
+                "response": {
+                    "method": "GET",
+                    "url": f"http://{host}:{port}/500",
+                    "body": "500 Internal Server Error",
+                    "status": 500,
+                    "content_type": "text/plain",
+                    "auto_calculate_content_length": False,
+                }
+            },
+            {
+                "response": {
+                    "method": "PUT",
+                    "url": f"http://{host}:{port}/202",
+                    "body": "OK",
+                    "status": 202,
+                    "content_type": "text/plain",
+                    "auto_calculate_content_length": False,
+                }
+            },
+        ]
+    }
+    return data
+
+
 class TestRecord:
     def setup(self):
         self.out_file = Path("out.toml")
@@ -35,7 +84,7 @@ class TestRecord:
 
         def another():
             requests.get(url500)
-            requests.get(url202)
+            requests.put(url202)
 
         @_recorder.record(file_path=self.out_file)
         def run():
@@ -48,47 +97,46 @@ class TestRecord:
         with open(self.out_file) as file:
             data = toml.load(file)
 
-        assert data == {
-            "responses": [
-                {
-                    "response": {
-                        "method": "GET",
-                        "url": f"http://{httpserver.host}:{httpserver.port}/404",
-                        "body": "404 Not Found",
-                        "status": 404,
-                        "content_type": "text/plain",
-                        "auto_calculate_content_length": False,
-                    }
-                },
-                {
-                    "response": {
-                        "method": "GET",
-                        "url": f"http://{httpserver.host}:{httpserver.port}/status/wrong",
-                        "body": "Invalid status code",
-                        "status": 400,
-                        "content_type": "text/plain",
-                        "auto_calculate_content_length": False,
-                    }
-                },
-                {
-                    "response": {
-                        "method": "GET",
-                        "url": f"http://{httpserver.host}:{httpserver.port}/500",
-                        "body": "500 Internal Server Error",
-                        "status": 500,
-                        "content_type": "text/plain",
-                        "auto_calculate_content_length": False,
-                    }
-                },
-                {
-                    "response": {
-                        "method": "GET",
-                        "url": f"http://{httpserver.host}:{httpserver.port}/202",
-                        "body": "OK",
-                        "status": 202,
-                        "content_type": "text/plain",
-                        "auto_calculate_content_length": False,
-                    }
-                },
-            ]
-        }
+        assert data == get_data(httpserver.host, httpserver.port)
+
+
+class TestReplay:
+    def teardown(self):
+        out_file = Path("out.toml")
+        if out_file.exists():
+            out_file.unlink()
+
+        assert not out_file.exists()
+
+    def test_add_from_file(self):
+        with open("out.toml", "w") as file:
+            toml.dump(get_data("example.com", "8080"), file)
+
+        @responses.activate
+        def run():
+            responses.patch("http://httpbin.org")
+            responses._add_from_file(file_path="out.toml")
+            responses.post("http://httpbin.org/form")
+
+            assert responses.registered()[0].url == "http://httpbin.org/"
+            assert responses.registered()[1].url == "http://example.com:8080/404"
+            assert (
+                responses.registered()[2].url == "http://example.com:8080/status/wrong"
+            )
+            assert responses.registered()[3].url == "http://example.com:8080/500"
+            assert responses.registered()[4].url == "http://example.com:8080/202"
+            assert responses.registered()[5].url == "http://httpbin.org/form"
+
+            assert responses.registered()[0].method == "PATCH"
+            assert responses.registered()[2].method == "GET"
+            assert responses.registered()[4].method == "PUT"
+            assert responses.registered()[5].method == "POST"
+
+            assert responses.registered()[2].status == 400
+            assert responses.registered()[3].status == 500
+
+            assert responses.registered()[3].body == "500 Internal Server Error"
+
+            assert responses.registered()[3].content_type == "text/plain"
+
+        run()
diff --git a/responses/tests/test_responses.py b/responses/tests/test_responses.py
index be87497..53924df 100644
--- a/responses/tests/test_responses.py
+++ b/responses/tests/test_responses.py
@@ -2450,6 +2450,23 @@ class TestMaxRetry:
         run()
         assert_reset()
 
+    def test_max_retries_exceed_msg(self):
+        @responses.activate(registry=registries.OrderedRegistry)
+        def run():
+            url = "https://example.com"
+            responses.get(url, body="Error", status=500)
+            responses.get(url, body="Error", status=500)
+
+            session = self.set_session(total=1)
+
+            with pytest.raises(RetryError) as err:
+                session.get(url)
+
+            assert "too many 500 error responses" in str(err.value)
+
+        run()
+        assert_reset()
+
     def test_adapter_retry_untouched(self):
         """Validate that every new request uses brand-new Retry object"""
 

Add expected response from a file
In your [introductory blog post](http://cramer.io/2014/05/20/mocking-requests-with-responses/) you have the last example with a lot of such calls:

```
responses.add(
            responses.GET, 'http://jenkins.example.com/job/server/2/logText/progressiveHtml/?start=0',
            match_querystring=True,
            adding_headers={'X-Text-Size': '7'},
            body='Foo bar')
```

This is clearly a lack of the feature and the workaround because it is barely practical to stuff one's test suite with big response strings. And a full response file can contain all of status, headers and response body. It can look like this (py3):

```
from io import BytesIO
from http.client import HTTPResponse

import responses


class FakeSocket():

  _stream = None


  def __init__(self, s):
    self._stream = BytesIO(s)

  def makefile(self, *args, **kwargs):
    return self._stream


def parse_response(request_string):
  response = HTTPResponse(FakeSocket(request_string))
  response.begin()
  return response

class ResponseMock(responses.RequestsMock):

  def add_from_file(self, method, url, filename, match_querystring = False, stream = False):  
    with open(filename, 'rb') as f:
      r = parse_response(f.read())

    content_type = r.getheader('content-type', 'text/plain')

    self.add(method, url, r.read(), match_querystring, r.status, r.getheaders(), stream, content_type)
```

Response file can look like this:

```
HTTP/1.1 200 OK
Date: Sat, 22 Nov 2014 12:00:40 GMT
Content-Type: text/xml; charset="utf-8"
Connection: close

Some <em>HTML</em> goes here.
```

responses/tests/test_recorder.py::TestReplay::test_add_from_file
responses/tests/test_responses.py::test_response responses/tests/test_responses.py::test_response_encoded responses/tests/test_responses.py::test_response_with_instance responses/tests/test_responses.py::test_replace[http://example.com/two-http://example.com/two] responses/tests/test_responses.py::test_replace[original1-replacement1] responses/tests/test_responses.py::test_replace[http://example\\.com/two-http://example\\.com/two] responses/tests/test_responses.py::test_replace_error[http://example.com/one-http://example\\.com/one] responses/tests/test_responses.py::test_replace_error[http://example\\.com/one-http://example.com/one] responses/tests/test_responses.py::test_replace_response_object_error responses/tests/test_responses.py::test_upsert_replace[http://example.com/two-http://example.com/two] responses/tests/test_responses.py::test_upsert_replace[original1-replacement1] responses/tests/test_responses.py::test_upsert_replace[http://example\\.com/two-http://example\\.com/two] responses/tests/test_responses.py::test_upsert_add[http://example.com/two-http://example.com/two] responses/tests/test_responses.py::test_upsert_add[original1-replacement1] responses/tests/test_responses.py::test_upsert_add[http://example\\.com/two-http://example\\.com/two] responses/tests/test_responses.py::test_remove responses/tests/test_responses.py::test_response_equality[args10-kwargs10-args20-kwargs20-True] responses/tests/test_responses.py::test_response_equality[args11-kwargs11-args21-kwargs21-False] responses/tests/test_responses.py::test_response_equality[args12-kwargs12-args22-kwargs22-False] responses/tests/test_responses.py::test_response_equality[args13-kwargs13-args23-kwargs23-True] responses/tests/test_responses.py::test_response_equality_different_objects responses/tests/test_responses.py::test_connection_error responses/tests/test_responses.py::test_match_querystring responses/tests/test_responses.py::test_match_querystring_empty responses/tests/test_responses.py::test_match_querystring_error responses/tests/test_responses.py::test_match_querystring_regex responses/tests/test_responses.py::test_match_querystring_error_regex responses/tests/test_responses.py::test_match_querystring_auto_activates responses/tests/test_responses.py::test_match_querystring_missing_key responses/tests/test_responses.py::test_accept_string_body responses/tests/test_responses.py::test_accept_json_body responses/tests/test_responses.py::test_no_content_type responses/tests/test_responses.py::test_arbitrary_status_code responses/tests/test_responses.py::test_throw_connection_error_explicit responses/tests/test_responses.py::test_callback responses/tests/test_responses.py::test_deprecated_package_attributes responses/tests/test_responses.py::test_callback_deprecated_stream_argument responses/tests/test_responses.py::test_callback_deprecated_match_querystring_argument responses/tests/test_responses.py::test_callback_match_querystring_default_false responses/tests/test_responses.py::test_callback_exception_result responses/tests/test_responses.py::test_callback_exception_body responses/tests/test_responses.py::test_callback_no_content_type responses/tests/test_responses.py::test_callback_content_type_dict responses/tests/test_responses.py::test_callback_matchers responses/tests/test_responses.py::test_callback_matchers_fail responses/tests/test_responses.py::test_callback_content_type_tuple responses/tests/test_responses.py::test_regular_expression_url responses/tests/test_responses.py::test_base_response_get_response responses/tests/test_responses.py::test_custom_adapter responses/tests/test_responses.py::test_responses_as_context_manager responses/tests/test_responses.py::test_activate_doesnt_change_signature responses/tests/test_responses.py::TestFixtures::test_function responses/tests/test_responses.py::TestFixtures::test_function_decorated responses/tests/test_responses.py::test_activate_mock_interaction responses/tests/test_responses.py::test_activate_doesnt_change_signature_with_return_type responses/tests/test_responses.py::test_activate_doesnt_change_signature_for_method responses/tests/test_responses.py::test_response_cookies responses/tests/test_responses.py::test_response_cookies_secure responses/tests/test_responses.py::test_response_cookies_multiple responses/tests/test_responses.py::test_response_cookies_session[True-True] responses/tests/test_responses.py::test_response_cookies_session[True-False] responses/tests/test_responses.py::test_response_cookies_session[True-None] responses/tests/test_responses.py::test_response_cookies_session[False-True] responses/tests/test_responses.py::test_response_cookies_session[False-False] responses/tests/test_responses.py::test_response_cookies_session[False-None] responses/tests/test_responses.py::test_response_cookies_session[None-True] responses/tests/test_responses.py::test_response_cookies_session[None-False] responses/tests/test_responses.py::test_response_cookies_session[None-None] responses/tests/test_responses.py::test_response_callback responses/tests/test_responses.py::test_response_filebody responses/tests/test_responses.py::test_use_stream_twice_to_double_raw_io responses/tests/test_responses.py::test_assert_all_requests_are_fired responses/tests/test_responses.py::test_allow_redirects_samehost responses/tests/test_responses.py::test_path_segments responses/tests/test_responses.py::test_handles_unicode_querystring responses/tests/test_responses.py::test_handles_unicode_url responses/tests/test_responses.py::test_handles_unicode_body responses/tests/test_responses.py::test_handles_buffered_reader_body responses/tests/test_responses.py::test_headers responses/tests/test_responses.py::test_content_length_error responses/tests/test_responses.py::test_stream_with_none_chunk_size responses/tests/test_responses.py::test_legacy_adding_headers responses/tests/test_responses.py::test_legacy_adding_headers_with_content_type responses/tests/test_responses.py::test_auto_calculate_content_length_string_body responses/tests/test_responses.py::test_auto_calculate_content_length_bytes_body responses/tests/test_responses.py::test_auto_calculate_content_length_json_body responses/tests/test_responses.py::test_auto_calculate_content_length_unicode_body responses/tests/test_responses.py::test_auto_calculate_content_length_doesnt_work_for_buffered_reader_body responses/tests/test_responses.py::test_multiple_responses responses/tests/test_responses.py::test_multiple_responses_intermixed responses/tests/test_responses.py::test_multiple_urls responses/tests/test_responses.py::test_multiple_methods responses/tests/test_responses.py::test_passthrough_flag responses/tests/test_responses.py::test_passthrough_kwarg responses/tests/test_responses.py::test_passthrough_response responses/tests/test_responses.py::test_passthrough_response_stream responses/tests/test_responses.py::test_passthru_prefixes responses/tests/test_responses.py::test_passthru responses/tests/test_responses.py::test_passthru_regex responses/tests/test_responses.py::test_passthru_does_not_persist_across_tests responses/tests/test_responses.py::test_method_named_param responses/tests/test_responses.py::test_passthru_unicode responses/tests/test_responses.py::test_custom_target responses/tests/test_responses.py::test_request_param[http://example.com] responses/tests/test_responses.py::test_request_param[http://example.com/some/path] responses/tests/test_responses.py::test_request_param[http://example.com/other/path/] responses/tests/test_responses.py::test_request_param_with_multiple_values_for_the_same_key responses/tests/test_responses.py::test_assert_call_count[http://example.com] responses/tests/test_responses.py::test_assert_call_count[http://example.com?hello=world] responses/tests/test_responses.py::test_call_count_with_matcher responses/tests/test_responses.py::test_call_count_without_matcher responses/tests/test_responses.py::test_fail_request_error responses/tests/test_responses.py::test_response_representations[response_params0-<Response(url='http://example.com/' responses/tests/test_responses.py::test_response_representations[response_params1-<Response(url='http://another-domain.com/' responses/tests/test_responses.py::test_response_representations[response_params2-<Response(url='http://abcd.com/' responses/tests/test_responses.py::test_mocked_responses_list_registered responses/tests/test_responses.py::test_rfc_compliance[http://service-A/foo?q=fizz-http://service-a/foo?q=fizz] responses/tests/test_responses.py::test_rfc_compliance[http://service-a/foo-http://service-A/foo] responses/tests/test_responses.py::test_rfc_compliance[http://someHost-AwAy/-http://somehost-away/] responses/tests/test_responses.py::test_rfc_compliance[http://fizzbuzz/foo-http://fizzbuzz/foo] responses/tests/test_responses.py::test_requests_between_add responses/tests/test_responses.py::test_responses_reuse responses/tests/test_responses.py::TestStrictWrapper::test_strict_wrapper responses/tests/test_responses.py::TestStrictWrapper::test_nested_decorators[True] responses/tests/test_responses.py::TestStrictWrapper::test_nested_decorators[False] responses/tests/test_responses.py::TestStrictWrapper::test_nested_decorators[None] responses/tests/test_responses.py::TestMultipleWrappers::test_wrapped responses/tests/test_responses.py::TestMultipleWrappers::test_call_another_wrapped_function responses/tests/test_responses.py::TestMultipleWrappers::test_mock_not_leaked responses/tests/test_responses.py::TestShortcuts::test_delete responses/tests/test_responses.py::TestShortcuts::test_get responses/tests/test_responses.py::TestShortcuts::test_head responses/tests/test_responses.py::TestShortcuts::test_options responses/tests/test_responses.py::TestShortcuts::test_patch responses/tests/test_responses.py::TestShortcuts::test_post responses/tests/test_responses.py::TestShortcuts::test_put responses/tests/test_responses.py::test_reset_in_the_middle responses/tests/test_responses.py::test_redirect