text.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. from rlp.atomic import (
  2. Atomic,
  3. )
  4. from rlp.exceptions import (
  5. DeserializationError,
  6. SerializationError,
  7. )
  8. class Text:
  9. """
  10. A sedes object for encoded text data of certain length.
  11. :param min_length: the minimal length in encoded characters or `None` for no lower
  12. limit
  13. :param max_length: the maximal length in encoded characters or `None` for no upper
  14. limit
  15. :param allow_empty: if true, empty strings are considered valid even if
  16. a minimum length is required otherwise
  17. """
  18. def __init__(
  19. self, min_length=None, max_length=None, allow_empty=False, encoding="utf8"
  20. ):
  21. self.min_length = min_length or 0
  22. if max_length is None:
  23. self.max_length = float("inf")
  24. else:
  25. self.max_length = max_length
  26. self.allow_empty = allow_empty
  27. self.encoding = encoding
  28. @classmethod
  29. def fixed_length(cls, length, allow_empty=False):
  30. """Create a sedes for text data with exactly `length` encoded characters."""
  31. return cls(length, length, allow_empty=allow_empty)
  32. @classmethod
  33. def is_valid_type(cls, obj):
  34. return isinstance(obj, str)
  35. def is_valid_length(self, length):
  36. return any(
  37. (
  38. self.min_length <= length <= self.max_length,
  39. self.allow_empty and length == 0,
  40. )
  41. )
  42. def serialize(self, obj):
  43. if not self.is_valid_type(obj):
  44. raise SerializationError(f"Object is not a serializable ({type(obj)})", obj)
  45. if not self.is_valid_length(len(obj)):
  46. raise SerializationError("Object has invalid length", obj)
  47. return obj.encode(self.encoding)
  48. def deserialize(self, serial):
  49. if not isinstance(serial, Atomic):
  50. raise DeserializationError(
  51. f"Objects of type {type(serial).__name__} cannot be deserialized",
  52. serial,
  53. )
  54. try:
  55. text_value = serial.decode(self.encoding)
  56. except UnicodeDecodeError as err:
  57. raise DeserializationError(str(err), serial)
  58. if self.is_valid_length(len(text_value)):
  59. return text_value
  60. else:
  61. raise DeserializationError(f"{type(serial)} has invalid length", serial)
  62. text = Text()