diff options
author | Jordan Cook <jordan.cook@pioneer.com> | 2022-04-09 13:33:32 -0500 |
---|---|---|
committer | Jordan Cook <jordan.cook@pioneer.com> | 2022-04-09 15:42:39 -0500 |
commit | 82e68b9f917ddc78feaa19fb4d63fffe20047089 (patch) | |
tree | 8e3b7c0babaa49780639321cdfa01f9d3c4eb473 | |
parent | 9c2defeba951fc166d1d6b5079f0ae7d73dde361 (diff) | |
download | requests-cache-82e68b9f917ddc78feaa19fb4d63fffe20047089.tar.gz |
Add compatibility with cattrs 21.1+, and clean up preconf module a bit
-rw-r--r-- | poetry.lock | 52 | ||||
-rw-r--r-- | pyproject.toml | 2 | ||||
-rw-r--r-- | requests_cache/__init__.py | 2 | ||||
-rw-r--r-- | requests_cache/serializers/preconf.py | 89 |
4 files changed, 84 insertions, 61 deletions
diff --git a/poetry.lock b/poetry.lock index 5db2e9b..6fe2a64 100644 --- a/poetry.lock +++ b/poetry.lock @@ -63,11 +63,11 @@ pytz = ">=2015.7" [[package]] name = "beautifulsoup4" -version = "4.10.0" +version = "4.11.1" description = "Screen-scraping library" category = "main" optional = true -python-versions = ">3.0.0" +python-versions = ">=3.6.0" [package.dependencies] soupsieve = ">1.2" @@ -78,14 +78,14 @@ lxml = ["lxml"] [[package]] name = "boto3" -version = "1.21.35" +version = "1.21.37" description = "The AWS SDK for Python" category = "main" optional = true python-versions = ">= 3.6" [package.dependencies] -botocore = ">=1.24.35,<1.25.0" +botocore = ">=1.24.37,<1.25.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.5.0,<0.6.0" @@ -94,7 +94,7 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.24.35" +version = "1.24.37" description = "Low-level, data-driven core of boto 3." category = "main" optional = true @@ -122,7 +122,7 @@ six = ">=1.9.0" [[package]] name = "cattrs" -version = "1.10.0" +version = "22.1.0" description = "Composable complex class support for attrs and dataclasses." category = "main" optional = false @@ -130,6 +130,7 @@ python-versions = ">=3.7,<4.0" [package.dependencies] attrs = ">=20" +exceptiongroup = {version = "*", markers = "python_version <= \"3.10\""} typing_extensions = {version = "*", markers = "python_version >= \"3.7\" and python_version < \"3.8\""} [[package]] @@ -237,6 +238,17 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] +name = "exceptiongroup" +version = "1.0.0rc2" +description = "Backport of PEP 654 (exception groups)" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +test = ["pytest (>=6)", "coverage (>=6)"] + +[[package]] name = "execnet" version = "1.9.0" description = "execnet: rapid multi-Python deployment" @@ -261,7 +273,7 @@ testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-co [[package]] name = "furo" -version = "2022.3.4" +version = "2022.4.7" description = "A clean customisable Sphinx documentation theme." category = "main" optional = true @@ -1259,7 +1271,7 @@ yaml = ["pyyaml"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "ef51335c82b4ea675988ed97c3f9f67f24a2cad0c6edec0d1695cd68ed686ffe" +content-hash = "5cb2e245d8e7642d221b6fb33465920b316e2e8e318db4c833a7ba919ee145d3" [metadata.files] alabaster = [ @@ -1287,23 +1299,23 @@ babel = [ {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, ] beautifulsoup4 = [ - {file = "beautifulsoup4-4.10.0-py3-none-any.whl", hash = "sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf"}, - {file = "beautifulsoup4-4.10.0.tar.gz", hash = "sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891"}, + {file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"}, + {file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"}, ] boto3 = [ - {file = "boto3-1.21.35-py3-none-any.whl", hash = "sha256:4fb810755bca4696effbeb0c6f792295795fae52e895638038dff53965f3f423"}, - {file = "boto3-1.21.35.tar.gz", hash = "sha256:ab6e001ba9de1db986634424abff6c79d938c15d0d2fa3ef95eb0939c120b4f6"}, + {file = "boto3-1.21.37-py3-none-any.whl", hash = "sha256:1e845aa92b3ad70b954329b98835135c28b3000e322ff8d3fc46a956bdb6e94b"}, + {file = "boto3-1.21.37.tar.gz", hash = "sha256:013ba57295f05da141e364191dd46f4086e8fe3eb83a3cd09730eeb684ffbab3"}, ] botocore = [ - {file = "botocore-1.24.35-py3-none-any.whl", hash = "sha256:734aa598af5d6bc0351e6ecce4a91b0b6ccf245febfd8d4de8425211aada5f36"}, - {file = "botocore-1.24.35.tar.gz", hash = "sha256:36b5422d8f0c312983582b8b4b056c98e1fd6121cb0b2ddb1f67e882e1ae6867"}, + {file = "botocore-1.24.37-py3-none-any.whl", hash = "sha256:21e164a213beca36033c46026bffa62f2ee2cd2600777271f9a551fb34dba006"}, + {file = "botocore-1.24.37.tar.gz", hash = "sha256:70c48c4ae3c2b9ec0ca025385979d01f4c7dae4d9a61c82758d4cf7caa7082cd"}, ] bson = [ {file = "bson-0.5.10.tar.gz", hash = "sha256:d6511b2ab051139a9123c184de1a04227262173ad593429d21e443d6462d6590"}, ] cattrs = [ - {file = "cattrs-1.10.0-py3-none-any.whl", hash = "sha256:35dd9063244263e63bd0bd24ea61e3015b00272cead084b2c40d788b0f857c46"}, - {file = "cattrs-1.10.0.tar.gz", hash = "sha256:211800f725cdecedcbcf4c753bbd22d248312b37d130f06045434acb7d9b34e1"}, + {file = "cattrs-22.1.0-py3-none-any.whl", hash = "sha256:d55c477b4672f93606e992049f15d526dc7867e6c756cd6256d4af92e2b1e364"}, + {file = "cattrs-22.1.0.tar.gz", hash = "sha256:94b67b64cf92c994f8784c40c082177dc916e0489a73a9a36b24eb18a9db40c6"}, ] certifi = [ {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, @@ -1384,6 +1396,10 @@ docutils = [ {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] +exceptiongroup = [ + {file = "exceptiongroup-1.0.0rc2-py3-none-any.whl", hash = "sha256:83e465152bd0bc2bc40d9b75686854260f86946bb947c652b5cafc31cdff70e7"}, + {file = "exceptiongroup-1.0.0rc2.tar.gz", hash = "sha256:4d254b05231bed1d43079bdcfe0f1d66c0ab4783e6777a329355f9b78de3ad83"}, +] execnet = [ {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, @@ -1393,8 +1409,8 @@ filelock = [ {file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"}, ] furo = [ - {file = "furo-2022.3.4-py3-none-any.whl", hash = "sha256:6c718293ebf87755f0b9f148b1e697c9e3aabd7af955644d4bcaee5ce75db781"}, - {file = "furo-2022.3.4.tar.gz", hash = "sha256:7660267cc67b2828fd0e17bc07adeb612c47b2eba5a6de07049a1569e6044aa8"}, + {file = "furo-2022.4.7-py3-none-any.whl", hash = "sha256:7f3e3d2fb977483590f8ecb2c2cd511bd82661b79c18efb24de9558bc9cdf2d7"}, + {file = "furo-2022.4.7.tar.gz", hash = "sha256:96204ab7cd047e4b6c523996e0279c4c629a8fc31f4f109b2efd470c17f49c80"}, ] identify = [ {file = "identify-2.4.12-py2.py3-none-any.whl", hash = "sha256:5f06b14366bd1facb88b00540a1de05b69b310cbc2654db3c7e07fa3a4339323"}, diff --git a/pyproject.toml b/pyproject.toml index a39fd4b..ae9fec9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ python = "^3.7" requests = "^2.22" # Needs no introduction urllib3 = ">=1.25.5" # Use a slightly newer version than required by requests (for bugfixes) attrs = ">=21.2" # For response data models -cattrs = "^1.8" # For response serialization +cattrs = ">=22.0" # For response serialization platformdirs = "^2.5" # For options that use platform-specific user cache dirs url-normalize = "^1.4" # For improved request matching diff --git a/requests_cache/__init__.py b/requests_cache/__init__.py index b752000..81da8e9 100644 --- a/requests_cache/__init__.py +++ b/requests_cache/__init__.py @@ -18,4 +18,4 @@ try: from .settings import * # Log and ignore ImportErrors, if imported outside a virtualenv (e.g., just to check __version__) except ImportError as e: - logger.warning(e) + logger.warning(e, exc_info=True) diff --git a/requests_cache/serializers/preconf.py b/requests_cache/serializers/preconf.py index ed19fb4..cb099b8 100644 --- a/requests_cache/serializers/preconf.py +++ b/requests_cache/serializers/preconf.py @@ -1,3 +1,4 @@ +# 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. @@ -14,69 +15,75 @@ class that raises an ``ImportError`` at initialization time instead of at import """ import pickle from functools import partial - -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 importlib import import_module 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) + +def make_stage(preconf_module: str): + """Create a preconf serializer stage from a module name, if dependencies are installed""" + try: + return CattrStage(import_module(preconf_module).make_converter) + except ImportError as e: + return get_placeholder_class(e) + + +base_stage = CattrStage() #: Base stage for all serializer pipelines 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 +pickle_serializer = SerializerPipeline([base_stage, pickle], is_binary=True) #: Pickle serializer 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 # 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') - - 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 - ) + 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) + +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'} + + +# BSON serializer +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) |