Loosen constraints from BinaryIO to IO[bytes]

This commit is contained in:
Jan Petykiewicz 2023-01-26 12:32:19 -08:00
parent e90e44bd15
commit 0bbc8f8e08
4 changed files with 45 additions and 45 deletions

View File

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

View File

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

View File

@ -1,7 +1,7 @@
""" """
File-level read/write functionality. 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 import io
from datetime import datetime from datetime import datetime
from dataclasses import dataclass from dataclasses import dataclass
@ -45,7 +45,7 @@ class FileHeader:
""" Last-accessed time """ """ Last-accessed time """
@classmethod @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. 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, return cls(mod_time=mod_time, acc_time=acc_time, name=name,
user_units_per_db_unit=uu, meters_per_db_unit=dbu) 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 Write the header to a stream
@ -80,7 +80,7 @@ class FileHeader:
return b 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 Scan through a GDS file, building a table of
{b'structure_name': byte_offset}. {b'structure_name': byte_offset}.
@ -107,7 +107,7 @@ def scan_structs(stream: BinaryIO) -> Dict[bytes, int]:
return positions 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. 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 return name, elements
def write_struct(stream: BinaryIO, def write_struct(stream: IO[bytes],
name: bytes, name: bytes,
elements: List[Element], elements: List[Element],
cre_time: datetime = datetime(1900, 1, 1), cre_time: datetime = datetime(1900, 1, 1),
@ -150,7 +150,7 @@ def write_struct(stream: BinaryIO,
return b 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 Read elements from the stream until an ENDSTR
record is encountered. The ENDSTR record is also record is encountered. The ENDSTR record is also
@ -186,7 +186,7 @@ def read_elements(stream: BinaryIO) -> List[Element]:
return data 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 Scan through a GDS file, building a table of instance counts
`{b'structure_name': {b'ref_name': count}}`. `{b'structure_name': {b'ref_name': count}}`.

View File

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