diff --git a/xrpl/binarycodec/types/hash.py b/xrpl/binarycodec/types/hash.py index 442fa8edb..5f354f363 100644 --- a/xrpl/binarycodec/types/hash.py +++ b/xrpl/binarycodec/types/hash.py @@ -3,10 +3,10 @@ """ from __future__ import annotations # Requires Python 3.7+ -from abc import ABC - -from typing_extensions import Final +from abc import ABC, abstractmethod +from typing import Optional, Type +from xrpl.binarycodec.binary_wrappers.binary_parser import BinaryParser from xrpl.binarycodec.exceptions import XRPLBinaryCodecException from xrpl.binarycodec.types.serialized_type import SerializedType @@ -15,24 +15,66 @@ class Hash(SerializedType, ABC): """ Base class for XRPL Hash types. `See Hash Fields `_ - - Attributes: - _LENGTH: The length of this hash in bytes. """ - _LENGTH: Final[int] - - def __init__(self: Hash, buffer: bytes) -> None: + def __init__(self: Hash, buffer: Optional[bytes]) -> None: """ Construct a Hash. - :param buffer: The byte buffer that will be used to store - the serialized encoding of this field. + Args: + buffer: The byte buffer that will be used to store the serialized + encoding of this field. """ - if len(buffer) != self._LENGTH: + buffer = buffer if buffer is not None else bytes(self._get_length()) + + if len(buffer) != self._get_length(): raise XRPLBinaryCodecException("Invalid hash length {}".format(len(buffer))) super().__init__(buffer) def __str__(self: Hash) -> str: """Returns a hex-encoded string representation of the bytes buffer.""" return self.to_hex() + + @classmethod + def from_value(cls: Type[Hash], value: str) -> Hash: + """ + Construct a Hash object from a hex string. + + Args: + value: The value to construct a Hash from. + + Returns: + The Hash object constructed from value. + + Raises: + XRPLBinaryCodecException: If the supplied value is of the wrong type. + """ + if not isinstance(value, str): + raise XRPLBinaryCodecException( + "Invalid type to construct a {}: expected str," + " received {}.".format(cls.__name__, value.__class__.__name__) + ) + + return cls(bytes.fromhex(value)) + + @classmethod + def from_parser( + cls: Type[Hash], parser: BinaryParser, length_hint: Optional[int] = None + ) -> Hash: + """ + Construct a Hash object from an existing BinaryParser. + + Args: + parser: The parser to construct the Hash object from. + length_hint: The number of bytes to consume from the parser. + + Returns: + The Hash object constructed from a parser. + """ + num_bytes = length_hint if length_hint is not None else cls._get_length() + return cls(parser.read(num_bytes)) + + @classmethod + @abstractmethod + def _get_length(cls: Type[Hash]) -> int: + raise NotImplementedError("Hash._get_length not implemented") diff --git a/xrpl/binarycodec/types/hash128.py b/xrpl/binarycodec/types/hash128.py index 111239995..39d7bafed 100644 --- a/xrpl/binarycodec/types/hash128.py +++ b/xrpl/binarycodec/types/hash128.py @@ -5,10 +5,8 @@ """ from __future__ import annotations -from typing import Optional +from typing import Type -from xrpl.binarycodec import XRPLBinaryCodecException -from xrpl.binarycodec.binary_wrappers.binary_parser import BinaryParser from xrpl.binarycodec.types.hash import Hash @@ -17,54 +15,8 @@ class Hash128(Hash): Codec for serializing and deserializing a hash field with a width of 128 bits (16 bytes). `See Hash Fields `_ - - - Attributes: - _LENGTH: The length of this hash in bytes. """ - _LENGTH = 16 - - def __init__(self: Hash128, buffer: bytes = None) -> None: - """Construct a Hash128.""" - buffer = buffer if buffer is not None else bytes(self._LENGTH) - super().__init__(buffer) - - @classmethod - def from_value(cls: Hash128, value: str) -> Hash128: - """ - Construct a Hash128 object from a hex string. - - Args: - value: The value to construct a Hash128 from. - - Returns: - The Hash128 object constructed from value. - - Raises: - XRPLBinaryCodecException: If the supplied value is of the wrong type. - """ - if not isinstance(value, str): - raise XRPLBinaryCodecException( - "Invalid type to construct a Hash128: expected str," - " received {}.".format(value.__class__.__name__) - ) - - return cls(bytes.fromhex(value)) - @classmethod - def from_parser( - cls: Hash128, parser: BinaryParser, length_hint: Optional[int] = None - ) -> Hash128: - """ - Construct a Hash128 object from an existing BinaryParser. - - Args: - parser: The parser to construct the Hash128 object from. - length_hint: The number of bytes to consume from the parser. - - Returns: - The Hash128 object constructed from a parser. - """ - num_bytes = length_hint if length_hint is not None else cls._LENGTH - return cls(parser.read(num_bytes)) + def _get_length(cls: Type[Hash128]) -> int: + return 16 diff --git a/xrpl/binarycodec/types/hash160.py b/xrpl/binarycodec/types/hash160.py index 0e6d85a8b..9f4f7aef6 100644 --- a/xrpl/binarycodec/types/hash160.py +++ b/xrpl/binarycodec/types/hash160.py @@ -4,10 +4,8 @@ """ from __future__ import annotations -from typing import Optional, Type +from typing import Type -from xrpl.binarycodec import XRPLBinaryCodecException -from xrpl.binarycodec.binary_wrappers.binary_parser import BinaryParser from xrpl.binarycodec.types.hash import Hash @@ -16,54 +14,8 @@ class Hash160(Hash): Codec for serializing and deserializing a hash field with a width of 160 bits (20 bytes). `See Hash Fields `_ - - - Attributes: - _LENGTH: The length of this hash in bytes. """ - _LENGTH = 20 - - def __init__(self: Hash160, buffer: bytes = None) -> None: - """Construct a Hash160.""" - buffer = buffer if buffer is not None else bytes(self._width) - super().__init__(buffer) - - @classmethod - def from_value(cls: Hash160, value: str) -> Hash160: - """ - Construct a Hash160 object from a hex string. - - Args: - value: The string to construct a Hash160 from. - - Returns: - The Hash160 constructed from value. - - Raises: - XRPLBinaryCodecException: If the supplied value is of the wrong type. - """ - if not isinstance(value, str): - raise XRPLBinaryCodecException( - "Invalid type to construct a Hash160: expected str," - " received {}.".format(value.__class__.__name__) - ) - - return cls(bytes.fromhex(value)) - @classmethod - def from_parser( - cls: Type[Hash160], parser: BinaryParser, length_hint: Optional[int] = None - ) -> Hash160: - """ - Construct a Hash160 object from an existing BinaryParser. - - Args: - parser: The parser to construct Hash160 from. - length_hint: The number of bytes to consume from the parser. - - Returns: - The Hash160 constructed from the parser. - """ - num_bytes = length_hint if length_hint is not None else cls._LENGTH - return cls(parser.read(num_bytes)) + def _get_length(cls: Type[Hash160]) -> int: + return 20 diff --git a/xrpl/binarycodec/types/hash256.py b/xrpl/binarycodec/types/hash256.py index 48763071f..ea0a38e9a 100644 --- a/xrpl/binarycodec/types/hash256.py +++ b/xrpl/binarycodec/types/hash256.py @@ -5,10 +5,8 @@ """ from __future__ import annotations -from typing import Optional +from typing import Type -from xrpl.binarycodec import XRPLBinaryCodecException -from xrpl.binarycodec.binary_wrappers.binary_parser import BinaryParser from xrpl.binarycodec.types.hash import Hash @@ -17,53 +15,8 @@ class Hash256(Hash): Codec for serializing and deserializing a hash field with a width of 256 bits (32 bytes). `See Hash Fields `_ - - - Attributes: - : The length of this hash in bytes. """ - _LENGTH = 32 - - def __init__(self: Hash256, buffer: bytes = None) -> None: - """Construct a Hash256.""" - buffer = buffer if buffer is not None else bytes(self._width) - super().__init__(buffer) - @classmethod - def from_value(cls: Hash256, value: str) -> Hash256: - """ - Construct a Hash256 object from a hex string. - - Args: - value: The string to construct a Hash256 object from. - - Returns: - The Hash256 constructed from value. - - Raises: - XRPLBinaryCodecException: If the supplied value is of the wrong type. - """ - if not isinstance(value, str): - raise XRPLBinaryCodecException( - "Invalid type to construct a Hash256: expected str," - " received {}.".format(value.__class__.__name__) - ) - return cls(bytes.fromhex(value)) - - @classmethod - def from_parser( - cls: Hash256, parser: BinaryParser, length_hint: Optional[int] = None - ) -> Hash256: - """ - Construct a Hash256 object from an existing BinaryParser. - - Args: - parser: The parser to construct a Hash256 from. - length_hint: The number of bytes to consume from the parser. - - Returns: - The Hash256 constructed from parser. - """ - num_bytes = length_hint if length_hint is not None else cls._LENGTH - return cls(parser.read(num_bytes)) + def _get_length(cls: Type[Hash256]) -> int: + return 32