Format: text/x-python
⬇ Download File (3.3 KB)
   1  import logging
   2  import pickle
   3  import typing as _t
   4  
   5  
   6  class BaseSerializer:
   7      """This is the base interface for all default serializers.
   8  
   9      BaseSerializer.load and BaseSerializer.dump will
  10      default to pickle.load and pickle.dump. This is currently
  11      used only by FileSystemCache which dumps/loads to/from a file stream.
  12      """
  13  
  14      def _warn(self, e: pickle.PickleError) -> None:
  15          logging.warning(
  16              f"An exception has been raised during a pickling operation: {e}"
  17          )
  18  
  19      def dump(
  20          self, value: int, f: _t.IO, protocol: int = pickle.HIGHEST_PROTOCOL
  21      ) -> None:
  22          try:
  23              pickle.dump(value, f, protocol)
  24          except (pickle.PickleError, pickle.PicklingError) as e:
  25              self._warn(e)
  26  
  27      def load(self, f: _t.BinaryIO) -> _t.Any:
  28          try:
  29              data = pickle.load(f)
  30          except pickle.PickleError as e:
  31              self._warn(e)
  32              return None
  33          else:
  34              return data
  35  
  36      """BaseSerializer.loads and BaseSerializer.dumps
  37      work on top of pickle.loads and pickle.dumps. Dumping/loading
  38      strings and byte strings is the default for most cache types.
  39      """
  40  
  41      def dumps(self, value: _t.Any, protocol: int = pickle.HIGHEST_PROTOCOL) -> bytes:
  42          try:
  43              serialized = pickle.dumps(value, protocol)
  44          except (pickle.PickleError, pickle.PicklingError) as e:
  45              self._warn(e)
  46          return serialized
  47  
  48      def loads(self, bvalue: bytes) -> _t.Any:
  49          try:
  50              data = pickle.loads(bvalue)
  51          except pickle.PickleError as e:
  52              self._warn(e)
  53              return None
  54          else:
  55              return data
  56  
  57  
  58  """Default serializers for each cache type.
  59  
  60  The following classes can be used to further customize
  61  serialiation behaviour. Alternatively, any serializer can be
  62  overriden in order to use a custom serializer with a different
  63  strategy altogether.
  64  """
  65  
  66  
  67  class UWSGISerializer(BaseSerializer):
  68      """Default serializer for UWSGICache."""
  69  
  70  
  71  class SimpleSerializer(BaseSerializer):
  72      """Default serializer for SimpleCache."""
  73  
  74  
  75  class FileSystemSerializer(BaseSerializer):
  76      """Default serializer for FileSystemCache."""
  77  
  78  
  79  class RedisSerializer(BaseSerializer):
  80      """Default serializer for RedisCache."""
  81  
  82      def dumps(self, value: _t.Any, protocol: int = pickle.HIGHEST_PROTOCOL) -> bytes:
  83          """Dumps an object into a string for redis, using pickle by default."""
  84          return b"!" + pickle.dumps(value, protocol)
  85  
  86      def loads(self, value: _t.Optional[bytes]) -> _t.Any:
  87          """The reversal of :meth:`dump_object`. This might be called with
  88          None.
  89          """
  90          if value is None:
  91              return None
  92          if value.startswith(b"!"):
  93              try:
  94                  return pickle.loads(value[1:])
  95              except pickle.PickleError:
  96                  return None
  97          try:
  98              return int(value)
  99          except ValueError:
 100              # before 0.8 we did not have serialization. Still support that.
 101              return value
 102  
 103  
 104  class DynamoDbSerializer(RedisSerializer):
 105      """Default serializer for DynamoDbCache."""
 106  
 107      def loads(self, value: _t.Any) -> _t.Any:
 108          """The reversal of :meth:`dump_object`. This might be called with
 109          None.
 110          """
 111          value = value.value
 112          return super().loads(value)
 113