示例#1
0
 def parse_one_item(cls: Type[cls.__name__], f_type: Type,
                    f: BinaryIO):  # type: ignore
     inner_type: Type
     if is_type_List(f_type):
         inner_type = f_type.__args__[0]
         full_list: List[inner_type] = []  # type: ignore
         assert inner_type != List.__args__[0]  # type: ignore
         list_size: uint32 = uint32(int.from_bytes(f.read(4), "big"))
         for list_index in range(list_size):
             full_list.append(cls.parse_one_item(inner_type,
                                                 f))  # type: ignore
         return full_list
     if is_type_SpecificOptional(f_type):
         inner_type = f_type.__args__[0]
         is_present: bool = f.read(1) == bytes([1])
         if is_present:
             return cls.parse_one_item(inner_type, f)  # type: ignore
         else:
             return None
     if hasattr(f_type, "parse"):
         return f_type.parse(f)
     if hasattr(f_type, "from_bytes") and size_hints[f_type.__name__]:
         return f_type.from_bytes(f.read(size_hints[f_type.__name__]))
     if f_type is str:
         str_size: uint32 = uint32(int.from_bytes(f.read(4), "big"))
         return bytes.decode(f.read(str_size), "utf-8")
     else:
         raise RuntimeError(f"Type {f_type} does not have parse")
示例#2
0
 def stream_one_item(self, f_type: Type, item, f: BinaryIO) -> None:
     inner_type: Type
     if is_type_List(f_type):
         assert is_type_List(type(item))
         f.write(uint32(len(item)).to_bytes(4, "big"))
         inner_type = f_type.__args__[0]
         assert inner_type != List.__args__[0]  # type: ignore
         for element in item:
             self.stream_one_item(inner_type, element, f)
     elif is_type_SpecificOptional(f_type):
         inner_type = f_type.__args__[0]
         if item is None:
             f.write(bytes([0]))
         else:
             f.write(bytes([1]))
             self.stream_one_item(inner_type, item, f)
     elif hasattr(f_type, "stream"):
         item.stream(f)
     elif hasattr(f_type, "__bytes__"):
         f.write(bytes(item))
     elif f_type is str:
         f.write(uint32(len(item)).to_bytes(4, "big"))
         f.write(item.encode("utf-8"))
     else:
         raise NotImplementedError(f"can't stream {item}, {f_type}")
