--- requests_cache/serializers/cattrs.py.orig	2022-02-23 03:10:56 UTC
+++ requests_cache/serializers/cattrs.py
@@ -14,7 +14,7 @@ serialization format.
 from datetime import datetime, timedelta
 from typing import Callable, Dict, ForwardRef, MutableMapping
 
-from cattr import GenConverter
+from cattr import Converter
 from requests.cookies import RequestsCookieJar, cookiejar_from_dict
 from requests.structures import CaseInsensitiveDict
 from urllib3._collections import HTTPHeaderDict
@@ -28,7 +28,7 @@ class CattrStage(Stage):
     on its own, or as a stage within a :py:class:`.SerializerPipeline`.
     """
 
-    def __init__(self, factory: Callable[..., GenConverter] = None):
+    def __init__(self, factory: Callable[..., Converter] = None):
         self.converter = init_converter(factory)
 
     def dumps(self, value: CachedResponse) -> Dict:
@@ -42,9 +42,9 @@ class CattrStage(Stage):
         return self.converter.structure(value, cl=CachedResponse)
 
 
-def init_converter(factory: Callable[..., GenConverter] = None):
+def init_converter(factory: Callable[..., Converter] = None):
     """Make a converter to structure and unstructure nested objects within a :py:class:`.CachedResponse`"""
-    factory = factory or GenConverter
+    factory = factory or Converter
     converter = factory(omit_if_default=True)
 
     # Convert datetimes to and from iso-formatted strings
Obtained from:	https://github.com/requests-cache/requests-cache/commit/66550b5355f4a4f063b4b22c3139a2f941c91eb4

--- requests_cache/serializers/preconf.py.orig	2022-02-23 03:10:56 UTC
+++ requests_cache/serializers/preconf.py
@@ -1,9 +1,10 @@
+# flake8: noqa: F841
 """The ``cattrs`` library includes a number of `pre-configured converters
 <https://cattrs.readthedocs.io/en/latest/preconf.html>`_ that perform some pre-serialization steps
 required for specific serialization formats.
 
 This module wraps those converters as serializer :py:class:`.Stage` objects. These are then used as
-a stage in a :py:class:`.SerializerPipeline`, which runs after the base converter and before the
+stages in a :py:class:`.SerializerPipeline`, which runs after the base converter and before the
 format's ``dumps()`` (or equivalent) method.
 
 For any optional libraries that aren't installed, the corresponding serializer will be a placeholder
