--- 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 `_ 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']