Loosen constraints from BinaryIO to IO[bytes]

master
Jan Petykiewicz 1 year ago
parent e90e44bd15
commit 0bbc8f8e08

@ -1,7 +1,7 @@
"""
Functionality for encoding/decoding basic datatypes
"""
from typing import Sequence, BinaryIO, List
from typing import Sequence, IO, List
import struct
from datetime import datetime
@ -172,7 +172,7 @@ def pack_datetime(data: Sequence[datetime]) -> bytes:
return pack_int2(parts)
def read(stream: BinaryIO, size: int) -> bytes:
def read(stream: IO[bytes], size: int) -> bytes:
""" Read and check for failure """
data = stream.read(size)
if len(data) != size:

@ -2,7 +2,7 @@
Functionality for reading/writing elements (geometry, text labels,
structure references) and associated properties.
"""
from typing import Dict, Tuple, Optional, BinaryIO, TypeVar, Type, Union
from typing import Dict, Tuple, Optional, IO, TypeVar, Type, Union
from abc import ABCMeta, abstractmethod
from dataclasses import dataclass
@ -29,7 +29,7 @@ X = TypeVar('X', bound='Box')
def read_properties(stream: BinaryIO) -> Dict[int, bytes]:
def read_properties(stream: IO[bytes]) -> Dict[int, bytes]:
"""
Read element properties.
@ -56,7 +56,7 @@ def read_properties(stream: BinaryIO) -> Dict[int, bytes]:
return properties
def write_properties(stream: BinaryIO, properties: Dict[int, bytes]) -> int:
def write_properties(stream: IO[bytes], properties: Dict[int, bytes]) -> int:
"""
Write element properties.
@ -78,7 +78,7 @@ class Element(metaclass=ABCMeta):
"""
@classmethod
@abstractmethod
def read(cls: Type[E], stream: BinaryIO) -> E:
def read(cls: Type[E], stream: IO[bytes]) -> E:
"""
Read from a stream to construct this object.
Consumes up to (and including) the ENDEL record.
@ -92,7 +92,7 @@ class Element(metaclass=ABCMeta):
pass
@abstractmethod
def write(self, stream: BinaryIO) -> int:
def write(self, stream: IO[bytes]) -> int:
"""
Write this element to a stream.
Finishes with an ENDEL record.
@ -151,7 +151,7 @@ class Reference(Element):
""" Properties associated with this reference. """
@classmethod
def read(cls: Type[R], stream: BinaryIO) -> R:
def read(cls: Type[R], stream: IO[bytes]) -> R:
invert_y = False
mag = 1
angle_deg = 0
@ -177,7 +177,7 @@ class Reference(Element):
return cls(struct_name=struct_name, xy=xy, properties=properties, colrow=colrow,
invert_y=invert_y, mag=mag, angle_deg=angle_deg)
def write(self, stream: BinaryIO) -> int:
def write(self, stream: IO[bytes]) -> int:
b = 0
if self.colrow is None:
b += SREF.write(stream, None)
@ -226,14 +226,14 @@ class Boundary(Element):
""" Properties for the element. """
@classmethod
def read(cls: Type[B], stream: BinaryIO) -> B:
def read(cls: Type[B], stream: IO[bytes]) -> B:
layer = LAYER.skip_and_read(stream)[0]
dtype = DATATYPE.read(stream)[0]
xy = XY.read(stream).reshape(-1, 2)
properties = read_properties(stream)
return cls(layer=(layer, dtype), xy=xy, properties=properties)
def write(self, stream: BinaryIO) -> int:
def write(self, stream: IO[bytes]) -> int:
b = BOUNDARY.write(stream, None)
b += LAYER.write(stream, self.layer[0])
b += DATATYPE.write(stream, self.layer[1])
@ -272,7 +272,7 @@ class Path(Element):
""" Properties for the element. """
@classmethod
def read(cls: Type[P], stream: BinaryIO) -> P:
def read(cls: Type[P], stream: IO[bytes]) -> P:
path_type = 0
width = 0
bgn_ext = 0
@ -299,7 +299,7 @@ class Path(Element):
properties=properties, extension=(bgn_ext, end_ext),
path_type=path_type, width=width)
def write(self, stream: BinaryIO) -> int:
def write(self, stream: IO[bytes]) -> int:
b = PATH.write(stream, None)
b += LAYER.write(stream, self.layer[0])
b += DATATYPE.write(stream, self.layer[1])
@ -337,14 +337,14 @@ class Box(Element):
""" Properties for the element. """
@classmethod
def read(cls: Type[X], stream: BinaryIO) -> X:
def read(cls: Type[X], stream: IO[bytes]) -> X:
layer = LAYER.skip_and_read(stream)[0]
dtype = BOXTYPE.read(stream)[0]
xy = XY.read(stream).reshape(-1, 2)
properties = read_properties(stream)
return cls(layer=(layer, dtype), xy=xy, properties=properties)
def write(self, stream: BinaryIO) -> int:
def write(self, stream: IO[bytes]) -> int:
b = BOX.write(stream, None)
b += LAYER.write(stream, self.layer[0])
b += BOXTYPE.write(stream, self.layer[1])
@ -371,14 +371,14 @@ class Node(Element):
""" Properties for the element. """
@classmethod
def read(cls: Type[N], stream: BinaryIO) -> N:
def read(cls: Type[N], stream: IO[bytes]) -> N:
layer = LAYER.skip_and_read(stream)[0]
dtype = NODETYPE.read(stream)[0]
xy = XY.read(stream).reshape(-1, 2)
properties = read_properties(stream)
return cls(layer=(layer, dtype), xy=xy, properties=properties)
def write(self, stream: BinaryIO) -> int:
def write(self, stream: IO[bytes]) -> int:
b = NODE.write(stream, None)
b += LAYER.write(stream, self.layer[0])
b += NODETYPE.write(stream, self.layer[1])
@ -431,7 +431,7 @@ class Text(Element):
""" Properties for the element. """
@classmethod
def read(cls: Type[T], stream: BinaryIO) -> T:
def read(cls: Type[T], stream: IO[bytes]) -> T:
path_type = 0
presentation = 0
invert_y = False
@ -467,7 +467,7 @@ class Text(Element):
string=string, presentation=presentation, path_type=path_type,
width=width, invert_y=invert_y, mag=mag, angle_deg=angle_deg)
def write(self, stream: BinaryIO) -> int:
def write(self, stream: IO[bytes]) -> int:
b = TEXT.write(stream, None)
b += LAYER.write(stream, self.layer[0])
b += TEXTTYPE.write(stream, self.layer[1])