def dataclass_from_dict(klass, d):
    """
    Converts a dictionary based on a dataclass, into an instance of that dataclass.
    Recursively goes through lists, optionals, and dictionaries.
    """
    if is_type_SpecificOptional(klass):
        # Type is optional, data is either None, or Any
        if not d:
            return None
        return dataclass_from_dict(get_args(klass)[0], d)
    elif is_type_Tuple(klass):
        return tuple(dataclass_from_dict(get_args(klass)[0], item) for item in d)
    elif dataclasses.is_dataclass(klass):
        # Type is a dataclass, data is a dictionary
        fieldtypes = {f.name: f.type for f in dataclasses.fields(klass)}
        return klass(**{f: dataclass_from_dict(fieldtypes[f], d[f]) for f in d})
    elif is_type_List(klass):
        # Type is a list, data is a list
        return [dataclass_from_dict(get_args(klass)[0], item) for item in d]
    elif issubclass(klass, bytes):
        # Type is bytes, data is a hex string
        return klass(hexstr_to_bytes(d))
    elif klass in unhashable_types:
        # Type is unhashable (bls type), so cast from hex string
        return klass.from_bytes(hexstr_to_bytes(d))
    else:
        # Type is a primitive, cast with correct class
        return klass(d)
 def parse_one_item(cls: Type[cls.__name__], f_type: Type, f: BinaryIO):  # type: ignore
     inner_type: Type
     if is_type_List(f_type):
         inner_type = get_args(f_type)[0]
         full_list: List[inner_type] = []  # type: ignore
         # wjb assert inner_type != get_args(List)[0]  # type: ignore
         list_size_bytes = f.read(4)
         assert list_size_bytes is not None and len(list_size_bytes) == 4  # Checks for EOF
         list_size: uint32 = uint32(int.from_bytes(list_size_bytes, "big"))
         for list_index in range(list_size):
             full_list.append(cls.parse_one_item(inner_type, f))  # type: ignore
         return full_list
     if is_type_SpecificOptional(f_type):
         inner_type = get_args(f_type)[0]
         is_present_bytes = f.read(1)
         assert is_present_bytes is not None and len(is_present_bytes) == 1  # Checks for EOF
         if is_present_bytes == bytes([0]):
             return None
         elif is_present_bytes == bytes([1]):
             return cls.parse_one_item(inner_type, f)  # type: ignore
         else:
             raise ValueError("Optional must be 0 or 1")
     if is_type_Tuple(f_type):
         inner_types = get_args(f_type)
         full_list = []
         for inner_type in inner_types:
             full_list.append(cls.parse_one_item(inner_type, f))  # type: ignore
         return tuple(full_list)
     if f_type is bool:
         bool_byte = f.read(1)
         assert bool_byte is not None and len(bool_byte) == 1  # Checks for EOF
         if bool_byte == bytes([0]):
             return False
         elif bool_byte == bytes([1]):
             return True
         else:
             raise ValueError("Bool byte must be 0 or 1")
     if f_type == bytes:
         list_size_bytes = f.read(4)
         assert list_size_bytes is not None and len(list_size_bytes) == 4  # Checks for EOF
         list_size = uint32(int.from_bytes(list_size_bytes, "big"))
         bytes_read = f.read(list_size)
         assert bytes_read is not None and len(bytes_read) == list_size
         return bytes_read
     if hasattr(f_type, "parse"):
         return f_type.parse(f)
     if hasattr(f_type, "from_bytes") and size_hints[f_type.__name__]:
         bytes_to_read = size_hints[f_type.__name__]
         bytes_read = f.read(bytes_to_read)
         assert bytes_read is not None and len(bytes_read) == bytes_to_read
         return f_type.from_bytes(bytes_read)
     if f_type is str:
         str_size_bytes = f.read(4)
         assert str_size_bytes is not None and len(str_size_bytes) == 4  # Checks for EOF
         str_size: uint32 = uint32(int.from_bytes(str_size_bytes, "big"))
         str_read_bytes = f.read(str_size)
         assert str_read_bytes is not None and len(str_read_bytes) == str_size  # Checks for EOF
         return bytes.decode(str_read_bytes, "utf-8")
     else:
         raise RuntimeError(f"Type {f_type} does not have parse")
示例#5
0
 def stream_one_item(self, f_type: Type, item, f: BinaryIO) -> None:
     inner_type: Type
     if is_type_List(f_type):
         assert is_type_List(type(item))
         f.write(uint32(len(item)).to_bytes(4, "big"))
         inner_type = get_args(f_type)[0]
         # wjb assert inner_type != get_args(List)[0]  # type: ignore
         for element in item:
             self.stream_one_item(inner_type, element, f)
     elif is_type_SpecificOptional(f_type):
         inner_type = get_args(f_type)[0]
         if item is None:
             f.write(bytes([0]))
         else:
             f.write(bytes([1]))
             self.stream_one_item(inner_type, item, f)
     elif is_type_Tuple(f_type):
         inner_types = get_args(f_type)
         assert len(item) == len(inner_types)
         for i in range(len(item)):
             self.stream_one_item(inner_types[i], item[i], f)
     elif f_type == bytes:
         f.write(uint32(len(item)).to_bytes(4, "big"))
         f.write(item)
     elif hasattr(f_type, "stream"):
         item.stream(f)
     elif hasattr(f_type, "__bytes__"):
         f.write(bytes(item))
     elif f_type is str:
         f.write(uint32(len(item)).to_bytes(4, "big"))
         f.write(item.encode("utf-8"))
     elif f_type is bool:
         f.write(int(item).to_bytes(4, "big"))
     else:
         raise NotImplementedError(f"can't stream {item}, {f_type}")
示例#6
0
 def test_basic_optional(self):
     assert is_type_SpecificOptional(Optional[int])
     assert is_type_SpecificOptional(Optional[Optional[int]])
     assert not is_type_SpecificOptional(List[int])