@@ -13,70 +14,95 @@ class that raises an ``ImportError`` at initialization
    :nosignatures:
 """
 import pickle
+from datetime import timedelta
+from decimal import Decimal
 from functools import partial
+from importlib import import_module
 
-from cattr.preconf import bson as bson_preconf
-from cattr.preconf import json as json_preconf
-from cattr.preconf import msgpack, orjson, pyyaml, tomlkit, ujson
+from cattr import Converter
 
 from .._utils import get_placeholder_class
 from .cattrs import CattrStage
 from .pipeline import SerializerPipeline, Stage
 
-base_stage = (
-    CattrStage()
-)  #: Base stage for all serializer pipelines (or standalone dict serializer)
-dict_serializer = base_stage  #: Partial serializer that unstructures responses into dicts
-bson_preconf_stage = CattrStage(bson_preconf.make_converter)  #: Pre-serialization steps for BSON
-json_preconf_stage = CattrStage(json_preconf.make_converter)  #: Pre-serialization steps for JSON
-msgpack_preconf_stage = CattrStage(msgpack.make_converter)  #: Pre-serialization steps for msgpack
-orjson_preconf_stage = CattrStage(orjson.make_converter)  #: Pre-serialization steps for orjson
-yaml_preconf_stage = CattrStage(pyyaml.make_converter)  #: Pre-serialization steps for YAML
-toml_preconf_stage = CattrStage(tomlkit.make_converter)  #: Pre-serialization steps for TOML
-ujson_preconf_stage = CattrStage(ujson.make_converter)  #: Pre-serialization steps for ultrajson
-pickle_serializer = SerializerPipeline(
-    [base_stage, pickle], is_binary=True
-)  #: Complete pickle serializer
+
+def make_stage(preconf_module: str, **kwargs):
+    """Create a preconf serializer stage from a module name, if dependencies are installed"""
+    try:
+        factory = import_module(preconf_module).make_converter
+        return CattrStage(factory, **kwargs)
+    except ImportError as e:
+        return get_placeholder_class(e)
+
+
+# Pre-serialization stages
+base_stage = CattrStage()  #: Base stage for all serializer pipelines
 utf8_encoder = Stage(dumps=str.encode, loads=lambda x: x.decode())  #: Encode to bytes
+bson_preconf_stage = make_stage('cattr.preconf.bson')  #: Pre-serialization steps for BSON
+json_preconf_stage = make_stage('cattr.preconf.json')  #: Pre-serialization steps for JSON
+msgpack_preconf_stage = make_stage('cattr.preconf.msgpack')  #: Pre-serialization steps for msgpack
+orjson_preconf_stage = make_stage('cattr.preconf.orjson')  #: Pre-serialization steps for orjson
+toml_preconf_stage = make_stage('cattr.preconf.tomlkit')  #: Pre-serialization steps for TOML
+ujson_preconf_stage = make_stage('cattr.preconf.ujson')  #: Pre-serialization steps for ultrajson
+yaml_preconf_stage = make_stage('cattr.preconf.pyyaml')  #: Pre-serialization steps for YAML
 
+# Basic serializers with no additional dependencies
+dict_serializer = SerializerPipeline(
+    [base_stage], is_binary=False
+)  #: Partial serializer that unstructures responses into dicts
+pickle_serializer = SerializerPipeline(
+    [base_stage, Stage(pickle)], is_binary=True
+)  #: Pickle serializer
 
 # Safe pickle serializer
-try:
+def signer_stage(secret_key=None, salt='requests-cache') -> Stage:
+    """Create a stage that uses ``itsdangerous`` to add a signature to responses on write, and
+    validate that signature with a secret key on read. Can be used in a
+    :py:class:`.SerializerPipeline` in combination with any other serialization steps.
+    """
     from itsdangerous import Signer
 
-    def signer_stage(secret_key=None, salt='requests-cache') -> Stage:
-        """Create a stage that uses ``itsdangerous`` to add a signature to responses on write, and
-        validate that signature with a secret key on read. Can be used in a
-        :py:class:`.SerializerPipeline` in combination with any other serialization steps.
-        """
-        return Stage(Signer(secret_key=secret_key, salt=salt), dumps='sign', loads='unsign')
+    return Stage(
+        Signer(secret_key=secret_key, salt=salt),
+        dumps='sign',
+        loads='unsign',
+    )
 
-    def safe_pickle_serializer(
-        secret_key=None, salt='requests-cache', **kwargs
-    ) -> SerializerPipeline:
-        """Create a serializer that uses ``pickle`` + ``itsdangerous`` to add a signature to
-        responses on write, and validate that signature with a secret key on read.
-        """
-        return SerializerPipeline(
-            [base_stage, pickle, signer_stage(secret_key, salt)], is_binary=True
-        )
 
+def safe_pickle_serializer(secret_key=None, salt='requests-cache', **kwargs) -> SerializerPipeline:
+    """Create a serializer that uses ``pickle`` + ``itsdangerous`` to add a signature to
+    responses on write, and validate that signature with a secret key on read.
+    """
+    return SerializerPipeline(
+        [base_stage, Stage(pickle), signer_stage(secret_key, salt)],
+        is_binary=True,
+    )
+
+
+try:
+    import itsdangerous  # noqa: F401
 except ImportError as e:
     signer_stage = get_placeholder_class(e)
     safe_pickle_serializer = get_placeholder_class(e)
 
 
 # BSON serializer
-try:
+def _get_bson_functions():
+    """Handle different function names between pymongo's bson and standalone bson"""
     try:
-        from bson import decode as _bson_loads
-        from bson import encode as _bson_dumps
+        import pymongo  # noqa: F401
+
+        return {'dumps': 'encode', 'loads': 'decode'}
     except ImportError:
-        from bson import dumps as _bson_dumps
-        from bson import loads as _bson_loads
+        return {'dumps': 'dumps', 'loads': 'loads'}
 
+
+try:
+    import bson
+
     bson_serializer = SerializerPipeline(
-        [bson_preconf_stage, Stage(dumps=_bson_dumps, loads=_bson_loads)], is_binary=True
+        [bson_preconf_stage, Stage(bson, **_get_bson_functions())],
+        is_binary=True,
     )  #: Complete BSON serializer; uses pymongo's ``bson`` if installed, otherwise standalone ``bson`` codec
 except ImportError as e:
     bson_serializer = get_placeholder_class(e)
@@ -94,7 +120,8 @@ except ImportError:
 
 _json_stage = Stage(dumps=partial(json.dumps, indent=2), loads=json.loads)
 json_serializer = SerializerPipeline(
-    [_json_preconf_stage, _json_stage], is_binary=False
+    [_json_preconf_stage, _json_stage],
+    is_binary=False,
 )  #: Complete JSON serializer; uses ultrajson if available
 
 
@@ -102,11 +129,9 @@ json_serializer = SerializerPipeline(
 try:
     import yaml
 
+    _yaml_stage = Stage(yaml, loads='safe_load', dumps='safe_dump')
     yaml_serializer = SerializerPipeline(
-        [
-            yaml_preconf_stage,
-            Stage(yaml, loads='safe_load', dumps='safe_dump'),
-        ],
+        [yaml_preconf_stage, _yaml_stage],
         is_binary=False,
     )  #: Complete YAML serializer
 except ImportError as e:
--- setup.py.orig	1970-01-01 00:00:00 UTC
+++ setup.py
@@ -13,7 +13,7 @@ package_data = \
 install_requires = \
 ['appdirs>=1.4.4,<2.0.0',
  'attrs>=21.2,<22.0',
- 'cattrs>=1.8,<2.0',
+ 'cattrs>=1.8,<23.3',
  'requests>=2.22,<3.0',
  'url-normalize>=1.4,<2.0',
  'urllib3>=1.25.5,<2.0.0']