@ -1,7 +1,7 @@
"""
File-level read/write functionality.
"""
from typing import List, Dict, Tuple, Optional, BinaryIO, TypeVar, Type, MutableMapping
from typing import List, Dict, Tuple, Optional, IO, TypeVar, Type, MutableMapping
import io
from datetime import datetime
from dataclasses import dataclass
@ -45,7 +45,7 @@ class FileHeader:
""" Last-accessed time """
@classmethod
def read(cls: Type[FH], stream: BinaryIO) -> FH:
def read(cls: Type[FH], stream: IO[bytes]) -> FH:
"""
Read and construct a header from the provided stream.
@ -63,7 +63,7 @@ class FileHeader:
return cls(mod_time=mod_time, acc_time=acc_time, name=name,
user_units_per_db_unit=uu, meters_per_db_unit=dbu)
def write(self, stream: BinaryIO) -> int:
def write(self, stream: IO[bytes]) -> int:
"""
Write the header to a stream
@ -80,7 +80,7 @@ class FileHeader:
return b
def scan_structs(stream: BinaryIO) -> Dict[bytes, int]:
def scan_structs(stream: IO[bytes]) -> Dict[bytes, int]:
"""
Scan through a GDS file, building a table of
{b'structure_name': byte_offset}.
@ -107,7 +107,7 @@ def scan_structs(stream: BinaryIO) -> Dict[bytes, int]:
return positions
def try_read_struct(stream: BinaryIO) -> Optional[Tuple[bytes, List[Element]]]:
def try_read_struct(stream: IO[bytes]) -> Optional[Tuple[bytes, List[Element]]]:
"""
Skip to the next structure and attempt to read it.
@ -125,7 +125,7 @@ def try_read_struct(stream: BinaryIO) -> Optional[Tuple[bytes, List[Element]]]:
return name, elements
def write_struct(stream: BinaryIO,
def write_struct(stream: IO[bytes],
name: bytes,
elements: List[Element],
cre_time: datetime = datetime(1900, 1, 1),
@ -150,7 +150,7 @@ def write_struct(stream: BinaryIO,
return b
def read_elements(stream: BinaryIO) -> List[Element]:
def read_elements(stream: IO[bytes]) -> List[Element]:
"""
Read elements from the stream until an ENDSTR
record is encountered. The ENDSTR record is also
@ -186,7 +186,7 @@ def read_elements(stream: BinaryIO) -> List[Element]:
return data
def scan_hierarchy(stream: BinaryIO) -> Dict[bytes, Dict[bytes, int]]:
def scan_hierarchy(stream: IO[bytes]) -> Dict[bytes, Dict[bytes, int]]:
"""
Scan through a GDS file, building a table of instance counts
`{b'structure_name': {b'ref_name': count}}`.

@ -1,7 +1,7 @@
"""
Generic record-level read/write functionality.
"""
from typing import Optional, Sequence, BinaryIO
from typing import Optional, Sequence, IO
from typing import TypeVar, List, Tuple, ClassVar, Type
import struct
import io
@ -19,7 +19,7 @@ from .basic import parse_ascii, pack_ascii, read
_RECORD_HEADER_FMT = struct.Struct('>HH')
def write_record_header(stream: BinaryIO, data_size: int, tag: int) -> int:
def write_record_header(stream: IO[bytes], data_size: int, tag: int) -> int:
record_size = data_size + 4
if record_size > 0xFFFF:
raise KlamathError(f'Record size is too big: {record_size}')
@ -27,7 +27,7 @@ def write_record_header(stream: BinaryIO, data_size: int, tag: int) -> int:
return stream.write(header)
def read_record_header(stream: BinaryIO) -> Tuple[int, int]:
def read_record_header(stream: IO[bytes]) -> Tuple[int, int]:
"""
Read a record's header (size and tag).
Args:
@ -46,7 +46,7 @@ def read_record_header(stream: BinaryIO) -> Tuple[int, int]:
return data_size, tag
def expect_record(stream: BinaryIO, tag: int) -> int:
def expect_record(stream: IO[bytes], tag: int) -> int:
data_size, actual_tag = read_record_header(stream)
if tag != actual_tag:
raise KlamathError(f'Unexpected record! Got tag 0x{actual_tag:04x}, expected 0x{tag:04x}')
@ -71,7 +71,7 @@ class Record(metaclass=ABCMeta):
@classmethod
@abstractmethod
def read_data(cls, stream: BinaryIO, size: int):
def read_data(cls, stream: IO[bytes], size: int):
pass
@classmethod
@ -80,15 +80,15 @@ class Record(metaclass=ABCMeta):
pass
@staticmethod
def read_header(stream: BinaryIO) -> Tuple[int, int]:
def read_header(stream: IO[bytes]) -> Tuple[int, int]:
return read_record_header(stream)
@classmethod
def write_header(cls, stream: BinaryIO, data_size: int) -> int:
def write_header(cls, stream: IO[bytes], data_size: int) -> int:
return write_record_header(stream, data_size, cls.tag)
@classmethod
def skip_past(cls, stream: BinaryIO) -> bool:
def skip_past(cls, stream: IO[bytes]) -> bool:
"""
Skip to the end of the next occurence of this record.
@ -110,7 +110,7 @@ class Record(metaclass=ABCMeta):
return True
@classmethod
def skip_and_read(cls, stream: BinaryIO):
def skip_and_read(cls, stream: IO[bytes]):
size, tag = Record.read_header(stream)
while tag != cls.tag:
stream.seek(size, io.SEEK_CUR)
@ -119,13 +119,13 @@ class Record(metaclass=ABCMeta):
return data
@classmethod
def read(cls: Type[R], stream: BinaryIO):
def read(cls: Type[R], stream: IO[bytes]):
size = expect_record(stream, cls.tag)
data = cls.read_data(stream, size)
return data
@classmethod
def write(cls, stream: BinaryIO, data) -> int:
def write(cls, stream: IO[bytes], data) -> int:
data_bytes = cls.pack_data(data)
b = cls.write_header(stream, len(data_bytes))
b += stream.write(data_bytes)
@ -136,7 +136,7 @@ class NoDataRecord(Record):
expected_size: ClassVar[Optional[int]] = 0
@classmethod
def read_data(cls, stream: BinaryIO, size: int) -> None:
def read_data(cls, stream: IO[bytes], size: int) -> None:
stream.read(size)
@classmethod
@ -150,7 +150,7 @@ class BitArrayRecord(Record):
expected_size: ClassVar[Optional[int]] = 2
@classmethod
def read_data(cls, stream: BinaryIO, size: int) -> int:
def read_data(cls, stream: IO[bytes], size: int) -> int:
return parse_bitarray(read(stream, 2))
@classmethod
@ -160,7 +160,7 @@ class BitArrayRecord(Record):
class Int2Record(Record):
@classmethod
def read_data(cls, stream: BinaryIO, size: int) -> numpy.ndarray:
def read_data(cls, stream: IO[bytes], size: int) -> numpy.ndarray:
return parse_int2(read(stream, size))
@classmethod
@ -170,7 +170,7 @@ class Int2Record(Record):
class Int4Record(Record):
@classmethod
def read_data(cls, stream: BinaryIO, size: int) -> numpy.ndarray:
def read_data(cls, stream: IO[bytes], size: int) -> numpy.ndarray:
return parse_int4(read(stream, size))
@classmethod
@ -180,7 +180,7 @@ class Int4Record(Record):
class Real8Record(Record):
@classmethod
def read_data(cls, stream: BinaryIO, size: int) -> numpy.ndarray:
def read_data(cls, stream: IO[bytes], size: int) -> numpy.ndarray:
return parse_real8(read(stream, size))
@classmethod
@ -190,7 +190,7 @@ class Real8Record(Record):
class ASCIIRecord(Record):
@classmethod
def read_data(cls, stream: BinaryIO, size: int) -> bytes:
def read_data(cls, stream: IO[bytes], size: int) -> bytes:
return parse_ascii(read(stream, size))
@classmethod
@ -200,7 +200,7 @@ class ASCIIRecord(Record):
class DateTimeRecord(Record):
@classmethod
def read_data(cls, stream: BinaryIO, size: int) -> List[datetime]:
def read_data(cls, stream: IO[bytes], size: int) -> List[datetime]:
return parse_datetime(read(stream, size))
@classmethod

Loading…
Cancel
Save