From 3016aec3dfe3dfa317b381f0277f332e199cfa29 Mon Sep 17 00:00:00 2001 From: jan Date: Thu, 19 Jan 2023 22:20:50 -0800 Subject: [PATCH 01/40] wip --- fatamorgana/basic.py | 210 ++++----- fatamorgana/main.py | 52 ++- fatamorgana/records.py | 657 ++++++++++++++-------------- fatamorgana/test/build_testfiles.py | 3 +- 4 files changed, 468 insertions(+), 454 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 6194ab0..b745f2f 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -11,7 +11,8 @@ import io import warnings try: - import numpy # type: ignore + import numpy + from numpy.typing import NDArray _USE_NUMPY = True except ImportError: _USE_NUMPY = False @@ -161,7 +162,7 @@ def _py_write_bool_byte(stream: io.BufferedIOBase, bits: Tuple[Union[bool, int], InvalidDataError if didn't receive 8 bits. """ if len(bits) != 8: - raise InvalidDataError('write_bool_byte received {} bits, requires 8'.format(len(bits))) + raise InvalidDataError(f'write_bool_byte received {len(bits)} bits, requires 8') byte = 0 for i, bit in enumerate(reversed(bits)): byte |= bit << i @@ -169,7 +170,7 @@ def _py_write_bool_byte(stream: io.BufferedIOBase, bits: Tuple[Union[bool, int], if _USE_NUMPY: - def _np_read_bool_byte(stream: io.BufferedIOBase) -> List[bool]: + def _np_read_bool_byte(stream: io.BufferedIOBase) -> NDArray[numpy.uint8]: """ Read a single byte from the stream, and interpret its bits as a list of 8 booleans. @@ -198,13 +199,13 @@ if _USE_NUMPY: InvalidDataError if didn't receive 8 bits. """ if len(bits) != 8: - raise InvalidDataError('write_bool_byte received {} bits, requires 8'.format(len(bits))) + raise InvalidDataError(f'write_bool_byte received {len(bits)} bits, requires 8') return stream.write(numpy.packbits(bits)[0]) - read_bool_byte = _np_read_bool_byte + read_bool_byte = _np_read_bool_byte # type: ignore write_bool_byte = _np_write_bool_byte else: - read_bool_byte = _py_read_bool_byte + read_bool_byte = _py_read_bool_byte # type: ignore write_bool_byte = _py_write_bool_byte def read_uint(stream: io.BufferedIOBase) -> int: @@ -249,7 +250,7 @@ def write_uint(stream: io.BufferedIOBase, n: int) -> int: SignedError: if `n` is negative. """ if n < 0: - raise SignedError('uint must be positive: {}'.format(n)) + raise SignedError(f'uint must be positive: {n}') current = n byte_list = [] @@ -392,7 +393,7 @@ def write_ratio(stream: io.BufferedIOBase, r: Fraction) -> int: SignedError: if r is negative. """ if r < 0: - raise SignedError('Ratio must be unsigned: {}'.format(r)) + raise SignedError(f'Ratio must be unsigned: {r}') size = write_uint(stream, r.numerator) size += write_uint(stream, r.denominator) return size @@ -456,7 +457,7 @@ def write_float64(stream: io.BufferedIOBase, f: float) -> int: return stream.write(b) -def read_real(stream: io.BufferedIOBase, real_type: int = None) -> real_t: +def read_real(stream: io.BufferedIOBase, real_type: Optional[int] = None) -> real_t: """ Read a real number from the stream. @@ -503,13 +504,14 @@ def read_real(stream: io.BufferedIOBase, real_type: int = None) -> real_t: return read_float32(stream) if real_type == 7: return read_float64(stream) - raise InvalidDataError('Invalid real type: {}'.format(real_type)) + raise InvalidDataError(f'Invalid real type: {real_type}') -def write_real(stream: io.BufferedIOBase, - r: real_t, - force_float32: bool = False - ) -> int: +def write_real( + stream: io.BufferedIOBase, + r: real_t, + force_float32: bool = False + ) -> int: """ Write a real number to the stream. See read_real() for format details. @@ -561,7 +563,7 @@ class NString: """ _string: str - def __init__(self, string_or_bytes: Union[bytes, str]): + def __init__(self, string_or_bytes: Union[bytes, str]) -> None: """ Args: string_or_bytes: Content of the `NString`. @@ -576,9 +578,9 @@ class NString: return self._string @string.setter - def string(self, string: str): + def string(self, string: str) -> None: if len(string) == 0 or not all(0x21 <= ord(c) <= 0x7e for c in string): - raise InvalidDataError('Invalid n-string {}'.format(string)) + raise InvalidDataError(f'Invalid n-string {string}') self._string = string @property @@ -586,9 +588,9 @@ class NString: return self._string.encode('ascii') @bytes.setter - def bytes(self, bstring: bytes): + def bytes(self, bstring: bytes) -> None: if len(bstring) == 0 or not all(0x21 <= c <= 0x7e for c in bstring): - raise InvalidDataError('Invalid n-string {!r}'.format(bstring)) + raise InvalidDataError(f'Invalid n-string {bstring!r}') self._string = bstring.decode('ascii') @staticmethod @@ -675,7 +677,7 @@ class AString: """ _string: str - def __init__(self, string_or_bytes: Union[bytes, str]): + def __init__(self, string_or_bytes: Union[bytes, str]) -> None: """ Args: string_or_bytes: Content of the AString. @@ -690,9 +692,9 @@ class AString: return self._string @string.setter - def string(self, string: str): + def string(self, string: str) -> None: if not all(0x20 <= ord(c) <= 0x7e for c in string): - raise InvalidDataError('Invalid a-string {}'.format(string)) + raise InvalidDataError(f'Invalid a-string "{string}"') self._string = string @property @@ -700,9 +702,9 @@ class AString: return self._string.encode('ascii') @bytes.setter - def bytes(self, bstring: bytes): + def bytes(self, bstring: bytes) -> None: if not all(0x20 <= c <= 0x7e for c in bstring): - raise InvalidDataError('Invalid a-string {!r}'.format(bstring)) + raise InvalidDataError(f'Invalid a-string "{bstring!r}"') self._string = bstring.decode('ascii') @staticmethod @@ -786,10 +788,10 @@ class ManhattanDelta: vertical (bool): `True` if aligned along y-axis value (int): signed length of the vector """ - vertical = None # type: bool - value = None # type: int + vertical: bool + value: int - def __init__(self, x: int, y: int): + def __init__(self, x: int, y: int) -> None: """ One of `x` or `y` _must_ be zero! @@ -801,7 +803,7 @@ class ManhattanDelta: y = int(y) if x != 0: if y != 0: - raise InvalidDataError('Non-Manhattan ManhattanDelta ({}, {})'.format(x, y)) + raise InvalidDataError(f'Non-Manhattan ManhattanDelta ({x}, {y})') self.vertical = False self.value = x else: @@ -884,7 +886,7 @@ class ManhattanDelta: return hasattr(other, 'as_list') and self.as_list() == other.as_list() def __repr__(self) -> str: - return '{}'.format(self.as_list()) + return str(self.as_list()) class OctangularDelta: @@ -910,7 +912,7 @@ class OctangularDelta: proj_mag: int octangle: int - def __init__(self, x: int, y: int): + def __init__(self, x: int, y: int) -> None: """ Either `abs(x)==abs(y)`, `x==0`, or `y==0` _must_ be true! @@ -932,7 +934,7 @@ class OctangularDelta: self.proj_mag = abs(x) self.octangle = (1 << 2) | (yn << 1) | (xn != yn) else: - raise InvalidDataError('Non-octangular delta! ({}, {})'.format(x, y)) + raise InvalidDataError(f'Non-octangular delta! ({x}, {y})') def as_list(self) -> List[int]: """ @@ -1020,7 +1022,7 @@ class OctangularDelta: return hasattr(other, 'as_list') and self.as_list() == other.as_list() def __repr__(self) -> str: - return '{}'.format(self.as_list()) + return str(self.as_list()) class Delta: @@ -1034,7 +1036,7 @@ class Delta: x: int y: int - def __init__(self, x: int, y: int): + def __init__(self, x: int, y: int) -> None: """ Args: x: x-displacement @@ -1104,7 +1106,7 @@ class Delta: return hasattr(other, 'as_list') and self.as_list() == other.as_list() def __repr__(self) -> str: - return '{}'.format(self.as_list()) + return str(self.as_list()) def read_repetition(stream: io.BufferedIOBase) -> repetition_t: @@ -1128,7 +1130,7 @@ def read_repetition(stream: io.BufferedIOBase) -> repetition_t: elif rtype in (4, 5, 6, 7, 10, 11): return ArbitraryRepetition.read(stream, rtype) else: - raise InvalidDataError('Unexpected repetition type: {}'.format(rtype)) + raise InvalidDataError(f'Unexpected repetition type: {rtype}') def write_repetition(stream: io.BufferedIOBase, repetition: repetition_t) -> int: @@ -1186,11 +1188,12 @@ class GridRepetition: a_count: int b_count: Optional[int] = None - def __init__(self, - a_vector: List[int], - a_count: int, - b_vector: Optional[List[int]] = None, - b_count: Optional[int] = None): + def __init__( + self, + a_vector: Sequence[int], + a_count: int, + b_vector: Optional[Sequence[int]] = None, + b_count: Optional[int] = None): """ Args: a_vector: First lattice vector, of the form `[x, y]`. @@ -1219,10 +1222,10 @@ class GridRepetition: warnings.warn('Removed b_count and b_vector since b_count == 1') if a_count < 2: - raise InvalidDataError('Repetition has too-small a_count: ' - '{}'.format(a_count)) - self.a_vector = a_vector - self.b_vector = b_vector + raise InvalidDataError(f'Repetition has too-small a_count: {a_count}') + + self.a_vector = list(a_vector) + self.b_vector = list(b_vector) if b_vector is not None else None self.a_count = a_count self.b_count = b_count @@ -1270,8 +1273,7 @@ class GridRepetition: a_vector = Delta.read(stream).as_list() b_vector = None else: - raise InvalidDataError('Invalid type for grid repetition ' - '{}'.format(repetition_type)) + raise InvalidDataError(f'Invalid type for grid repetition {repetition_type}') return GridRepetition(a_vector, na, b_vector, nb) def write(self, stream: io.BufferedIOBase) -> int: @@ -1292,7 +1294,7 @@ class GridRepetition: """ if self.b_vector is None or self.b_count is None: if self.b_vector is not None or self.b_count is not None: - raise InvalidDataError('Malformed repetition {}'.format(self)) + raise InvalidDataError(f'Malformed repetition {self}') if self.a_vector[1] == 0: size = write_uint(stream, 2) @@ -1343,8 +1345,7 @@ class GridRepetition: return True def __repr__(self) -> str: - return 'GridRepetition: ({} : {} | {} : {})'.format(self.a_count, self.a_vector, - self.b_count, self.b_vector) + return f'GridRepetition: ({self.a_count} : {self.a_vector} | {self.b_count} : {self.b_vector})' class ArbitraryRepetition: @@ -1360,16 +1361,18 @@ class ArbitraryRepetition: x_displacements: List[int] y_displacements: List[int] - def __init__(self, - x_displacements: List[int], - y_displacements: List[int]): + def __init__( + self, + x_displacements: Sequence[int], + y_displacements: Sequence[int], + ) -> None: """ Args: x_displacements: x-displacements between consecutive elements y_displacements: y-displacements between consecutive elements """ - self.x_displacements = x_displacements - self.y_displacements = y_displacements + self.x_displacements = list(x_displacements) + self.y_displacements = list(y_displacements) @staticmethod def read(stream: io.BufferedIOBase, repetition_type: int) -> 'ArbitraryRepetition': @@ -1423,7 +1426,7 @@ class ArbitraryRepetition: x_displacements.append(x * mult) y_displacements.append(y * mult) else: - raise InvalidDataError('Invalid ArbitraryRepetition repetition_type: {}'.format(repetition_type)) + raise InvalidDataError(f'Invalid ArbitraryRepetition repetition_type: {repetition_type}') return ArbitraryRepetition(x_displacements, y_displacements) def write(self, stream: io.BufferedIOBase) -> int: @@ -1497,12 +1500,13 @@ class ArbitraryRepetition: and self.y_displacements == other.y_displacements) def __repr__(self) -> str: - return 'ArbitraryRepetition: x{} y{})'.format(self.x_displacements, self.y_displacements) + return f'ArbitraryRepetition: x{self.x_displacements} y{self.y_displacements})' -def read_point_list(stream: io.BufferedIOBase, - implicit_closed: bool, - ) -> List[List[int]]: +def read_point_list( + stream: io.BufferedIOBase, + implicit_closed: bool, + ) -> List[List[int]]: """ Read a point list from a stream. @@ -1583,16 +1587,17 @@ def read_point_list(stream: io.BufferedIOBase, if _USE_NUMPY: points = numpy.vstack((points, close_points)) else: - points.append(close_points) + points += close_points return points -def write_point_list(stream: io.BufferedIOBase, - points: List[Sequence[int]], - fast: bool = False, - implicit_closed: bool = True - ) -> int: +def write_point_list( + stream: io.BufferedIOBase, + points: List[Sequence[int]], + fast: bool = False, + implicit_closed: bool = True + ) -> int: """ Write a point list to a stream. @@ -1689,19 +1694,19 @@ def write_point_list(stream: io.BufferedIOBase, deltas = [Delta(*points[0])] + [Delta(x, y) for x, y in diff] else: previous = [0, 0] - diff = [] + diffl = [] for point in points: d = [point[0] - previous[0], point[1] - previous[1]] previous = point - diff.append(d) + diffl.append(d) - if sum(sum(p) for p in points) < sum(sum(d) for d in diff) * decision_factor: + if sum(sum(p) for p in points) < sum(sum(d) for d in diffl) * decision_factor: list_type = 4 deltas = [Delta(x, y) for x, y in points] else: list_type = 5 - deltas = [Delta(x, y) for x, y in diff] + deltas = [Delta(x, y) for x, y in diffl] size = write_uint(stream, list_type) size += write_uint(stream, len(points)) @@ -1720,7 +1725,7 @@ class PropStringReference: ref: int reference_type: Type - def __init__(self, ref: int, ref_type: Type): + def __init__(self, ref: int, ref_type: Type) -> None: """ :param ref: ID number of the target. :param ref_type: Type of the target. One of bytes, NString, AString. @@ -1732,7 +1737,7 @@ class PropStringReference: return isinstance(other, type(self)) and self.ref == other.ref and self.reference_type == other.reference_type def __repr__(self) -> str: - return '[{} : {}]'.format(self.ref_type, self.ref) + return f'[{self.ref_type} : {self.ref}]' def read_property_value(stream: io.BufferedIOBase) -> property_value_t: @@ -1789,15 +1794,16 @@ def read_property_value(stream: io.BufferedIOBase) -> property_value_t: ref = read_uint(stream) return PropStringReference(ref, ref_type) else: - raise InvalidDataError('Invalid property type: {}'.format(prop_type)) + raise InvalidDataError(f'Invalid property type: {prop_type}') -def write_property_value(stream: io.BufferedIOBase, - value: property_value_t, - force_real: bool = False, - force_signed_int: bool = False, - force_float32: bool = False - ) -> int: +def write_property_value( + stream: io.BufferedIOBase, + value: property_value_t, + force_real: bool = False, + force_signed_int: bool = False, + force_float32: bool = False, + ) -> int: """ Write a property value to a stream. @@ -1844,7 +1850,7 @@ def write_property_value(stream: io.BufferedIOBase, size = write_uint(stream, 15) size += write_uint(stream, value.ref) else: - raise Exception('Invalid property type: {} ({})'.format(type(value), value)) + raise Exception(f'Invalid property type: {type(value)} ({value})') return size @@ -1885,13 +1891,14 @@ def read_interval(stream: io.BufferedIOBase) -> Tuple[Optional[int], Optional[in elif interval_type == 4: return read_uint(stream), read_uint(stream) else: - raise InvalidDataError('Unrecognized interval type: {}'.format(interval_type)) + raise InvalidDataError(f'Unrecognized interval type: {interval_type}') -def write_interval(stream: io.BufferedIOBase, - min_bound: Optional[int] = None, - max_bound: Optional[int] = None - ) -> int: +def write_interval( + stream: io.BufferedIOBase, + min_bound: Optional[int] = None, + max_bound: Optional[int] = None, + ) -> int: """ Write an interval to a stream. Used for layer data; see `read_interval()` for format details. @@ -1942,7 +1949,7 @@ class OffsetEntry: strict: bool = False offset: int = 0 - def __init__(self, strict: bool = False, offset: int = 0): + def __init__(self, strict: bool = False, offset: int = 0) -> None: """ Args: strict: `True` if the records referenced are written in @@ -1983,7 +1990,7 @@ class OffsetEntry: return write_uint(stream, self.strict) + write_uint(stream, self.offset) def __repr__(self) -> str: - return 'Offset(s: {}, o: {})'.format(self.strict, self.offset) + return f'Offset(s: {self.strict}, o: {self.offset})' class OffsetTable: @@ -2015,13 +2022,15 @@ class OffsetTable: layernames: OffsetEntry xnames: OffsetEntry - def __init__(self, - cellnames: Optional[OffsetEntry] = None, - textstrings: Optional[OffsetEntry] = None, - propnames: Optional[OffsetEntry] = None, - propstrings: Optional[OffsetEntry] = None, - layernames: Optional[OffsetEntry] = None, - xnames: Optional[OffsetEntry] = None): + def __init__( + self, + cellnames: Optional[OffsetEntry] = None, + textstrings: Optional[OffsetEntry] = None, + propnames: Optional[OffsetEntry] = None, + propstrings: Optional[OffsetEntry] = None, + layernames: Optional[OffsetEntry] = None, + xnames: Optional[OffsetEntry] = None, + ) -> None: """ All parameters default to a non-strict entry with offset `0`. @@ -2127,7 +2136,7 @@ def write_u32(stream: io.BufferedIOBase, n: int) -> int: SignedError: if `n` is negative. """ if n < 0: - raise SignedError('Negative u32: {}'.format(n)) + raise SignedError(f'Negative u32: {n}') return stream.write(struct.pack(' None: """ Args: checksum_type: 0,1,2 (No checksum, crc32, checksum32) @@ -2207,18 +2216,16 @@ class Validation: if self.checksum_type == 0: return write_uint(stream, 0) elif self.checksum is None: - raise InvalidDataError('Checksum is empty but type is ' - '{}'.format(self.checksum_type)) + raise InvalidDataError(f'Checksum is empty but type is {self.checksum_type}') elif self.checksum_type == 1: return write_uint(stream, 1) + write_u32(stream, self.checksum) elif self.checksum_type == 2: return write_uint(stream, 2) + write_u32(stream, self.checksum) else: - raise InvalidDataError('Unrecognized checksum type: ' - '{}'.format(self.checksum_type)) + raise InvalidDataError(f'Unrecognized checksum type: {self.checksum_type}') def __repr__(self) -> str: - return 'Validation(type: {} sum: {})'.format(self.checksum_type, self.checksum) + return f'Validation(type: {self.checksum_type} sum: {self.checksum})' def write_magic_bytes(stream: io.BufferedIOBase) -> int: @@ -2247,5 +2254,4 @@ def read_magic_bytes(stream: io.BufferedIOBase): """ magic = _read(stream, len(MAGIC_BYTES)) if magic != MAGIC_BYTES: - raise InvalidDataError('Could not read magic bytes, ' - 'found {!r}'.format(magic)) + raise InvalidDataError(f'Could not read magic bytes, found {magic!r}') diff --git a/fatamorgana/main.py b/fatamorgana/main.py index b73d4c2..a11af4e 100644 --- a/fatamorgana/main.py +++ b/fatamorgana/main.py @@ -40,7 +40,7 @@ class FileModals: end_has_offset_table: bool = False started: bool = False - def __init__(self, property_target: List[records.Property]): + def __init__(self, property_target: List[records.Property]) -> None: self.property_target = property_target @@ -89,7 +89,11 @@ class OasisLayout: propstrings: Dict[int, AString] layers: List[records.LayerName] - def __init__(self, unit: real_t, validation: Validation = None): + def __init__( + self, + unit: real_t, + validation: Optional[Validation] = None, + ) -> None: """ Args: unit: Real number (i.e. int, float, or `Fraction`), grid steps per micron. @@ -132,11 +136,12 @@ class OasisLayout: pass return layout - def read_record(self, - stream: io.BufferedIOBase, - modals: Modals, - file_state: FileModals - ) -> bool: + def read_record( + self, + stream: io.BufferedIOBase, + modals: Modals, + file_state: FileModals + ) -> bool: """ Read a single record of unspecified type from a stream, adding its contents into this `OasisLayout` object. @@ -162,7 +167,7 @@ class OasisLayout: else: raise e - logger.info('read_record of type {} at position 0x{:x}'.format(record_id, stream.tell())) + logger.info(f'read_record of type {record_id} at position 0x{stream.tell():x}') record: Record @@ -182,7 +187,7 @@ class OasisLayout: # Make sure order is valid (eg, no out-of-cell geometry) if not file_state.started and record_id != 1: - raise InvalidRecordError('Non-Start record {} before Start'.format(record_id)) + raise InvalidRecordError(f'Non-Start record {record_id} before Start') if record_id == 1: if file_state.started: raise InvalidRecordError('Duplicate Start record') @@ -201,7 +206,7 @@ class OasisLayout: elif record_id in (13, 14): file_state.within_cell = True else: - raise InvalidRecordError('Unknown record id: {}'.format(record_id)) + raise InvalidRecordError(f'Unknown record id: {record_id}') if record_id == 0: ''' Pad ''' @@ -335,7 +340,7 @@ class OasisLayout: self.cells[-1].geometry.append(record) file_state.property_target = record.properties else: - raise InvalidRecordError('Unknown record id: {}'.format(record_id)) + raise InvalidRecordError(f'Unknown record id: {record_id}') return False def write(self, stream: io.BufferedIOBase) -> int: @@ -412,13 +417,14 @@ class Cell: placements: List[records.Placement] geometry: List[records.geometry_t] - def __init__(self, - name: Union[NString, str, int], - *, - properties: Optional[List[records.Property]] = None, - placements: Optional[List[records.Placement]] = None, - geometry: Optional[List[records.geometry_t]] = None, - ): + def __init__( + self, + name: Union[NString, str, int], + *, + properties: Optional[List[records.Property]] = None, + placements: Optional[List[records.Placement]] = None, + geometry: Optional[List[records.geometry_t]] = None, + ) -> None: self.name = name if isinstance(name, (NString, int)) else NString(name) self.properties = [] if properties is None else properties self.placements = [] if placements is None else placements @@ -460,9 +466,11 @@ class CellName: nstring: NString properties: List[records.Property] - def __init__(self, - nstring: Union[NString, str], - properties: Optional[List[records.Property]] = None): + def __init__( + self, + nstring: Union[NString, str], + properties: Optional[List[records.Property]] = None, + ) -> None: """ Args: nstring: The contained string. @@ -499,7 +507,7 @@ class XName: attribute: int bstring: bytes - def __init__(self, attribute: int, bstring: bytes): + def __init__(self, attribute: int, bstring: bytes) -> None: """ Args: attribute: Attribute number. diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 19d50f1..453ad03 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -29,7 +29,7 @@ from .basic import ( ) if _USE_NUMPY: - import numpy # type: ignore + import numpy logger = logging.getLogger(__name__) @@ -76,10 +76,10 @@ class Modals: property_name: Union[int, NString, None] = None property_is_standard: Optional[bool] = None - def __init__(self): + def __init__(self) -> None: self.reset() - def reset(self): + def reset(self) -> None: """ Resets all modal variables to their default values. Default values are: @@ -133,7 +133,7 @@ class Record(metaclass=ABCMeta): Common interface for records. """ @abstractmethod - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: """ Copy all defined values from this record into the modal variables. Fill all undefined values in this record from the modal variables. @@ -144,7 +144,7 @@ class Record(metaclass=ABCMeta): pass @abstractmethod - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: """ Check all defined values in this record against those in the modal variables. If any values are equal, remove them from @@ -224,7 +224,7 @@ class Record(metaclass=ABCMeta): return copy.deepcopy(self) def __repr__(self) -> str: - return '{}: {}'.format(self.__class__, pprint.pformat(self.__dict__)) + return f'{self.__class__}: ' + pprint.pformat(self.__dict__) class GeometryMixin(metaclass=ABCMeta): @@ -255,10 +255,11 @@ class GeometryMixin(metaclass=ABCMeta): return (self.get_layer(), self.get_datatype()) -def read_refname(stream: io.BufferedIOBase, - is_present: Union[bool, int], - is_reference: Union[bool, int] - ) -> Union[None, int, NString]: +def read_refname( + stream: io.BufferedIOBase, + is_present: Union[bool, int], + is_reference: Union[bool, int] + ) -> Union[None, int, NString]: """ Helper function for reading a possibly-absent, possibly-referenced NString. @@ -279,10 +280,11 @@ def read_refname(stream: io.BufferedIOBase, return NString.read(stream) -def read_refstring(stream: io.BufferedIOBase, - is_present: Union[bool, int], - is_reference: Union[bool, int], - ) -> Union[None, int, AString]: +def read_refstring( + stream: io.BufferedIOBase, + is_present: Union[bool, int], + is_reference: Union[bool, int], + ) -> Union[None, int, AString]: """ Helper function for reading a possibly-absent, possibly-referenced `AString`. @@ -307,19 +309,18 @@ class Pad(Record): """ Pad record (ID 0) """ - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: pass - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: pass @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Pad': if record_id != 0: - raise InvalidDataError('Invalid record id for Pad ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Pad {record_id}') record = Pad() - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -329,31 +330,28 @@ class Pad(Record): class XYMode(Record): """ XYMode record (ID 15, 16) - - Attributes: - relative (bool): default `False` """ - relative: bool = False + relative: bool @property def absolute(self) -> bool: return not self.relative @absolute.setter - def absolute(self, b: bool): + def absolute(self, b: bool) -> None: self.relative = not b - def __init__(self, relative: bool): + def __init__(self, relative: bool) -> None: """ Args: relative: `True` if the mode is 'relative', `False` if 'absolute'. """ self.relative = relative - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.xy_relative = self.relative - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: pass @staticmethod @@ -361,7 +359,7 @@ class XYMode(Record): if record_id not in (15, 16): raise InvalidDataError('Invalid record id for XYMode') record = XYMode(record_id == 16) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -373,19 +371,21 @@ class Start(Record): Start Record (ID 1) Attributes: - version (AString): "1.0" + version (AString): unit (real_t): positive real number, grid steps per micron offset_table (Optional[OffsetTable]): If `None` then table must be placed in the `End` record) """ version: AString unit: real_t - offset_table: Optional[OffsetTable] = None + offset_table: Optional[OffsetTable] - def __init__(self, - unit: real_t, - version: Union[AString, str] = None, - offset_table: Optional[OffsetTable] = None): + def __init__( + self, + unit: real_t, + version: Union[AString, str] = "1.0", + offset_table: Optional[OffsetTable] = None, + ) -> None: """ Args unit: Grid steps per micron (positive real number) @@ -394,37 +394,32 @@ class Start(Record): it in the `End` record instead. """ if unit <= 0: - raise InvalidDataError('Non-positive unit: {}'.format(unit)) + raise InvalidDataError(f'Non-positive unit: {unit}') if math.isnan(unit): raise InvalidDataError('NaN unit') if math.isinf(unit): raise InvalidDataError('Non-finite unit') self.unit = unit - if version is None: - version = AString('1.0') if isinstance(version, AString): self.version = version else: self.version = AString(version) if self.version.string != '1.0': - raise InvalidDataError('Invalid version string, ' - 'only "1.0" is allowed: ' - + str(self.version.string)) + raise InvalidDataError(f'Invalid version string, only "1.0" is allowed: "{self.version.string}"') self.offset_table = offset_table - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Start': if record_id != 1: - raise InvalidDataError('Invalid record id for Start: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Start: {record_id}') version = AString.read(stream) unit = read_real(stream) has_offset_table = read_uint(stream) == 0 @@ -434,7 +429,7 @@ class Start(Record): else: offset_table = None record = Start(unit, version, offset_table) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -458,12 +453,14 @@ class End(Record): written into the `Start` record instead validation (Validation): object containing checksum """ - offset_table: Optional[OffsetTable] = None + offset_table: Optional[OffsetTable] validation: Validation - def __init__(self, - validation: Validation, - offset_table: Optional[OffsetTable] = None): + def __init__( + self, + validation: Validation, + offset_table: Optional[OffsetTable] = None, + ) -> None: """ Args: validation: `Validation` object for this file. @@ -480,12 +477,13 @@ class End(Record): pass @staticmethod - def read(stream: io.BufferedIOBase, - record_id: int, - has_offset_table: bool - ) -> 'End': + def read( + stream: io.BufferedIOBase, + record_id: int, + has_offset_table: bool + ) -> 'End': if record_id != 2: - raise InvalidDataError('Invalid record id for End {}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for End {record_id}') if has_offset_table: offset_table: Optional[OffsetTable] = OffsetTable.read(stream) else: @@ -493,7 +491,7 @@ class End(Record): _padding_string = read_bstring(stream) # noqa validation = Validation.read(stream) record = End(validation, offset_table) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -526,10 +524,12 @@ class CBlock(Record): decompressed_byte_count: int compressed_bytes: bytes - def __init__(self, - compression_type: int, - decompressed_byte_count: int, - compressed_bytes: bytes): + def __init__( + self, + compression_type: int, + decompressed_byte_count: int, + compressed_bytes: bytes, + ) -> None: """ Args: compression_type: `0` (zlib) @@ -537,29 +537,27 @@ class CBlock(Record): compressed_bytes: The compressed data. """ if compression_type != 0: - raise InvalidDataError('CBlock: Invalid compression scheme ' - '{}'.format(compression_type)) + raise InvalidDataError(f'CBlock: Invalid compression scheme {compression_type}') self.compression_type = compression_type self.decompressed_byte_count = decompressed_byte_count self.compressed_bytes = compressed_bytes - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: pass - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: pass @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'CBlock': if record_id != 34: - raise InvalidDataError('Invalid record id for CBlock: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for CBlock: {record_id}') compression_type = read_uint(stream) decompressed_count = read_uint(stream) compressed_bytes = read_bstring(stream) record = CBlock(compression_type, decompressed_count, compressed_bytes) - logger.debug('CBlock ending at 0x{:x} was read successfully'.format(stream.tell())) + logger.debug(f'CBlock ending at 0x{stream.tell():x} was read successfully') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -570,10 +568,11 @@ class CBlock(Record): return size @staticmethod - def from_decompressed(decompressed_bytes: bytes, - compression_type: int = 0, - compression_args: Dict = None - ) -> 'CBlock': + def from_decompressed( + decompressed_bytes: bytes, + compression_type: int = 0, + compression_args: Optional[Dict[str, Any]] = None, + ) -> 'CBlock': """ Create a CBlock record from uncompressed data. @@ -597,12 +596,11 @@ class CBlock(Record): compressed_bytes = (compressor.compress(decompressed_bytes) + compressor.flush()) else: - raise InvalidDataError('Unknown compression type: ' - '{}'.format(compression_type)) + raise InvalidDataError(f'Unknown compression type: {compression_type}') return CBlock(compression_type, count, compressed_bytes) - def decompress(self, decompression_args: Dict = None) -> bytes: + def decompress(self, decompression_args: Optional[Dict[str, Any]] = None) -> bytes: """ Decompress the contents of this CBlock. @@ -625,8 +623,7 @@ class CBlock(Record): if len(decompressed_bytes) != self.decompressed_byte_count: raise InvalidDataError('Decompressed data length does not match!') else: - raise InvalidDataError('Unknown compression type: ' - '{}'.format(self.compression_type)) + raise InvalidDataError(f'Unknown compression type: {self.compression_type}') return decompressed_bytes @@ -639,11 +636,13 @@ class CellName(Record): reference_number (Optional[int]): `None` results in implicit assignment """ nstring: NString - reference_number: Optional[int] = None + reference_number: Optional[int] - def __init__(self, - nstring: Union[NString, str], - reference_number: int = None): + def __init__( + self, + nstring: Union[NString, str], + reference_number: Optional[int] = None, + ) -> None: """ Args: nstring: The contained string. @@ -656,24 +655,23 @@ class CellName(Record): self.nstring = NString(nstring) self.reference_number = reference_number - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'CellName': if record_id not in (3, 4): - raise InvalidDataError('Invalid record id for CellName ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for CellName {record_id}') nstring = NString.read(stream) if record_id == 4: reference_number: Optional[int] = read_uint(stream) else: reference_number = None record = CellName(nstring, reference_number) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -695,9 +693,11 @@ class PropName(Record): nstring: NString reference_number: Optional[int] = None - def __init__(self, - nstring: Union[NString, str], - reference_number: int = None): + def __init__( + self, + nstring: Union[NString, str], + reference_number: Optional[int] = None, + ) -> None: """ Args: nstring: The contained string. @@ -719,15 +719,14 @@ class PropName(Record): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'PropName': if record_id not in (7, 8): - raise InvalidDataError('Invalid record id for PropName ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for PropName {record_id}') nstring = NString.read(stream) if record_id == 8: reference_number: Optional[int] = read_uint(stream) else: reference_number = None record = PropName(nstring, reference_number) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -750,9 +749,11 @@ class TextString(Record): astring: AString reference_number: Optional[int] = None - def __init__(self, - string: Union[AString, str], - reference_number: int = None): + def __init__( + self, + string: Union[AString, str], + reference_number: Optional[int] = None, + ) -> None: """ Args: string: The contained string. @@ -765,24 +766,23 @@ class TextString(Record): self.astring = AString(string) self.reference_number = reference_number - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'TextString': if record_id not in (5, 6): - raise InvalidDataError('Invalid record id for TextString: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for TextString: {record_id}') astring = AString.read(stream) if record_id == 6: reference_number: Optional[int] = read_uint(stream) else: reference_number = None record = TextString(astring, reference_number) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -803,11 +803,13 @@ class PropString(Record): reference_number (Optional[int]): `None` results in implicit assignment """ astring: AString - reference_number: Optional[int] = None + reference_number: Optional[int] - def __init__(self, - string: Union[AString, str], - reference_number: int = None): + def __init__( + self, + string: Union[AString, str], + reference_number: Optional[int] = None, + ) -> None: """ Args: string: The contained string. @@ -820,24 +822,23 @@ class PropString(Record): self.astring = AString(string) self.reference_number = reference_number - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'PropString': if record_id not in (9, 10): - raise InvalidDataError('Invalid record id for PropString: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for PropString: {record_id}') astring = AString.read(stream) if record_id == 10: reference_number: Optional[int] = read_uint(stream) else: reference_number = None record = PropString(astring, reference_number) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -860,15 +861,17 @@ class LayerName(Record): is_textlayer (bool): Is this a text layer? """ nstring: NString - layer_interval: Tuple - type_interval: Tuple + layer_interval: Tuple[Optional[int], Optional[int]] + type_interval: Tuple[Optional[int], Optional[int]] is_textlayer: bool - def __init__(self, - nstring: Union[NString, str], - layer_interval: Tuple, - type_interval: Tuple, - is_textlayer: bool): + def __init__( + self, + nstring: Union[NString, str], + layer_interval: Tuple[Optional[int], Optional[int]], + type_interval: Tuple[Optional[int], Optional[int]], + is_textlayer: bool, + ) -> None: """ Args: nstring: The layer name. @@ -886,23 +889,22 @@ class LayerName(Record): self.type_interval = type_interval self.is_textlayer = is_textlayer - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'LayerName': if record_id not in (11, 12): - raise InvalidDataError('Invalid record id for LayerName: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for LayerName: {record_id}') is_textlayer = (record_id == 12) nstring = NString.read(stream) layer_interval = read_interval(stream) type_interval = read_interval(stream) record = LayerName(nstring, layer_interval, type_interval, is_textlayer) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -924,14 +926,16 @@ class Property(Record): values (Optional[List[property_value_t]]): List of property values. is_standard (bool): Whether this is a standard property. """ - name: Optional[Union[NString, int]] = None - values: Optional[List[property_value_t]] = None - is_standard: Optional[bool] = None + name: Optional[Union[NString, int]] + values: Optional[List[property_value_t]] + is_standard: Optional[bool] - def __init__(self, - name: Union[NString, str, int, None] = None, - values: Optional[List[property_value_t]] = None, - is_standard: Optional[bool] = None): + def __init__( + self, + name: Union[NString, str, int, None] = None, + values: Optional[List[property_value_t]] = None, + is_standard: Optional[bool] = None, + ) -> None: """ Args: name: Property name, reference number, or `None` (i.e. use modal) @@ -957,12 +961,12 @@ class Property(Record): def get_is_standard(self) -> bool: return verify_modal(self.is_standard) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_field(self, 'name', modals, 'property_name') adjust_field(self, 'values', modals, 'property_value_list') adjust_field(self, 'is_standard', modals, 'property_is_standard') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_field(self, 'name', modals, 'property_name') dedup_field(self, 'values', modals, 'property_value_list') if self.values is None and self.name is None: @@ -971,8 +975,7 @@ class Property(Record): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Property': if record_id not in (28, 29): - raise InvalidDataError('Invalid record id for PropertyValue: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for PropertyValue: {record_id}') if record_id == 29: record = Property() else: @@ -997,7 +1000,7 @@ class Property(Record): # logger.warning('Malformed property record header; requested modal' # ' values but had nonzero count. Ignoring count.') record = Property(name, values, bool(s)) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1005,8 +1008,7 @@ class Property(Record): return write_uint(stream, 29) else: if self.is_standard is None: - raise InvalidDataError('Property has value or name, ' - 'but no is_standard flag!') + raise InvalidDataError('Property has value or name, but no is_standard flag!') if self.values is not None: value_count = len(self.values) v = 0 @@ -1047,12 +1049,14 @@ class XName(Record): """ attribute: int bstring: bytes - reference_number: Optional[int] = None + reference_number: Optional[int] - def __init__(self, - attribute: int, - bstring: bytes, - reference_number: int = None): + def __init__( + self, + attribute: int, + bstring: bytes, + reference_number: Optional[int] = None, + ) -> None: """ Args: attribute: Attribute number. @@ -1064,17 +1068,16 @@ class XName(Record): self.bstring = bstring self.reference_number = reference_number - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'XName': if record_id not in (30, 31): - raise InvalidDataError('Invalid record id for XName: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for XName: {record_id}') attribute = read_uint(stream) bstring = read_bstring(stream) if record_id == 31: @@ -1082,7 +1085,7 @@ class XName(Record): else: reference_number = None record = XName(attribute, bstring, reference_number) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1107,10 +1110,12 @@ class XElement(Record): bstring: bytes properties: List['Property'] - def __init__(self, - attribute: int, - bstring: bytes, - properties: Optional[List['Property']] = None): + def __init__( + self, + attribute: int, + bstring: bytes, + properties: Optional[List['Property']] = None, + ) -> None: """ Args: attribute: Attribute number. @@ -1121,21 +1126,20 @@ class XElement(Record): self.bstring = bstring self.properties = [] if properties is None else properties - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: pass - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: pass @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'XElement': if record_id != 32: - raise InvalidDataError('Invalid record id for XElement: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for XElement: {record_id}') attribute = read_uint(stream) bstring = read_bstring(stream) record = XElement(attribute, bstring) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1168,15 +1172,17 @@ class XGeometry(Record, GeometryMixin): repetition: Optional[repetition_t] = None properties: List['Property'] - def __init__(self, - attribute: int, - bstring: bytes, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + attribute: int, + bstring: bytes, + layer: Optional[int] = None, + datatype: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Args: attribute: Attribute number for this XGeometry. @@ -1197,13 +1203,13 @@ class XGeometry(Record, GeometryMixin): self.repetition = repetition self.properties = [] if properties is None else properties - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') adjust_field(self, 'datatype', modals, 'datatype') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -1212,8 +1218,7 @@ class XGeometry(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'XGeometry': if record_id != 33: - raise InvalidDataError('Invalid record id for XGeometry: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for XGeometry: {record_id}') z0, z1, z2, x, y, r, d, l = read_bool_byte(stream) if z0 or z1 or z2: @@ -1233,7 +1238,7 @@ class XGeometry(Record, GeometryMixin): optional['repetition'] = read_repetition(stream) record = XGeometry(attribute, bstring, **optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1269,17 +1274,17 @@ class Cell(Record): """ name: Union[int, NString] - def __init__(self, name: Union[int, str, NString]): + def __init__(self, name: Union[int, str, NString]) -> None: """ Args: name: `NString`, or an int specifying a `CellName` reference number. """ self.name = name if isinstance(name, (int, NString)) else NString(name) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod @@ -1290,10 +1295,9 @@ class Cell(Record): elif record_id == 14: name = NString.read(stream) else: - raise InvalidDataError('Invalid record id for Cell: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Cell: {record_id}') record = Cell(name) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1331,15 +1335,17 @@ class Placement(Record): flip: bool properties: List['Property'] - def __init__(self, - flip: bool, - name: Union[NString, str, int, None] = None, - magnification: Optional[real_t] = None, - angle: Optional[real_t] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + flip: bool, + name: Union[NString, str, int, None] = None, + magnification: Optional[real_t] = None, + angle: Optional[real_t] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Args: flip: Whether to perform reflection about the x-axis. @@ -1374,12 +1380,12 @@ class Placement(Record): def get_y(self) -> int: return verify_modal(self.y) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'placement_x', 'placement_y') adjust_repetition(self, modals) adjust_field(self, 'name', modals, 'placement_cell') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'placement_x', 'placement_y') dedup_repetition(self, modals) dedup_field(self, 'name', modals, 'placement_cell') @@ -1387,8 +1393,7 @@ class Placement(Record): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Placement': if record_id not in (17, 18): - raise InvalidDataError('Invalid record id for Placement: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Placement: {record_id}') #CNXYRAAF (17) or CNXYRMAF (18) c, n, x, y, r, ma0, ma1, flip = read_bool_byte(stream) @@ -1413,7 +1418,7 @@ class Placement(Record): optional['repetition'] = read_repetition(stream) record = Placement(flip, name, **optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1479,14 +1484,16 @@ class Text(Record, GeometryMixin): repetition: Optional[repetition_t] = None properties: List['Property'] - def __init__(self, - string: Union[AString, str, int, None] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + string: Union[AString, str, int, None] = None, + layer: Optional[int] = None, + datatype: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Args: string: Text content, or `TextString` reference number. @@ -1512,14 +1519,14 @@ class Text(Record, GeometryMixin): def get_string(self) -> Union[AString, int]: return verify_modal(self.string) # type: ignore - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'text_x', 'text_y') adjust_repetition(self, modals) adjust_field(self, 'string', modals, 'text_string') adjust_field(self, 'layer', modals, 'text_layer') adjust_field(self, 'datatype', modals, 'text_datatype') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'text_x', 'text_y') dedup_repetition(self, modals) dedup_field(self, 'string', modals, 'text_string') @@ -1529,8 +1536,7 @@ class Text(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Text': if record_id != 19: - raise InvalidDataError('Invalid record id for Text: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Text: {record_id}') z0, c, n, x, y, r, d, l = read_bool_byte(stream) if z0: @@ -1550,7 +1556,7 @@ class Text(Record, GeometryMixin): optional['repetition'] = read_repetition(stream) record = Text(string, **optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1613,16 +1619,18 @@ class Rectangle(Record, GeometryMixin): is_square: bool = False properties: List['Property'] - def __init__(self, - is_square: bool = False, - layer: Optional[int] = None, - datatype: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + is_square: bool = False, + layer: Optional[int] = None, + datatype: Optional[int] = None, + width: Optional[int] = None, + height: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: self.is_square = is_square self.layer = layer self.datatype = datatype @@ -1643,7 +1651,7 @@ class Rectangle(Record, GeometryMixin): return verify_modal(self.width) return verify_modal(self.height) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') @@ -1654,7 +1662,7 @@ class Rectangle(Record, GeometryMixin): else: adjust_field(self, 'height', modals, 'geometry_h') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -1668,8 +1676,7 @@ class Rectangle(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Rectangle': if record_id != 20: - raise InvalidDataError('Invalid record id for Rectangle: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Rectangle: {record_id}') is_square, w, h, x, y, r, d, l = read_bool_byte(stream) optional: Dict[str, Any] = {} @@ -1688,7 +1695,7 @@ class Rectangle(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = Rectangle(is_square, **optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1750,14 +1757,16 @@ class Polygon(Record, GeometryMixin): point_list: Optional[point_list_t] = None properties: List['Property'] - def __init__(self, - point_list: Optional[point_list_t] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + point_list: Optional[point_list_t] = None, + layer: Optional[int] = None, + datatype: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: self.layer = layer self.datatype = datatype self.x = x @@ -1773,14 +1782,14 @@ class Polygon(Record, GeometryMixin): def get_point_list(self) -> point_list_t: return verify_modal(self.point_list) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') adjust_field(self, 'datatype', modals, 'datatype') adjust_field(self, 'point_list', modals, 'polygon_point_list') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -1790,8 +1799,7 @@ class Polygon(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Polygon': if record_id != 21: - raise InvalidDataError('Invalid record id for Polygon: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Polygon: {record_id}') z0, z1, p, x, y, r, d, l = read_bool_byte(stream) if z0 or z1: @@ -1811,7 +1819,7 @@ class Polygon(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = Polygon(**optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug('Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase, fast: bool = False) -> int: @@ -1876,17 +1884,19 @@ class Path(Record, GeometryMixin): extension_end: Optional[pathextension_t] = None properties: List['Property'] - def __init__(self, - point_list: Optional[point_list_t] = None, - half_width: Optional[int] = None, - extension_start: Optional[pathextension_t] = None, - extension_end: Optional[pathextension_t] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + point_list: Optional[point_list_t] = None, + half_width: Optional[int] = None, + extension_start: Optional[pathextension_t] = None, + extension_end: Optional[pathextension_t] = None, + layer: Optional[int] = None, + datatype: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: self.layer = layer self.datatype = datatype self.x = x @@ -1910,7 +1920,7 @@ class Path(Record, GeometryMixin): def get_extension_end(self) -> pathextension_t: return verify_modal(self.extension_end) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') @@ -1920,7 +1930,7 @@ class Path(Record, GeometryMixin): adjust_field(self, 'extension_start', modals, 'path_extension_start') adjust_field(self, 'extension_end', modals, 'path_extension_end') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -1933,8 +1943,7 @@ class Path(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Path': if record_id != 22: - raise InvalidDataError('Invalid record id for Path: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Path: {record_id}') e, w, p, x, y, r, d, l = read_bool_byte(stream) optional: Dict[str, Any] = {} @@ -1959,7 +1968,7 @@ class Path(Record, GeometryMixin): elif ext_scheme == 3: return PathExtensionScheme.Arbitrary, read_sint(stream) else: - raise InvalidDataError('Invalid ext_scheme: {}'.format(ext_scheme)) + raise InvalidDataError(f'Invalid ext_scheme: {ext_scheme}') optional['extension_start'] = get_pathext(scheme_start) optional['extension_end'] = get_pathext(scheme_end) @@ -1972,7 +1981,7 @@ class Path(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = Path(**optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase, fast: bool = False) -> int: @@ -2058,18 +2067,20 @@ class Trapezoid(Record, GeometryMixin): is_vertical: bool properties: List['Property'] - def __init__(self, - is_vertical: bool, - delta_a: int = 0, - delta_b: int = 0, - layer: int = None, - datatype: int = None, - width: int = None, - height: int = None, - x: int = None, - y: int = None, - repetition: repetition_t = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + is_vertical: bool, + delta_a: int = 0, + delta_b: int = 0, + layer: Optional[int] = None, + datatype: Optional[int] = None, + width: Optional[int] = None, + height: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Raises: InvalidDataError: if dimensions are impossible. @@ -2088,12 +2099,10 @@ class Trapezoid(Record, GeometryMixin): if self.is_vertical: if height is not None and delta_b - delta_a > height: - raise InvalidDataError('Trapezoid: h < delta_b - delta_a' - + ' ({} < {} - {})'.format(height, delta_b, delta_a)) + raise InvalidDataError(f'Trapezoid: h < delta_b - delta_a ({height} < {delta_b} - {delta_a})') else: if width is not None and delta_b - delta_a > width: - raise InvalidDataError('Trapezoid: w < delta_b - delta_a' - + ' ({} < {} - {})'.format(width, delta_b, delta_a)) + raise InvalidDataError(f'Trapezoid: w < delta_b - delta_a ({width} < {delta_b} - {delta_a})') def get_is_vertical(self) -> bool: return verify_modal(self.is_vertical) @@ -2110,7 +2119,7 @@ class Trapezoid(Record, GeometryMixin): def get_height(self) -> int: return verify_modal(self.height) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') @@ -2118,7 +2127,7 @@ class Trapezoid(Record, GeometryMixin): adjust_field(self, 'width', modals, 'geometry_w') adjust_field(self, 'height', modals, 'geometry_h') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -2129,8 +2138,7 @@ class Trapezoid(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Trapezoid': if record_id not in (23, 24, 25): - raise InvalidDataError('Invalid record id for Trapezoid: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Trapezoid: {record_id}') is_vertical, w, h, x, y, r, d, l = read_bool_byte(stream) optional: Dict[str, Any] = {} @@ -2153,7 +2161,7 @@ class Trapezoid(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = Trapezoid(bool(is_vertical), **optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -2260,16 +2268,18 @@ class CTrapezoid(Record, GeometryMixin): repetition: Optional[repetition_t] = None properties: List['Property'] - def __init__(self, - ctrapezoid_type: int = None, - layer: int = None, - datatype: int = None, - width: int = None, - height: int = None, - x: int = None, - y: int = None, - repetition: repetition_t = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + ctrapezoid_type: Optional[int] = None, + layer: Optional[int] = None, + datatype: Optional[int] = None, + width: Optional[int] = None, + height: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Raises: InvalidDataError: if dimensions are invalid. @@ -2303,7 +2313,7 @@ class CTrapezoid(Record, GeometryMixin): return verify_modal(self.height) return verify_modal(self.width) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') @@ -2312,21 +2322,19 @@ class CTrapezoid(Record, GeometryMixin): if self.ctrapezoid_type in (20, 21): if self.width is not None: - raise InvalidDataError('CTrapezoid has spurious width entry: ' - '{}'.format(self.width)) + raise InvalidDataError(f'CTrapezoid has spurious width entry: {self.width}') else: adjust_field(self, 'width', modals, 'geometry_w') if self.ctrapezoid_type in (16, 17, 18, 19, 22, 23, 25): if self.height is not None: - raise InvalidDataError('CTrapezoid has spurious height entry: ' - '{}'.format(self.height)) + raise InvalidDataError(f'CTrapezoid has spurious height entry: {self.height}') else: adjust_field(self, 'height', modals, 'geometry_h') self.check_valid() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -2337,15 +2345,13 @@ class CTrapezoid(Record, GeometryMixin): if self.ctrapezoid_type in (20, 21): if self.width is not None: - raise InvalidDataError('CTrapezoid has spurious width entry: ' - '{}'.format(self.width)) + raise InvalidDataError(f'CTrapezoid has spurious width entry: {self.width}') else: dedup_field(self, 'width', modals, 'geometry_w') if self.ctrapezoid_type in (16, 17, 18, 19, 22, 23, 25): if self.height is not None: - raise InvalidDataError('CTrapezoid has spurious height entry: ' - '{}'.format(self.height)) + raise InvalidDataError(f'CTrapezoid has spurious height entry: {self.height}') else: dedup_field(self, 'height', modals, 'geometry_h') @@ -2354,8 +2360,7 @@ class CTrapezoid(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'CTrapezoid': if record_id != 26: - raise InvalidDataError('Invalid record id for CTrapezoid: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for CTrapezoid: {record_id}') t, w, h, x, y, r, d, l = read_bool_byte(stream) optional: Dict[str, Any] = {} @@ -2376,7 +2381,7 @@ class CTrapezoid(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = CTrapezoid(**optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -2409,35 +2414,28 @@ class CTrapezoid(Record, GeometryMixin): size += self.repetition.write(stream) # type: ignore return size - def check_valid(self): + def check_valid(self) -> None: ctrapezoid_type = self.ctrapezoid_type width = self.width height = self.height if ctrapezoid_type in (20, 21) and width is not None: - raise InvalidDataError('CTrapezoid has spurious width entry: ' - '{}'.format(width)) + raise InvalidDataError(f'CTrapezoid has spurious width entry: {width}') if ctrapezoid_type in (16, 17, 18, 19, 22, 23, 25) and height is not None: - raise InvalidDataError('CTrapezoid has spurious height entry: ' - '{}'.format(height)) + raise InvalidDataError(f'CTrapezoid has spurious height entry: {height}') if width is not None and height is not None: if ctrapezoid_type in range(0, 4) and width < height: - raise InvalidDataError('CTrapezoid has width < height' - ' ({} < {})'.format(width, height)) + raise InvalidDataError(f'CTrapezoid has width < height ({width} < {height})') if ctrapezoid_type in range(4, 8) and width < 2 * height: - raise InvalidDataError('CTrapezoid has width < 2*height' - ' ({} < 2 * {})'.format(width, height)) + raise InvalidDataError(f'CTrapezoid has width < 2*height ({width} < 2 * {height})') if ctrapezoid_type in range(8, 12) and width > height: - raise InvalidDataError('CTrapezoid has width > height' - ' ({} > {})'.format(width, height)) + raise InvalidDataError(f'CTrapezoid has width > height ({width} > {height})') if ctrapezoid_type in range(12, 16) and 2 * width > height: - raise InvalidDataError('CTrapezoid has 2*width > height' - ' ({} > 2 * {})'.format(width, height)) + raise InvalidDataError(f'CTrapezoid has 2*width > height ({width} > 2 * {height})') if ctrapezoid_type is not None and ctrapezoid_type not in range(0, 26): - raise InvalidDataError('CTrapezoid has invalid type: ' - '{}'.format(ctrapezoid_type)) + raise InvalidDataError(f'CTrapezoid has invalid type: {ctrapezoid_type}') class Circle(Record, GeometryMixin): @@ -2453,22 +2451,24 @@ class Circle(Record, GeometryMixin): repetition (Optional[repetition_t]): Repetition, if any properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] = None - datatype: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - radius: Optional[int] = None + layer: Optional[int] + datatype: Optional[int] + x: Optional[int] + y: Optional[int] + repetition: Optional[repetition_t] + radius: Optional[int] properties: List['Property'] - def __init__(self, - radius: int = None, - layer: int = None, - datatype: int = None, - x: int = None, - y: int = None, - repetition: repetition_t = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + radius: Optional[int] = None, + layer: Optional[int] = None, + datatype: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Args: radius: Radius. Default `None` (reuse modal). @@ -2493,14 +2493,14 @@ class Circle(Record, GeometryMixin): def get_radius(self) -> int: return verify_modal(self.radius) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') adjust_field(self, 'datatype', modals, 'datatype') adjust_field(self, 'radius', modals, 'circle_radius') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -2510,8 +2510,7 @@ class Circle(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Circle': if record_id != 27: - raise InvalidDataError('Invalid record id for Circle: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Circle: {record_id}') z0, z1, has_radius, x, y, r, d, l = read_bool_byte(stream) if z0 or z1: @@ -2531,7 +2530,7 @@ class Circle(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = Circle(**optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -2559,7 +2558,7 @@ class Circle(Record, GeometryMixin): return size -def adjust_repetition(record, modals: Modals): +def adjust_repetition(record, modals: Modals) -> None: """ Merge the record's repetition entry with the one in the modals @@ -2581,7 +2580,7 @@ def adjust_repetition(record, modals: Modals): modals.repetition = copy.copy(record.repetition) -def adjust_field(record, r_field: str, modals: Modals, m_field: str): +def adjust_field(record, r_field: str, modals: Modals, m_field: str) -> None: """ Merge `record.r_field` with `modals.m_field` @@ -2602,10 +2601,10 @@ def adjust_field(record, r_field: str, modals: Modals, m_field: str): if m is not None: setattr(record, r_field, copy.copy(m)) else: - raise InvalidDataError('Unfillable field: {}'.format(m_field)) + raise InvalidDataError(f'Unfillable field: {m_field}') -def adjust_coordinates(record, modals: Modals, mx_field: str, my_field: str): +def adjust_coordinates(record, modals: Modals, mx_field: str, my_field: str) -> None: """ Merge `record.x` and `record.y` with `modals.mx_field` and `modals.my_field`, taking into account the value of `modals.xy_relative`. @@ -2639,7 +2638,7 @@ def adjust_coordinates(record, modals: Modals, mx_field: str, my_field: str): # TODO: Clarify the docs on the dedup_* functions -def dedup_repetition(record, modals: Modals): +def dedup_repetition(record, modals: Modals) -> None: """ Deduplicate the record's repetition entry with the one in the modals. Update the one in the modals if they are different. @@ -2666,7 +2665,7 @@ def dedup_repetition(record, modals: Modals): modals.repetition = record.repetition -def dedup_field(record, r_field: str, modals: Modals, m_field: str): +def dedup_field(record, r_field: str, modals: Modals, m_field: str) -> None: """ Deduplicate `record.r_field` using `modals.m_field` Update the `modals.m_field` if they are different. @@ -2699,7 +2698,7 @@ def dedup_field(record, r_field: str, modals: Modals, m_field: str): raise InvalidDataError('Unfillable field') -def dedup_coordinates(record, modals: Modals, mx_field: str, my_field: str): +def dedup_coordinates(record, modals: Modals, mx_field: str, my_field: str) -> None: """ Deduplicate `record.x` and `record.y` using `modals.mx_field` and `modals.my_field`, taking into account the value of `modals.xy_relative`. diff --git a/fatamorgana/test/build_testfiles.py b/fatamorgana/test/build_testfiles.py index 0dedfc4..e776c61 100644 --- a/fatamorgana/test/build_testfiles.py +++ b/fatamorgana/test/build_testfiles.py @@ -12,7 +12,8 @@ from . import ( test_files_circles, test_files_ctrapezoids, test_files_trapezoids, test_files_placements, test_files_paths, test_files_modals, test_files_polygons, test_files_rectangles, test_files_empty, - test_files_texts, test_files_cells) + test_files_texts, test_files_cells, + ) def build_file(num: str, func: Callable[[BufferedIOBase], BufferedIOBase]) -> None: From 406550cfd6daa63dad57e7e1fea05b7e6c9a5f83 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Thu, 26 Jan 2023 12:47:09 -0800 Subject: [PATCH 02/40] Use IO[bytes] instead of BinaryIO wherever possible --- fatamorgana/basic.py | 125 +++++++++++++++++++------------------- fatamorgana/main.py | 10 ++-- fatamorgana/records.py | 132 ++++++++++++++++++++--------------------- 3 files changed, 134 insertions(+), 133 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index b745f2f..2e41b6c 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -2,7 +2,7 @@ This module contains all datatypes and parsing/writing functions for all abstractions below the 'record' or 'block' level. """ -from typing import List, Tuple, Type, Union, Optional, Any, Sequence +from typing import List, Tuple, Type, Union, Optional, Any, Sequence, IO from fractions import Fraction from enum import Enum import math @@ -24,6 +24,7 @@ except ImportError: real_t = Union[int, float, Fraction] repetition_t = Union['ReuseRepetition', 'GridRepetition', 'ArbitraryRepetition'] property_value_t = Union[int, bytes, 'AString', 'NString', 'PropStringReference', float, Fraction] +bytes_t = bytes class FatamorganaError(Exception): @@ -85,7 +86,7 @@ MAGIC_BYTES: bytes = b'%SEMI-OASIS\r\n' ''' Basic IO ''' -def _read(stream: io.BufferedIOBase, n: int) -> bytes: +def _read(stream: IO[bytes], n: int) -> bytes: """ Read n bytes from the stream. Raise an EOFError if there were not enough bytes in the stream. @@ -106,7 +107,7 @@ def _read(stream: io.BufferedIOBase, n: int) -> bytes: return b -def read_byte(stream: io.BufferedIOBase) -> int: +def read_byte(stream: IO[bytes]) -> int: """ Read a single byte and return it. @@ -119,7 +120,7 @@ def read_byte(stream: io.BufferedIOBase) -> int: return _read(stream, 1)[0] -def write_byte(stream: io.BufferedIOBase, n: int) -> int: +def write_byte(stream: IO[bytes], n: int) -> int: """ Write a single byte to the stream. @@ -132,7 +133,7 @@ def write_byte(stream: io.BufferedIOBase, n: int) -> int: return stream.write(bytes((n,))) -def _py_read_bool_byte(stream: io.BufferedIOBase) -> List[bool]: +def _py_read_bool_byte(stream: IO[bytes]) -> List[bool]: """ Read a single byte from the stream, and interpret its bits as a list of 8 booleans. @@ -147,7 +148,7 @@ def _py_read_bool_byte(stream: io.BufferedIOBase) -> List[bool]: bits = [bool((byte >> i) & 0x01) for i in reversed(range(8))] return bits -def _py_write_bool_byte(stream: io.BufferedIOBase, bits: Tuple[Union[bool, int], ...]) -> int: +def _py_write_bool_byte(stream: IO[bytes], bits: Tuple[Union[bool, int], ...]) -> int: """ Pack 8 booleans into a byte, and write it to the stream. @@ -170,7 +171,7 @@ def _py_write_bool_byte(stream: io.BufferedIOBase, bits: Tuple[Union[bool, int], if _USE_NUMPY: - def _np_read_bool_byte(stream: io.BufferedIOBase) -> NDArray[numpy.uint8]: + def _np_read_bool_byte(stream: IO[bytes]) -> NDArray[numpy.uint8]: """ Read a single byte from the stream, and interpret its bits as a list of 8 booleans. @@ -184,7 +185,7 @@ if _USE_NUMPY: byte_arr = _read(stream, 1) return numpy.unpackbits(numpy.frombuffer(byte_arr, dtype=numpy.uint8)) - def _np_write_bool_byte(stream: io.BufferedIOBase, bits: Tuple[Union[bool, int], ...]) -> int: + def _np_write_bool_byte(stream: IO[bytes], bits: Tuple[Union[bool, int], ...]) -> int: """ Pack 8 booleans into a byte, and write it to the stream. @@ -208,7 +209,7 @@ else: read_bool_byte = _py_read_bool_byte # type: ignore write_bool_byte = _py_write_bool_byte -def read_uint(stream: io.BufferedIOBase) -> int: +def read_uint(stream: IO[bytes]) -> int: """ Read an unsigned integer from the stream. @@ -234,7 +235,7 @@ def read_uint(stream: io.BufferedIOBase) -> int: return result -def write_uint(stream: io.BufferedIOBase, n: int) -> int: +def write_uint(stream: IO[bytes], n: int) -> int: """ Write an unsigned integer to the stream. See format details in `read_uint()`. @@ -297,7 +298,7 @@ def encode_sint(sint: int) -> int: return (abs(sint) << 1) | (sint < 0) -def read_sint(stream: io.BufferedIOBase) -> int: +def read_sint(stream: IO[bytes]) -> int: """ Read a signed integer from the stream. See `decode_sint()` for format details. @@ -311,7 +312,7 @@ def read_sint(stream: io.BufferedIOBase) -> int: return decode_sint(read_uint(stream)) -def write_sint(stream: io.BufferedIOBase, n: int) -> int: +def write_sint(stream: IO[bytes], n: int) -> int: """ Write a signed integer to the stream. See `decode_sint()` for format details. @@ -326,7 +327,7 @@ def write_sint(stream: io.BufferedIOBase, n: int) -> int: return write_uint(stream, encode_sint(n)) -def read_bstring(stream: io.BufferedIOBase) -> bytes: +def read_bstring(stream: IO[bytes]) -> bytes: """ Read a binary string from the stream. The format is: @@ -343,7 +344,7 @@ def read_bstring(stream: io.BufferedIOBase) -> bytes: return _read(stream, length) -def write_bstring(stream: io.BufferedIOBase, bstring: bytes): +def write_bstring(stream: IO[bytes], bstring: bytes): """ Write a binary string to the stream. See `read_bstring()` for format details. @@ -359,7 +360,7 @@ def write_bstring(stream: io.BufferedIOBase, bstring: bytes): return stream.write(bstring) -def read_ratio(stream: io.BufferedIOBase) -> Fraction: +def read_ratio(stream: IO[bytes]) -> Fraction: """ Read a ratio (unsigned) from the stream. The format is: @@ -377,7 +378,7 @@ def read_ratio(stream: io.BufferedIOBase) -> Fraction: return Fraction(numer, denom) -def write_ratio(stream: io.BufferedIOBase, r: Fraction) -> int: +def write_ratio(stream: IO[bytes], r: Fraction) -> int: """ Write an unsigned ratio to the stream. See `read_ratio()` for format details. @@ -399,7 +400,7 @@ def write_ratio(stream: io.BufferedIOBase, r: Fraction) -> int: return size -def read_float32(stream: io.BufferedIOBase) -> float: +def read_float32(stream: IO[bytes]) -> float: """ Read a 32-bit float from the stream. @@ -413,7 +414,7 @@ def read_float32(stream: io.BufferedIOBase) -> float: return struct.unpack(" int: +def write_float32(stream: IO[bytes], f: float) -> int: """ Write a 32-bit float to the stream. @@ -428,7 +429,7 @@ def write_float32(stream: io.BufferedIOBase, f: float) -> int: return stream.write(b) -def read_float64(stream: io.BufferedIOBase) -> float: +def read_float64(stream: IO[bytes]) -> float: """ Read a 64-bit float from the stream. @@ -442,7 +443,7 @@ def read_float64(stream: io.BufferedIOBase) -> float: return struct.unpack(" int: +def write_float64(stream: IO[bytes], f: float) -> int: """ Write a 64-bit float to the stream. @@ -457,7 +458,7 @@ def write_float64(stream: io.BufferedIOBase, f: float) -> int: return stream.write(b) -def read_real(stream: io.BufferedIOBase, real_type: Optional[int] = None) -> real_t: +def read_real(stream: IO[bytes], real_type: Optional[int] = None) -> real_t: """ Read a real number from the stream. @@ -508,7 +509,7 @@ def read_real(stream: io.BufferedIOBase, real_type: Optional[int] = None) -> rea def write_real( - stream: io.BufferedIOBase, + stream: IO[bytes], r: real_t, force_float32: bool = False ) -> int: @@ -594,7 +595,7 @@ class NString: self._string = bstring.decode('ascii') @staticmethod - def read(stream: io.BufferedIOBase) -> 'NString': + def read(stream: IO[bytes_t]) -> 'NString': """ Create an NString object by reading a bstring from the provided stream. @@ -609,7 +610,7 @@ class NString: """ return NString(read_bstring(stream)) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes_t]) -> int: """ Write this NString to a stream. @@ -631,7 +632,7 @@ class NString: return self._string -def read_nstring(stream: io.BufferedIOBase) -> str: +def read_nstring(stream: IO[bytes]) -> str: """ Read a name string from the provided stream. See `NString` for constraints on name strings. @@ -648,7 +649,7 @@ def read_nstring(stream: io.BufferedIOBase) -> str: return NString.read(stream).string -def write_nstring(stream: io.BufferedIOBase, string: str) -> int: +def write_nstring(stream: IO[bytes], string: str) -> int: """ Write a name string to a stream. See `NString` for constraints on name strings. @@ -708,7 +709,7 @@ class AString: self._string = bstring.decode('ascii') @staticmethod - def read(stream: io.BufferedIOBase) -> 'AString': + def read(stream: IO[bytes_t]) -> 'AString': """ Create an `AString` object by reading a bstring from the provided stream. @@ -723,7 +724,7 @@ class AString: """ return AString(read_bstring(stream)) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes_t]) -> int: """ Write this `AString` to a stream. @@ -745,7 +746,7 @@ class AString: return self._string -def read_astring(stream: io.BufferedIOBase) -> str: +def read_astring(stream: IO[bytes]) -> str: """ Read an ASCII string from the provided stream. See `AString` for constraints on ASCII strings. @@ -762,7 +763,7 @@ def read_astring(stream: io.BufferedIOBase) -> str: return AString.read(stream).string -def write_astring(stream: io.BufferedIOBase, string: str) -> int: +def write_astring(stream: IO[bytes], string: str) -> int: """ Write an ASCII string to a stream. See AString for constraints on ASCII strings. @@ -853,7 +854,7 @@ class ManhattanDelta: return d @staticmethod - def read(stream: io.BufferedIOBase) -> 'ManhattanDelta': + def read(stream: IO[bytes]) -> 'ManhattanDelta': """ Read a `ManhattanDelta` object from the provided stream. @@ -868,7 +869,7 @@ class ManhattanDelta: n = read_uint(stream) return ManhattanDelta.from_uint(n) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write a `ManhattanDelta` object to the provided stream. @@ -989,7 +990,7 @@ class OctangularDelta: return d @staticmethod - def read(stream: io.BufferedIOBase) -> 'OctangularDelta': + def read(stream: IO[bytes]) -> 'OctangularDelta': """ Read an `OctangularDelta` object from the provided stream. @@ -1004,7 +1005,7 @@ class OctangularDelta: n = read_uint(stream) return OctangularDelta.from_uint(n) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write an `OctangularDelta` object to the provided stream. @@ -1057,7 +1058,7 @@ class Delta: return [self.x, self.y] @staticmethod - def read(stream: io.BufferedIOBase) -> 'Delta': + def read(stream: IO[bytes]) -> 'Delta': """ Read a `Delta` object from the provided stream. @@ -1083,7 +1084,7 @@ class Delta: y = read_sint(stream) return Delta(x, y) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write a `Delta` object to the provided stream. @@ -1109,7 +1110,7 @@ class Delta: return str(self.as_list()) -def read_repetition(stream: io.BufferedIOBase) -> repetition_t: +def read_repetition(stream: IO[bytes]) -> repetition_t: """ Read a repetition entry from the given stream. @@ -1133,7 +1134,7 @@ def read_repetition(stream: io.BufferedIOBase) -> repetition_t: raise InvalidDataError(f'Unexpected repetition type: {rtype}') -def write_repetition(stream: io.BufferedIOBase, repetition: repetition_t) -> int: +def write_repetition(stream: IO[bytes], repetition: repetition_t) -> int: """ Write a repetition entry to the given stream. @@ -1153,10 +1154,10 @@ class ReuseRepetition: the most recently written repetition should be reused. """ @staticmethod - def read(_stream: io.BufferedIOBase, _repetition_type: int) -> 'ReuseRepetition': + def read(_stream: IO[bytes], _repetition_type: int) -> 'ReuseRepetition': return ReuseRepetition() - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: return write_uint(stream, 0) def __eq__(self, other: Any) -> bool: @@ -1230,7 +1231,7 @@ class GridRepetition: self.b_count = b_count @staticmethod - def read(stream: io.BufferedIOBase, repetition_type: int) -> 'GridRepetition': + def read(stream: IO[bytes], repetition_type: int) -> 'GridRepetition': """ Read a `GridRepetition` from a stream. @@ -1276,7 +1277,7 @@ class GridRepetition: raise InvalidDataError(f'Invalid type for grid repetition {repetition_type}') return GridRepetition(a_vector, na, b_vector, nb) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write the `GridRepetition` to a stream. @@ -1375,7 +1376,7 @@ class ArbitraryRepetition: self.y_displacements = list(y_displacements) @staticmethod - def read(stream: io.BufferedIOBase, repetition_type: int) -> 'ArbitraryRepetition': + def read(stream: IO[bytes], repetition_type: int) -> 'ArbitraryRepetition': """ Read an `ArbitraryRepetition` from a stream. @@ -1429,7 +1430,7 @@ class ArbitraryRepetition: raise InvalidDataError(f'Invalid ArbitraryRepetition repetition_type: {repetition_type}') return ArbitraryRepetition(x_displacements, y_displacements) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write the `ArbitraryRepetition` to a stream. @@ -1504,7 +1505,7 @@ class ArbitraryRepetition: def read_point_list( - stream: io.BufferedIOBase, + stream: IO[bytes], implicit_closed: bool, ) -> List[List[int]]: """ @@ -1537,7 +1538,7 @@ def read_point_list( for i in range(list_len): n = read_sint(stream) if n == 0: - raise Exception('Zero-sized 1-delta') + raise InvalidDataError('Zero-sized 1-delta') point = [0, 0] point[(i + 1) % 2] = n points.append(point) @@ -1593,7 +1594,7 @@ def read_point_list( def write_point_list( - stream: io.BufferedIOBase, + stream: IO[bytes], points: List[Sequence[int]], fast: bool = False, implicit_closed: bool = True @@ -1740,7 +1741,7 @@ class PropStringReference: return f'[{self.ref_type} : {self.ref}]' -def read_property_value(stream: io.BufferedIOBase) -> property_value_t: +def read_property_value(stream: IO[bytes]) -> property_value_t: """ Read a property value from a stream. @@ -1798,7 +1799,7 @@ def read_property_value(stream: io.BufferedIOBase) -> property_value_t: def write_property_value( - stream: io.BufferedIOBase, + stream: IO[bytes], value: property_value_t, force_real: bool = False, force_signed_int: bool = False, @@ -1850,11 +1851,11 @@ def write_property_value( size = write_uint(stream, 15) size += write_uint(stream, value.ref) else: - raise Exception(f'Invalid property type: {type(value)} ({value})') + raise InvalidDataError(f'Invalid property type: {type(value)} ({value})') return size -def read_interval(stream: io.BufferedIOBase) -> Tuple[Optional[int], Optional[int]]: +def read_interval(stream: IO[bytes]) -> Tuple[Optional[int], Optional[int]]: """ Read an interval from a stream. These are used for storing layer info. @@ -1895,7 +1896,7 @@ def read_interval(stream: io.BufferedIOBase) -> Tuple[Optional[int], Optional[in def write_interval( - stream: io.BufferedIOBase, + stream: IO[bytes], min_bound: Optional[int] = None, max_bound: Optional[int] = None, ) -> int: @@ -1962,7 +1963,7 @@ class OffsetEntry: self.offset = offset @staticmethod - def read(stream: io.BufferedIOBase) -> 'OffsetEntry': + def read(stream: IO[bytes]) -> 'OffsetEntry': """ Read an offset entry from a stream. @@ -1977,7 +1978,7 @@ class OffsetEntry: entry.offset = read_uint(stream) return entry - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write this offset entry to a stream. @@ -2063,7 +2064,7 @@ class OffsetTable: self.xnames = xnames @staticmethod - def read(stream: io.BufferedIOBase) -> 'OffsetTable': + def read(stream: IO[bytes]) -> 'OffsetTable': """ Read an offset table from a stream. See class docstring for format details. @@ -2083,7 +2084,7 @@ class OffsetTable: table.xnames = OffsetEntry.read(stream) return table - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write this offset table to a stream. See class docstring for format details. @@ -2107,7 +2108,7 @@ class OffsetTable: self.propstrings, self.layernames, self.xnames]) -def read_u32(stream: io.BufferedIOBase) -> int: +def read_u32(stream: IO[bytes]) -> int: """ Read a 32-bit unsigned integer (little endian) from a stream. @@ -2121,7 +2122,7 @@ def read_u32(stream: io.BufferedIOBase) -> int: return struct.unpack(' int: +def write_u32(stream: IO[bytes], n: int) -> int: """ Write a 32-bit unsigned integer (little endian) to a stream. @@ -2174,7 +2175,7 @@ class Validation: self.checksum = checksum @staticmethod - def read(stream: io.BufferedIOBase) -> 'Validation': + def read(stream: IO[bytes]) -> 'Validation': """ Read a validation entry from a stream. See class docstring for format details. @@ -2199,7 +2200,7 @@ class Validation: raise InvalidDataError('Invalid validation type!') return Validation(checksum_type, checksum) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write this validation entry to a stream. See class docstring for format details. @@ -2228,7 +2229,7 @@ class Validation: return f'Validation(type: {self.checksum_type} sum: {self.checksum})' -def write_magic_bytes(stream: io.BufferedIOBase) -> int: +def write_magic_bytes(stream: IO[bytes]) -> int: """ Write the magic byte sequence to a stream. @@ -2241,7 +2242,7 @@ def write_magic_bytes(stream: io.BufferedIOBase) -> int: return stream.write(MAGIC_BYTES) -def read_magic_bytes(stream: io.BufferedIOBase): +def read_magic_bytes(stream: IO[bytes]): """ Read the magic byte sequence from a stream. Raise an `InvalidDataError` if it was not found. diff --git a/fatamorgana/main.py b/fatamorgana/main.py index a11af4e..8748d7f 100644 --- a/fatamorgana/main.py +++ b/fatamorgana/main.py @@ -3,7 +3,7 @@ This module contains data structures and functions for reading from and writing to whole OASIS layout files, and provides a few additional abstractions for the data contained inside them. """ -from typing import List, Dict, Union, Optional, Type +from typing import List, Dict, Union, Optional, Type, IO import io import logging @@ -116,7 +116,7 @@ class OasisLayout: self.layers = [] @staticmethod - def read(stream: io.BufferedIOBase) -> 'OasisLayout': + def read(stream: IO[bytes]) -> 'OasisLayout': """ Read an entire .oas file into an `OasisLayout` object. @@ -138,7 +138,7 @@ class OasisLayout: def read_record( self, - stream: io.BufferedIOBase, + stream: IO[bytes], modals: Modals, file_state: FileModals ) -> bool: @@ -343,7 +343,7 @@ class OasisLayout: raise InvalidRecordError(f'Unknown record id: {record_id}') return False - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write this object in OASIS fromat to a stream. @@ -430,7 +430,7 @@ class Cell: self.placements = [] if placements is None else placements self.geometry = [] if geometry is None else geometry - def dedup_write(self, stream: io.BufferedIOBase, modals: Modals) -> int: + def dedup_write(self, stream: IO[bytes], modals: Modals) -> int: """ Write this cell to a stream, using the provided modal variables to deduplicate any repeated data. diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 453ad03..20e9819 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -10,7 +10,7 @@ Higher-level code (e.g. monitoring for combinations of records with parse, or code for dealing with nested records in a CBlock) should live in main.py instead. """ -from typing import List, Dict, Tuple, Union, Optional, Sequence, Any, TypeVar +from typing import List, Dict, Tuple, Union, Optional, Sequence, Any, TypeVar, IO from abc import ABCMeta, abstractmethod import copy import math @@ -159,7 +159,7 @@ class Record(metaclass=ABCMeta): @staticmethod @abstractmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Record': + def read(stream: IO[bytes], record_id: int) -> 'Record': """ Read a record of this type from a stream. This function does not merge with modal variables. @@ -179,7 +179,7 @@ class Record(metaclass=ABCMeta): pass @abstractmethod - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write this record to a stream as-is. This function does not merge or deduplicate with modal variables. @@ -195,7 +195,7 @@ class Record(metaclass=ABCMeta): """ pass - def dedup_write(self, stream: io.BufferedIOBase, modals: Modals) -> int: + def dedup_write(self, stream: IO[bytes], modals: Modals) -> int: """ Run `.deduplicate_with_modals()` and then `.write()` to the stream. @@ -256,7 +256,7 @@ class GeometryMixin(metaclass=ABCMeta): def read_refname( - stream: io.BufferedIOBase, + stream: IO[bytes], is_present: Union[bool, int], is_reference: Union[bool, int] ) -> Union[None, int, NString]: @@ -281,7 +281,7 @@ def read_refname( def read_refstring( - stream: io.BufferedIOBase, + stream: IO[bytes], is_present: Union[bool, int], is_reference: Union[bool, int], ) -> Union[None, int, AString]: @@ -316,14 +316,14 @@ class Pad(Record): pass @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Pad': + def read(stream: IO[bytes], record_id: int) -> 'Pad': if record_id != 0: raise InvalidDataError(f'Invalid record id for Pad {record_id}') record = Pad() logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: return write_uint(stream, 0) @@ -355,14 +355,14 @@ class XYMode(Record): pass @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'XYMode': + def read(stream: IO[bytes], record_id: int) -> 'XYMode': if record_id not in (15, 16): raise InvalidDataError('Invalid record id for XYMode') record = XYMode(record_id == 16) logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: return write_uint(stream, 15 + self.relative) @@ -417,7 +417,7 @@ class Start(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Start': + def read(stream: IO[bytes], record_id: int) -> 'Start': if record_id != 1: raise InvalidDataError(f'Invalid record id for Start: {record_id}') version = AString.read(stream) @@ -432,7 +432,7 @@ class Start(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: size = write_uint(stream, 1) size += self.version.write(stream) size += write_real(stream, self.unit) @@ -478,7 +478,7 @@ class End(Record): @staticmethod def read( - stream: io.BufferedIOBase, + stream: IO[bytes], record_id: int, has_offset_table: bool ) -> 'End': @@ -494,7 +494,7 @@ class End(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: size = write_uint(stream, 2) if self.offset_table is not None: size += self.offset_table.write(stream) @@ -550,7 +550,7 @@ class CBlock(Record): pass @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'CBlock': + def read(stream: IO[bytes], record_id: int) -> 'CBlock': if record_id != 34: raise InvalidDataError(f'Invalid record id for CBlock: {record_id}') compression_type = read_uint(stream) @@ -560,7 +560,7 @@ class CBlock(Record): logger.debug(f'CBlock ending at 0x{stream.tell():x} was read successfully') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: size = write_uint(stream, 34) size += write_uint(stream, self.compression_type) size += write_uint(stream, self.decompressed_byte_count) @@ -662,7 +662,7 @@ class CellName(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'CellName': + def read(stream: IO[bytes], record_id: int) -> 'CellName': if record_id not in (3, 4): raise InvalidDataError(f'Invalid record id for CellName {record_id}') nstring = NString.read(stream) @@ -674,7 +674,7 @@ class CellName(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 3 + (self.reference_number is not None) size = write_uint(stream, record_id) size += self.nstring.write(stream) @@ -717,7 +717,7 @@ class PropName(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'PropName': + def read(stream: IO[bytes], record_id: int) -> 'PropName': if record_id not in (7, 8): raise InvalidDataError(f'Invalid record id for PropName {record_id}') nstring = NString.read(stream) @@ -729,7 +729,7 @@ class PropName(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 7 + (self.reference_number is not None) size = write_uint(stream, record_id) size += self.nstring.write(stream) @@ -773,7 +773,7 @@ class TextString(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'TextString': + def read(stream: IO[bytes], record_id: int) -> 'TextString': if record_id not in (5, 6): raise InvalidDataError(f'Invalid record id for TextString: {record_id}') astring = AString.read(stream) @@ -785,7 +785,7 @@ class TextString(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 5 + (self.reference_number is not None) size = write_uint(stream, record_id) size += self.astring.write(stream) @@ -829,7 +829,7 @@ class PropString(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'PropString': + def read(stream: IO[bytes], record_id: int) -> 'PropString': if record_id not in (9, 10): raise InvalidDataError(f'Invalid record id for PropString: {record_id}') astring = AString.read(stream) @@ -841,7 +841,7 @@ class PropString(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 9 + (self.reference_number is not None) size = write_uint(stream, record_id) size += self.astring.write(stream) @@ -896,7 +896,7 @@ class LayerName(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'LayerName': + def read(stream: IO[bytes], record_id: int) -> 'LayerName': if record_id not in (11, 12): raise InvalidDataError(f'Invalid record id for LayerName: {record_id}') is_textlayer = (record_id == 12) @@ -907,7 +907,7 @@ class LayerName(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 11 + self.is_textlayer size = write_uint(stream, record_id) size += self.nstring.write(stream) @@ -973,7 +973,7 @@ class Property(Record): dedup_field(self, 'is_standard', modals, 'property_is_standard') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Property': + def read(stream: IO[bytes], record_id: int) -> 'Property': if record_id not in (28, 29): raise InvalidDataError(f'Invalid record id for PropertyValue: {record_id}') if record_id == 29: @@ -1003,7 +1003,7 @@ class Property(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: if self.is_standard is None and self.values is None and self.name is None: return write_uint(stream, 29) else: @@ -1075,7 +1075,7 @@ class XName(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'XName': + def read(stream: IO[bytes], record_id: int) -> 'XName': if record_id not in (30, 31): raise InvalidDataError(f'Invalid record id for XName: {record_id}') attribute = read_uint(stream) @@ -1088,7 +1088,7 @@ class XName(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 30 + (self.reference_number is not None) size = write_uint(stream, record_id) size += write_uint(stream, self.attribute) @@ -1133,7 +1133,7 @@ class XElement(Record): pass @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'XElement': + def read(stream: IO[bytes], record_id: int) -> 'XElement': if record_id != 32: raise InvalidDataError(f'Invalid record id for XElement: {record_id}') attribute = read_uint(stream) @@ -1142,7 +1142,7 @@ class XElement(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: size = write_uint(stream, 32) size += write_uint(stream, self.attribute) size += write_bstring(stream, self.bstring) @@ -1216,7 +1216,7 @@ class XGeometry(Record, GeometryMixin): dedup_field(self, 'datatype', modals, 'datatype') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'XGeometry': + def read(stream: IO[bytes], record_id: int) -> 'XGeometry': if record_id != 33: raise InvalidDataError(f'Invalid record id for XGeometry: {record_id}') @@ -1241,7 +1241,7 @@ class XGeometry(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: x = self.x is not None y = self.y is not None r = self.repetition is not None @@ -1288,7 +1288,7 @@ class Cell(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Cell': + def read(stream: IO[bytes], record_id: int) -> 'Cell': name: Union[int, NString] if record_id == 13: name = read_uint(stream) @@ -1300,7 +1300,7 @@ class Cell(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: size = 0 if isinstance(self.name, int): size += write_uint(stream, 13) @@ -1391,7 +1391,7 @@ class Placement(Record): dedup_field(self, 'name', modals, 'placement_cell') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Placement': + def read(stream: IO[bytes], record_id: int) -> 'Placement': if record_id not in (17, 18): raise InvalidDataError(f'Invalid record id for Placement: {record_id}') @@ -1421,7 +1421,7 @@ class Placement(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: c = self.name is not None n = c and isinstance(self.name, int) x = self.x is not None @@ -1534,7 +1534,7 @@ class Text(Record, GeometryMixin): dedup_field(self, 'datatype', modals, 'text_datatype') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Text': + def read(stream: IO[bytes], record_id: int) -> 'Text': if record_id != 19: raise InvalidDataError(f'Invalid record id for Text: {record_id}') @@ -1559,7 +1559,7 @@ class Text(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: c = self.string is not None n = c and isinstance(self.string, int) x = self.x is not None @@ -1609,14 +1609,14 @@ class Rectangle(Record, GeometryMixin): repetition (Optional[repetition_t]): Repetition, if any. properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] = None - datatype: Optional[int] = None - width: Optional[int] = None - height: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - is_square: bool = False + layer: Optional[int] + datatype: Optional[int] + width: Optional[int] + height: Optional[int] + x: Optional[int] + y: Optional[int] + repetition: Optional[repetition_t] + is_square: bool properties: List['Property'] def __init__( @@ -1674,7 +1674,7 @@ class Rectangle(Record, GeometryMixin): dedup_field(self, 'height', modals, 'geometry_h') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Rectangle': + def read(stream: IO[bytes], record_id: int) -> 'Rectangle': if record_id != 20: raise InvalidDataError(f'Invalid record id for Rectangle: {record_id}') @@ -1698,7 +1698,7 @@ class Rectangle(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: s = self.is_square w = self.width is not None h = self.height is not None @@ -1749,12 +1749,12 @@ class Polygon(Record, GeometryMixin): Default no repetition. properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] = None - datatype: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - point_list: Optional[point_list_t] = None + layer: Optional[int] + datatype: Optional[int] + x: Optional[int] + y: Optional[int] + repetition: Optional[repetition_t] + point_list: Optional[point_list_t] properties: List['Property'] def __init__( @@ -1797,7 +1797,7 @@ class Polygon(Record, GeometryMixin): dedup_field(self, 'point_list', modals, 'polygon_point_list') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Polygon': + def read(stream: IO[bytes], record_id: int) -> 'Polygon': if record_id != 21: raise InvalidDataError(f'Invalid record id for Polygon: {record_id}') @@ -1822,7 +1822,7 @@ class Polygon(Record, GeometryMixin): logger.debug('Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase, fast: bool = False) -> int: + def write(self, stream: IO[bytes], fast: bool = False) -> int: p = self.point_list is not None x = self.x is not None y = self.y is not None @@ -1941,7 +1941,7 @@ class Path(Record, GeometryMixin): dedup_field(self, 'extension_end', modals, 'path_extension_end') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Path': + def read(stream: IO[bytes], record_id: int) -> 'Path': if record_id != 22: raise InvalidDataError(f'Invalid record id for Path: {record_id}') @@ -1984,7 +1984,7 @@ class Path(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase, fast: bool = False) -> int: + def write(self, stream: IO[bytes], fast: bool = False) -> int: e = self.extension_start is not None or self.extension_end is not None w = self.half_width is not None p = self.point_list is not None @@ -2136,7 +2136,7 @@ class Trapezoid(Record, GeometryMixin): dedup_field(self, 'height', modals, 'geometry_h') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Trapezoid': + def read(stream: IO[bytes], record_id: int) -> 'Trapezoid': if record_id not in (23, 24, 25): raise InvalidDataError(f'Invalid record id for Trapezoid: {record_id}') @@ -2164,7 +2164,7 @@ class Trapezoid(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: v = self.is_vertical w = self.width is not None h = self.height is not None @@ -2358,7 +2358,7 @@ class CTrapezoid(Record, GeometryMixin): self.check_valid() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'CTrapezoid': + def read(stream: IO[bytes], record_id: int) -> 'CTrapezoid': if record_id != 26: raise InvalidDataError(f'Invalid record id for CTrapezoid: {record_id}') @@ -2384,7 +2384,7 @@ class CTrapezoid(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: t = self.ctrapezoid_type is not None w = self.width is not None h = self.height is not None @@ -2508,7 +2508,7 @@ class Circle(Record, GeometryMixin): dedup_field(self, 'radius', modals, 'circle_radius') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Circle': + def read(stream: IO[bytes], record_id: int) -> 'Circle': if record_id != 27: raise InvalidDataError(f'Invalid record id for Circle: {record_id}') @@ -2533,7 +2533,7 @@ class Circle(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: s = self.radius is not None x = self.x is not None y = self.y is not None From aa5967b58cd7ea4b3f49a429b3908877468b7579 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Thu, 26 Jan 2023 13:36:22 -0800 Subject: [PATCH 03/40] cleanup based on flake8 output --- .flake8 | 1 + fatamorgana/basic.py | 5 +- fatamorgana/records.py | 2 +- fatamorgana/test/test_files_cblocks.py | 179 +++--- fatamorgana/test/test_files_cells.py | 7 +- fatamorgana/test/test_files_circles.py | 86 ++- fatamorgana/test/test_files_ctrapezoids.py | 143 ++--- fatamorgana/test/test_files_empty.py | 7 +- fatamorgana/test/test_files_layernames.py | 118 ++-- fatamorgana/test/test_files_modals.py | 208 +++--- fatamorgana/test/test_files_paths.py | 176 +++--- fatamorgana/test/test_files_placements.py | 564 ++++++++--------- fatamorgana/test/test_files_polygons.py | 305 ++++----- fatamorgana/test/test_files_properties.py | 698 ++++++++++----------- fatamorgana/test/test_files_rectangles.py | 160 +++-- fatamorgana/test/test_files_texts.py | 21 +- fatamorgana/test/test_files_trapezoids.py | 230 ++++--- fatamorgana/test/test_int.py | 3 - fatamorgana/test/utils.py | 10 +- 19 files changed, 1429 insertions(+), 1494 deletions(-) diff --git a/.flake8 b/.flake8 index 0042015..fb07707 100644 --- a/.flake8 +++ b/.flake8 @@ -27,3 +27,4 @@ ignore = per-file-ignores = # F401 import without use */__init__.py: F401, + __init__.py: F401, diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 2e41b6c..476e5f6 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -7,7 +7,6 @@ from fractions import Fraction from enum import Enum import math import struct -import io import warnings try: @@ -1663,13 +1662,13 @@ def write_point_list( if implicit_closed: ManhattanDelta(points[-1][0] - points[0][0], points[-1][1] - points[0][1]) list_type = 2 - except: + except InvalidDataError: try: deltas = [OctangularDelta(x, y) for x, y in points] if implicit_closed: OctangularDelta(points[-1][0] - points[0][0], points[-1][1] - points[0][1]) list_type = 3 - except: + except InvalidDataError: pass if list_type is not None: size = write_uint(stream, list_type) diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 20e9819..46beb48 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -383,7 +383,7 @@ class Start(Record): def __init__( self, unit: real_t, - version: Union[AString, str] = "1.0", + version: Union[AString, str] = "1.0", offset_table: Optional[OffsetTable] = None, ) -> None: """ diff --git a/fatamorgana/test/test_files_cblocks.py b/fatamorgana/test/test_files_cblocks.py index 93ff0ac..cf3f2ec 100644 --- a/fatamorgana/test/test_files_cblocks.py +++ b/fatamorgana/test/test_files_cblocks.py @@ -1,17 +1,11 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore -import numpy from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_bstring, write_byte from ..main import OasisLayout @@ -98,86 +92,105 @@ def test_file_1() -> None: assert geometry[1].height == 610 assert geometry[1].width == 680 - assert_equal(geometry[2].point_list, - [[-30, -360], [480, -50], [180, 430], [-630, -20]]) + assert_equal(geometry[2].point_list, [ + [-30, -360], + [480, -50], + [180, 430], + [-630, -20], + ]) - assert_equal(geometry[3].point_list, - [[-30, -400], - [450, 40], - [70, -220], - [10, 210], - [740, -20], - [0, 660], - [570, 10], - [50, 500], - [630, 20], - [10, 100], - [-810, 10], - [20, -470], - [-660, 0], - [20, -470], - [-620, 10], - [0, 610], - [610, -10], - [0, -100], - [210, 10], - [40, 820], - [-1340, 60], - [30, -1370]]) + assert_equal(geometry[3].point_list, [ + [-30, -400], + [450, 40], + [70, -220], + [10, 210], + [740, -20], + [0, 660], + [570, 10], + [50, 500], + [630, 20], + [10, 100], + [-810, 10], + [20, -470], + [-660, 0], + [20, -470], + [-620, 10], + [0, 610], + [610, -10], + [0, -100], + [210, 10], + [40, 820], + [-1340, 60], + [30, -1370], + ]) - assert_equal(geometry[4].point_list, - [[40, -760], [490, -50], [110, 800], [-640, 10]]) + assert_equal(geometry[4].point_list, [ + [40, -760], + [490, -50], + [110, 800], + [-640, 10], + ]) - assert_equal(geometry[5].point_list, - [[140, -380], - [340, -10], - [30, -100], - [-320, 20], - [130, -460], - [-480, -20], - [-210, 910], - [370, 40]]) + assert_equal(geometry[5].point_list, [ + [140, -380], + [340, -10], + [30, -100], + [-320, 20], + [130, -460], + [-480, -20], + [-210, 910], + [370, 40], + ]) - assert_equal(geometry[6].point_list, - [[720, -20], - [20, 20], - [690, 0], - [-10, 650], - [-20, 30], - [-90, -10], - [10, 70], - [470, -30], - [20, -120], - [-320, 0], - [40, -790], - [-90, -20], - [-60, 140], - [-1390, 50], - [10, 30]]) + assert_equal(geometry[6].point_list, [ + [720, -20], + [20, 20], + [690, 0], + [-10, 650], + [-20, 30], + [-90, -10], + [10, 70], + [470, -30], + [20, -120], + [-320, 0], + [40, -790], + [-90, -20], + [-60, 140], + [-1390, 50], + [10, 30], + ]) - assert_equal(geometry[7].point_list, - [[150, -830], - [-1320, 40], - [-70, 370], - [310, -30], - [10, 220], - [250, -40], - [40, -220], - [340, 10], - [-20, 290], - [-1070, 20], - [0, 230], - [1380, -60]]) + assert_equal(geometry[7].point_list, [ + [150, -830], + [-1320, 40], + [-70, 370], + [310, -30], + [10, 220], + [250, -40], + [40, -220], + [340, 10], + [-20, 290], + [-1070, 20], + [0, 230], + [1380, -60], + ]) - assert_equal(geometry[8].point_list, - [[330, 0], [-10, 480], [620, -20], [-10, 330], [-930, 60], [0, -850]]) + assert_equal(geometry[8].point_list, [ + [330, 0], + [-10, 480], + [620, -20], + [-10, 330], + [-930, 60], + [0, -850], + ]) - assert_equal(geometry[9].point_list, - [[-140, -410], - [10, -140], - [270, 0], - [130, 1030], - [-500, 50], - [10, -330], - [210, -10], - [10, -190]]) + assert_equal(geometry[9].point_list, [ + [-140, -410], + [10, -140], + [270, 0], + [130, 1030], + [-500, 50], + [10, -330], + [210, -10], + [10, -190], + ]) diff --git a/fatamorgana/test/test_files_cells.py b/fatamorgana/test/test_files_cells.py index 9239994..9fae7b8 100644 --- a/fatamorgana/test/test_files_cells.py +++ b/fatamorgana/test/test_files_cells.py @@ -1,14 +1,11 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore +import pytest from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring +from ..basic import write_uint, write_bstring from ..basic import InvalidRecordError, InvalidDataError from ..main import OasisLayout diff --git a/fatamorgana/test/test_files_circles.py b/fatamorgana/test/test_files_circles.py index 35c7a14..794c18f 100644 --- a/fatamorgana/test/test_files_circles.py +++ b/fatamorgana/test/test_files_circles.py @@ -1,17 +1,9 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct - -import pytest # type: ignore -import numpy -from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -37,52 +29,52 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0011_1011) # 00rX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 150) # radius - write_sint(buf, -100) # geometry-x (absolute) - write_sint(buf, 200) # geometry-y (absolute) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0011_1011) # 00rX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 150) # radius + write_sint(buf, -100) # geometry-x (absolute) + write_sint(buf, 200) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0000_1000) # 00rX_YRDL - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0000_1000) # 00rX_YRDL + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0010_1000) # 00rX_YRDL - write_uint(buf, 0) # radius - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0010_1000) # 00rX_YRDL + write_uint(buf, 0) # radius + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0010_1000) # 00rX_YRDL - write_uint(buf, 1) # radius - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0010_1000) # 00rX_YRDL + write_uint(buf, 1) # radius + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0010_1000) # 00rX_YRDL - write_uint(buf, 6) # radius - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0010_1000) # 00rX_YRDL + write_uint(buf, 6) # radius + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0010_1000) # 00rX_YRDL - write_uint(buf, 20) # radius - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0010_1000) # 00rX_YRDL + write_uint(buf, 20) # radius + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0010_1100) # 00rX_YRDL - write_uint(buf, 100) # radius - write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 400) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0010_1100) # 00rX_YRDL + write_uint(buf, 100) # radius + write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 400) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing buf.write(FOOTER) return buf diff --git a/fatamorgana/test/test_files_ctrapezoids.py b/fatamorgana/test/test_files_ctrapezoids.py index b98794a..fdcc6cf 100644 --- a/fatamorgana/test/test_files_ctrapezoids.py +++ b/fatamorgana/test/test_files_ctrapezoids.py @@ -1,17 +1,9 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct - -import pytest # type: ignore -import numpy -from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -33,29 +25,29 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b1111_1011) # TWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 24) # ctrapezoid type - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, -100) # geometry-x (absolute) - write_sint(buf, 200) # geometry-y (absolute) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b1111_1011) # TWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 24) # ctrapezoid type + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, -100) # geometry-x (absolute) + write_sint(buf, 200) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b0000_1000) # TWHX_YRDL - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b0000_1000) # TWHX_YRDL + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_0011) # SWHX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_0011) # SWHX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype h = [250, 100] v = [100, 250] @@ -66,33 +58,34 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: + [0b10] * 4 + [0b01] * 2 + [0b10] * 2 - + [0b11, 0b10]) + + [0b11, 0b10] + ) for t, (x, x_en) in enumerate(zip(wh, wh_en)): - write_uint(buf, 26) # CTRAPEZOID record + write_uint(buf, 26) # CTRAPEZOID record write_byte(buf, 0b1000_1011 | (x_en << 5)) # TWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, t) # ctrapezoid type + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, t) # ctrapezoid type if x_en & 0b10: - write_uint(buf, x[0]) # width + write_uint(buf, x[0]) # width if x_en & 0b01: - write_uint(buf, x[1]) # height - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, x[1]) # height + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_0011) # SWHX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_0011) # SWHX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b0000_1100) # TWHX_YRDL - write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 400) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b0000_1100) # TWHX_YRDL + write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 400) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing buf.write(FOOTER) return buf @@ -143,7 +136,7 @@ def test_file_1() -> None: elif ct_type in range(22, 24) or ct_type == 25: assert gg.height == [100, None][is_ctrapz], msg else: - if ct_type < 8 or 16 <= ct_type < 25 or 26 <= ct_type : + if ct_type < 8 or 16 <= ct_type < 25 or 26 <= ct_type: assert gg.width == 250, msg assert gg.height == 100, msg else: @@ -169,39 +162,39 @@ def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: write_bstring(buf, b'A') # Cell name # Shouldn't access (undefined) height modal, despite not having a height. - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b1101_1011) # TWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 16) # ctrapezoid type - write_uint(buf, 200) # width - write_sint(buf, -100) # geometry-x (absolute) - write_sint(buf, 200) # geometry-y (absolute) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b1101_1011) # TWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 16) # ctrapezoid type + write_uint(buf, 200) # width + write_sint(buf, -100) # geometry-x (absolute) + write_sint(buf, 200) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b0000_1000) # TWHX_YRDL - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b0000_1000) # TWHX_YRDL + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'B') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'B') # Cell name # Shouldn't access (undefined) width modal, despite not having a width. - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b1011_1011) # TWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 20) # ctrapezoid type - write_uint(buf, 200) # height - write_sint(buf, -100) # geometry-x (absolute) - write_sint(buf, 200) # geometry-y (absolute) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b1011_1011) # TWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 20) # ctrapezoid type + write_uint(buf, 200) # height + write_sint(buf, -100) # geometry-x (absolute) + write_sint(buf, 200) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b0000_1000) # TWHX_YRDL - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b0000_1000) # TWHX_YRDL + write_sint(buf, 400) # geometry-y (relative) buf.write(FOOTER) return buf diff --git a/fatamorgana/test/test_files_empty.py b/fatamorgana/test/test_files_empty.py index 1fbb63c..acf651d 100644 --- a/fatamorgana/test/test_files_empty.py +++ b/fatamorgana/test/test_files_empty.py @@ -1,14 +1,10 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase import struct -import pytest # type: ignore - from .utils import MAGIC_BYTES, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring +from ..basic import write_uint, write_bstring from ..main import OasisLayout @@ -59,7 +55,6 @@ def test_file_1() -> None: assert layout.unit == 1000 - def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: ''' File contains no records. diff --git a/fatamorgana/test/test_files_layernames.py b/fatamorgana/test/test_files_layernames.py index 56ddc23..94a2cc8 100644 --- a/fatamorgana/test/test_files_layernames.py +++ b/fatamorgana/test/test_files_layernames.py @@ -1,16 +1,10 @@ # type: ignore +from typing import Sequence -from typing import List, Tuple, Iterable, Sequence -from itertools import chain from io import BytesIO, BufferedIOBase -import pytest # type: ignore -import numpy -from numpy.testing import assert_equal - from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -37,67 +31,67 @@ def base_tests(layout: OasisLayout) -> None: def write_names_geom(buf: BufferedIOBase, short: bool = False) -> BufferedIOBase: - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'AA') # name - write_uint(buf, 0) # all layers - write_uint(buf, 0) # all datatypes + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'AA') # name + write_uint(buf, 0) # all layers + write_uint(buf, 0) # all datatypes - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'L5A') # name - write_uint(buf, 1) # layer <=5 - write_uint(buf, 5) # (...) - write_uint(buf, 0) # all datatypes + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'L5A') # name + write_uint(buf, 1) # layer <=5 + write_uint(buf, 5) # (...) + write_uint(buf, 0) # all datatypes - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'H5A') # name - write_uint(buf, 2) # layer >=5 - write_uint(buf, 5) # (...) - write_uint(buf, 0) # all datatypes + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'H5A') # name + write_uint(buf, 2) # layer >=5 + write_uint(buf, 5) # (...) + write_uint(buf, 0) # all datatypes - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'E5A') # name - write_uint(buf, 3) # layer ==5 - write_uint(buf, 5) # (...) - write_uint(buf, 0) # all datatypes + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'E5A') # name + write_uint(buf, 3) # layer ==5 + write_uint(buf, 5) # (...) + write_uint(buf, 0) # all datatypes - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'I56A') # name - write_uint(buf, 4) # layer 5 to 6 - write_uint(buf, 5) # (...) - write_uint(buf, 6) # (...) - write_uint(buf, 0) # all datatypes + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'I56A') # name + write_uint(buf, 4) # layer 5 to 6 + write_uint(buf, 5) # (...) + write_uint(buf, 6) # (...) + write_uint(buf, 0) # all datatypes if short: return buf - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'E5L4') # name - write_uint(buf, 3) # layer ==5 - write_uint(buf, 5) # (...) - write_uint(buf, 1) # datatype <=4 - write_uint(buf, 4) # (...) + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'E5L4') # name + write_uint(buf, 3) # layer ==5 + write_uint(buf, 5) # (...) + write_uint(buf, 1) # datatype <=4 + write_uint(buf, 4) # (...) - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'E5H4') # name - write_uint(buf, 3) # layer ==5 - write_uint(buf, 5) # (...) - write_uint(buf, 2) # datatype >=4 - write_uint(buf, 4) # (...) + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'E5H4') # name + write_uint(buf, 3) # layer ==5 + write_uint(buf, 5) # (...) + write_uint(buf, 2) # datatype >=4 + write_uint(buf, 4) # (...) - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'E5E4') # name - write_uint(buf, 3) # layer ==5 - write_uint(buf, 5) # (...) - write_uint(buf, 3) # datatype ==4 - write_uint(buf, 4) # (...) + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'E5E4') # name + write_uint(buf, 3) # layer ==5 + write_uint(buf, 5) # (...) + write_uint(buf, 3) # datatype ==4 + write_uint(buf, 4) # (...) - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'E5I47') # name - write_uint(buf, 3) # layer ==5 - write_uint(buf, 5) # (...) - write_uint(buf, 4) # datatype 4 to 7 - write_uint(buf, 4) # (...) - write_uint(buf, 7) # (...) + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'E5I47') # name + write_uint(buf, 3) # layer ==5 + write_uint(buf, 5) # (...) + write_uint(buf, 4) # datatype 4 to 7 + write_uint(buf, 4) # (...) + write_uint(buf, 7) # (...) return buf @@ -127,7 +121,7 @@ def write_names_text(buf: BufferedIOBase, prefix: bytes = b'') -> BufferedIOBase write_uint(buf, 0) # all datatypes write_uint(buf, 12) # LAYERNAME record (geometry) - write_bstring(buf, prefix + b'I56A') # name + write_bstring(buf, prefix + b'I56A') # name write_uint(buf, 4) # layer 5 to 6 write_uint(buf, 5) # (...) write_uint(buf, 6) # (...) @@ -160,7 +154,8 @@ def write_text(buf: BufferedIOBase) -> BufferedIOBase: def name_test(layers: Sequence, is_textlayer: bool) -> None: for ii, nn in enumerate(layers): - assert is_textlayer == nn.is_textlayer, f'Fail on layername {ii}' + msg = f'Fail on layername {ii}' + assert is_textlayer == nn.is_textlayer, msg assert nn.nstring.string == ['AA', 'L5A', 'H5A', 'E5A', 'I56A', 'E5L4', 'E5H4', 'E5E4', 'E5I47'][ii], msg @@ -172,7 +167,8 @@ def name_test(layers: Sequence, is_textlayer: bool) -> None: def name_test_text(layers: Sequence) -> None: for ii, nn in enumerate(layers): - assert nn.is_textlayer, f'Fail on layername {ii}' + msg = f'Fail on layername {ii}' + assert nn.is_textlayer, msg assert nn.nstring.string == ['TAA', 'TL5A', 'TH5A', 'TE5A', 'TI56A'][ii], msg assert nn.layer_interval[0] == [None, None, 5, 5, 5][ii], msg diff --git a/fatamorgana/test/test_files_modals.py b/fatamorgana/test/test_files_modals.py index 0021bf1..d2417f2 100644 --- a/fatamorgana/test/test_files_modals.py +++ b/fatamorgana/test/test_files_modals.py @@ -1,17 +1,9 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct - -import pytest # type: ignore -import numpy -from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -33,151 +25,151 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0110_0011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 10) # width - write_uint(buf, 20) # height + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0110_0011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 10) # width + write_uint(buf, 20) # height # TEXT 1 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0100_0011) # 0CNX_YRTL - write_bstring(buf, b'A') # text string - write_uint(buf, 2) # layer - write_uint(buf, 1) # datatype + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0100_0011) # 0CNX_YRTL + write_bstring(buf, b'A') # text string + write_uint(buf, 2) # layer + write_uint(buf, 1) # datatype # RECTANGLE 2 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 100) # geometry-x (absolute) - write_sint(buf, -100) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 100) # geometry-x (absolute) + write_sint(buf, -100) # geometry-y (absolute) # TEXT 3 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 100) # text-x (absolute) - write_sint(buf, -100) # text-y (absolute) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 100) # text-x (absolute) + write_sint(buf, -100) # text-y (absolute) # RECTANGLE 4 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 200) # geometry-x (absolute) - write_sint(buf, -200) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 200) # geometry-x (absolute) + write_sint(buf, -200) # geometry-y (absolute) # TEXT 5 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 200) # text-x (absolute) - write_sint(buf, -200) # text-y (absolute) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 200) # text-x (absolute) + write_sint(buf, -200) # text-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # RECTANGLE 6 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 100) # geometry-x (relative) - write_sint(buf, -100) # geometry-y (relative) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 100) # geometry-x (relative) + write_sint(buf, -100) # geometry-y (relative) # TEXT 7 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 100) # text-x (relative) - write_sint(buf, -100) # text-y (relative) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 100) # text-x (relative) + write_sint(buf, -100) # text-y (relative) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'B') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'B') # Cell name # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0110_0011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 20) # width - write_uint(buf, 10) # height + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0110_0011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 20) # width + write_uint(buf, 10) # height # TEXT 1 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0100_0011) # 0CNX_YRTL - write_bstring(buf, b'B') # text string - write_uint(buf, 2) # layer - write_uint(buf, 1) # datatype + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0100_0011) # 0CNX_YRTL + write_bstring(buf, b'B') # text string + write_uint(buf, 2) # layer + write_uint(buf, 1) # datatype # RECTANGLE 2 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 100) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 100) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) # TEXT 3 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 100) # text-x (absolute) - write_sint(buf, 100) # text-y (absolute) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 100) # text-x (absolute) + write_sint(buf, 100) # text-y (absolute) # RECTANGLE 4 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 200) # geometry-x (absolute) - write_sint(buf, 200) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 200) # geometry-x (absolute) + write_sint(buf, 200) # geometry-y (absolute) # TEXT 5 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 200) # text-x (absolute) - write_sint(buf, 200) # text-y (absolute) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 200) # text-x (absolute) + write_sint(buf, 200) # text-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # RECTANGLE 6 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 100) # geometry-x (relative) - write_sint(buf, 100) # geometry-y (relative) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 100) # geometry-x (relative) + write_sint(buf, 100) # geometry-y (relative) # TEXT 7 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 100) # text-x (relative) - write_sint(buf, 100) # text-y (relative) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 100) # text-x (relative) + write_sint(buf, 100) # text-y (relative) # PLACEMENT 0 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b1000_0000) # CNXY_RAAF - write_bstring(buf, b'A') # Cell reference + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b1000_0000) # CNXY_RAAF + write_bstring(buf, b'A') # Cell reference # PLACEMENT 1 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_0000) # CNXY_RAAF - write_sint(buf, 50) # placement-x (relative) - write_sint(buf, 50) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_0000) # CNXY_RAAF + write_sint(buf, 50) # placement-x (relative) + write_sint(buf, 50) # placement-y (relative) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'TOP') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'TOP') # Cell name # PLACEMENT 0 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b1000_0000) # CNXY_RAAF - write_bstring(buf, b'B') # Cell reference + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b1000_0000) # CNXY_RAAF + write_bstring(buf, b'B') # Cell reference # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0110_0011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 50) # width - write_uint(buf, 5) # height + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0110_0011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 50) # width + write_uint(buf, 5) # height # TEXT 1 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0100_0011) # 0CNX_YRTL - write_bstring(buf, b'TOP') # text string - write_uint(buf, 2) # layer - write_uint(buf, 1) # datatype + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0100_0011) # 0CNX_YRTL + write_bstring(buf, b'TOP') # text string + write_uint(buf, 2) # layer + write_uint(buf, 1) # datatype buf.write(FOOTER) return buf diff --git a/fatamorgana/test/test_files_paths.py b/fatamorgana/test/test_files_paths.py index a359817..8fb2cc0 100644 --- a/fatamorgana/test/test_files_paths.py +++ b/fatamorgana/test/test_files_paths.py @@ -1,17 +1,11 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore -import numpy from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte, PathExtensionScheme from ..main import OasisLayout @@ -37,108 +31,108 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'ABC') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'ABC') # Cell name # PATH 0 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b1111_1011) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 10) # half-width - write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE - write_sint(buf, 5) # (extension-scheme) start - write_sint(buf, -5) # (extension-scheme) end - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 0) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b1111_1011) # EWPX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 10) # half-width + write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE + write_sint(buf, 5) # (extension-scheme) start + write_sint(buf, -5) # (extension-scheme) end + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 0) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PATH 1 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b1110_1011) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 10) # half-width - write_byte(buf, 0b0000_0000) # extension-scheme 0000_SSEE - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b1110_1011) # EWPX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 10) # half-width + write_byte(buf, 0b0000_0000) # extension-scheme 0000_SSEE + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 200) # geometry-y (relative) # PATH 2 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b1110_1001) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 10) # half-width - write_byte(buf, 0b0000_0100) # extension-scheme 0000_SSEE - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b1110_1001) # EWPX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 10) # half-width + write_byte(buf, 0b0000_0100) # extension-scheme 0000_SSEE + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 200) # geometry-y (relative) # PATH 3 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b1110_1010) # EWPX_YRDL - write_uint(buf, 2) # datatype - write_uint(buf, 12) # half-width - write_byte(buf, 0b0000_0101) # extension-scheme 0000_SSEE - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b1110_1010) # EWPX_YRDL + write_uint(buf, 2) # datatype + write_uint(buf, 12) # half-width + write_byte(buf, 0b0000_0101) # extension-scheme 0000_SSEE + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 200) # geometry-y (relative) # PATH 4 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b1010_1011) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_byte(buf, 0b0000_1010) # extension-scheme 0000_SSEE - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b1010_1011) # EWPX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_byte(buf, 0b0000_1010) # extension-scheme 0000_SSEE + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 200) # geometry-y (relative) # PATH 5 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b0000_1011) # EWPX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b0000_1011) # EWPX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_sint(buf, 200) # geometry-y (relative) # PATH 6 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b0000_1111) # EWPX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_sint(buf, 200) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 22) # PATH record + write_byte(buf, 0b0000_1111) # EWPX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PATH 7 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b0001_0101) # EWPX_YRDL - write_uint(buf, 1) # layer - write_sint(buf, 1000) # geometry-x (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b0001_0101) # EWPX_YRDL + write_uint(buf, 1) # layer + write_sint(buf, 1000) # geometry-x (relative) + write_uint(buf, 0) # repetition (reuse) buf.write(FOOTER) return buf diff --git a/fatamorgana/test/test_files_placements.py b/fatamorgana/test/test_files_placements.py index 5059be9..390876e 100644 --- a/fatamorgana/test/test_files_placements.py +++ b/fatamorgana/test/test_files_placements.py @@ -1,17 +1,11 @@ # type: ignore - -from typing import List, Tuple, Iterable -from itertools import chain +from typing import Tuple from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore -import numpy from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError, write_float32, write_float64 +from ..basic import write_uint, write_sint, write_bstring, write_byte, write_float32, write_float64 from ..main import OasisLayout @@ -28,14 +22,14 @@ def base_tests(layout: OasisLayout) -> None: def write_rectangle(buf: BufferedIOBase, pos: Tuple[int, int] = (300, -400)) -> None: - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, pos[0]) # geometry-x (absolute) - write_sint(buf, pos[1]) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, pos[0]) # geometry-x (absolute) + write_sint(buf, pos[1]) # geometry-y (absolute) def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: @@ -43,120 +37,120 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name write_rectangle(buf) - write_uint(buf, 14) # CELL record (explicit) + write_uint(buf, 14) # CELL record (explicit) write_bstring(buf, b'TOP') # Cell name - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 0 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b1011_0000) # CNXY_RAAF - write_bstring(buf, b'A') # cell reference - write_sint(buf, -300) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b1011_0000) # CNXY_RAAF + write_bstring(buf, b'A') # cell reference + write_sint(buf, -300) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 1 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_0000) # CNXY_RAAF - write_sint(buf, 0) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_0000) # CNXY_RAAF + write_sint(buf, 0) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 2 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0000) # CNXY_RAAF - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0000) # CNXY_RAAF + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 3 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0010_0000) # CNXY_RAAF - write_sint(buf, 300) # placement-x (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0010_0000) # CNXY_RAAF + write_sint(buf, 300) # placement-x (relative) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 4 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_0001) # CNXY_RAAF - write_sint(buf, 700) # placement-x (absolute) - write_sint(buf, 400) # placement-y (absolute) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_0001) # CNXY_RAAF + write_sint(buf, 700) # placement-x (absolute) + write_sint(buf, 400) # placement-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 5 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0010) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0010) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) # PLACEMENT 6 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0011) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0011) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 7 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (absolute) - write_sint(buf, 0) # placement-y (absolute) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 300) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (absolute) + write_sint(buf, 0) # placement-y (absolute) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 300) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 8 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 0) # repetition (reuse) # PLACEMENT 9 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 2) # repetition (3 cols.) - write_uint(buf, 1) # (repetition) count - write_uint(buf, 320) # (repetition) spacing + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 2) # repetition (3 cols.) + write_uint(buf, 1) # (repetition) count + write_uint(buf, 320) # (repetition) spacing # PLACEMENT 10 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 3) # repetition (4 rows) - write_uint(buf, 2) # (repetition) count - write_uint(buf, 310) # (repetition) spacing + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 3) # repetition (4 rows) + write_uint(buf, 2) # (repetition) count + write_uint(buf, 310) # (repetition) spacing # PLACEMENT 11 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 4) # repetition (4 arbitrary cols.) - write_uint(buf, 2) # (repetition) dimension - write_uint(buf, 320) # (repetition) spacing - write_uint(buf, 330) # (repetition) spacing - write_uint(buf, 340) # (repetition) spacing + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 4) # repetition (4 arbitrary cols.) + write_uint(buf, 2) # (repetition) dimension + write_uint(buf, 320) # (repetition) spacing + write_uint(buf, 330) # (repetition) spacing + write_uint(buf, 340) # (repetition) spacing # PLACEMENT 12 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 8) # repetition (3x4 matrix, arbitrary vectors) - write_uint(buf, 1) # (repetition) n-dimension - write_uint(buf, 2) # (repetition) m-dimension - write_uint(buf, 310 << 2 | 0b01) # (repetition) n-displacement g-delta: (310, 320) - write_sint(buf, 320) # (repetition g-delta) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 8) # repetition (3x4 matrix, arbitrary vectors) + write_uint(buf, 1) # (repetition) n-dimension + write_uint(buf, 2) # (repetition) m-dimension + write_uint(buf, 310 << 2 | 0b01) # (repetition) n-displacement g-delta: (310, 320) + write_sint(buf, 320) # (repetition g-delta) write_uint(buf, 330 << 4 | 0b1010) # (repetition) m-displacement g-delta: 330-northwest (-330, 330) buf.write(FOOTER) @@ -211,9 +205,9 @@ def test_file_1() -> None: assert pp.y == 0, msg if ii < 4 or ii == 5: - assert pp.flip == False, msg + assert not bool(pp.flip), msg else: - assert pp.flip == True, msg + assert bool(pp.flip), msg if ii < 5: assert pp.angle == 0, msg @@ -286,49 +280,49 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: # PLACEMENT 0 write_uint(buf, 17) # PLACEMENT (simple) if variant == 2: - write_byte(buf, 0b1011_0000) # CNXY_RAAF - write_bstring(buf, b'A') # cell reference + write_byte(buf, 0b1011_0000) # CNXY_RAAF + write_bstring(buf, b'A') # cell reference else: - write_byte(buf, 0b1111_0000) # CNXY_RAAF - write_uint(buf, 0) # cell reference - write_sint(buf, -300) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) + write_byte(buf, 0b1111_0000) # CNXY_RAAF + write_uint(buf, 0) # cell reference + write_sint(buf, -300) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 1 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_0000) # CNXY_RAAF - write_sint(buf, 0) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_0000) # CNXY_RAAF + write_sint(buf, 0) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 2 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0000) # CNXY_RAAF - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0000) # CNXY_RAAF + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 3 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0010_0000) # CNXY_RAAF - write_sint(buf, 300) # placement-x (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0010_0000) # CNXY_RAAF + write_sint(buf, 300) # placement-x (relative) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 4 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_0001) # CNXY_RAAF - write_sint(buf, 700) # placement-x (absolute) - write_sint(buf, 400) # placement-y (absolute) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_0001) # CNXY_RAAF + write_sint(buf, 700) # placement-x (absolute) + write_sint(buf, 400) # placement-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 5 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0010) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0010) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) # PLACEMENT 6 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0011) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0011) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) if variant == 2: write_uint(buf, 14) # CELL record (explicit) @@ -502,9 +496,9 @@ def common_tests(layout: OasisLayout, variant: int) -> None: assert pp.y == 400 * (ii + 1), msg if ii in (4, 6): - assert pp.flip == True, msg + assert bool(pp.flip), msg else: - assert pp.flip == False, msg + assert not bool(pp.flip), msg if ii in (5, 6): assert pp.angle == 90, msg @@ -525,73 +519,73 @@ def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 3) # CELLNAME record (implicit id 0) + write_uint(buf, 3) # CELLNAME record (implicit id 0) write_bstring(buf, b'A') - write_uint(buf, 3) # CELLNAME record (implicit id 1) + write_uint(buf, 3) # CELLNAME record (implicit id 1) write_bstring(buf, b'TOP') - write_uint(buf, 13) # CELL record (name ref.) - write_uint(buf, 1) # Cell name 1 (TOP) + write_uint(buf, 13) # CELL record (name ref.) + write_uint(buf, 1) # Cell name 1 (TOP) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 0 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b1111_1000) # CNXY_RAAF - write_uint(buf, 0) # cell reference - write_sint(buf, -300) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 20) # (repetition) x-spacing - write_uint(buf, 30) # (repetition) y-spacing + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b1111_1000) # CNXY_RAAF + write_uint(buf, 0) # cell reference + write_sint(buf, -300) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 20) # (repetition) x-spacing + write_uint(buf, 30) # (repetition) y-spacing # PLACEMENT 1 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1000) # CNXY_RAAF - write_sint(buf, 0) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1000) # CNXY_RAAF + write_sint(buf, 0) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 0) # repetition (reuse) # PLACEMENT 2 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_1000) # CNXY_RAAF - write_sint(buf, 400) # placement-y (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_1000) # CNXY_RAAF + write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 0) # repetition (reuse) # PLACEMENT 3 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0010_1000) # CNXY_RAAF - write_sint(buf, 300) # placement-x (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0010_1000) # CNXY_RAAF + write_sint(buf, 300) # placement-x (relative) + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 4 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1001) # CNXY_RAAF - write_sint(buf, 700) # placement-x (absolute) - write_sint(buf, 400) # placement-y (absolute) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1001) # CNXY_RAAF + write_sint(buf, 700) # placement-x (absolute) + write_sint(buf, 400) # placement-y (absolute) + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 5 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_1010) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_1010) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 0) # repetition (reuse) # PLACEMENT 6 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_1011) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_1011) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 13) # CELL record (name ref.) - write_uint(buf, 0) # Cell name 0 (A) + write_uint(buf, 13) # CELL record (name ref.) + write_uint(buf, 0) # Cell name 0 (A) write_rectangle(buf) @@ -604,84 +598,84 @@ def write_file_6(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'TOPTOP') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'TOPTOP') # Cell name - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record - write_uint(buf, 18) # PLACEMENT (mag 0.5, manhattan) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'TOP') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 0.5) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 90.0) # (angle) - write_sint(buf, 100) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (mag 0.5, manhattan) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'TOP') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 0.5) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 90.0) # (angle) + write_sint(buf, 100) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0011_0000) # CNXY_RMAF - write_sint(buf, 100) # placement-x (relative) - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0011_0000) # CNXY_RMAF + write_sint(buf, 100) # placement-x (relative) + write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'TOP') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'TOP') # Cell name - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 0 - write_uint(buf, 18) # PLACEMENT (mag 0.5, manhattan) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'A') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 0.5) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 0.0) # (angle) - write_sint(buf, -150) # placement-x (relative) - write_sint(buf, 200) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (mag 0.5, manhattan) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'A') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 0.5) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 0.0) # (angle) + write_sint(buf, -150) # placement-x (relative) + write_sint(buf, 200) # placement-y (relative) # PLACEMENT 1 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0011_0000) # CNXY_RMAF - write_sint(buf, -150) # placement-x (relative) - write_sint(buf, 600) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0011_0000) # CNXY_RMAF + write_sint(buf, -150) # placement-x (relative) + write_sint(buf, 600) # placement-y (relative) # PLACEMENT 2 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0001_0000) # CNXY_RMAF - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0001_0000) # CNXY_RMAF + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 3 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0010_0000) # CNXY_RMAF - write_sint(buf, 300) # placement-x (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0010_0000) # CNXY_RMAF + write_sint(buf, 300) # placement-x (relative) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 4 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0011_0001) # CNXY_RMAF - write_sint(buf, 700) # placement-x (absolute) - write_sint(buf, 400) # placement-y (absolute) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0011_0001) # CNXY_RMAF + write_sint(buf, 700) # placement-x (absolute) + write_sint(buf, 400) # placement-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 5 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0001_0010) # CNXY_RMAF - write_uint(buf, 0) # angle (uint, positive) - write_uint(buf, 90) # (angle) - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0001_0010) # CNXY_RMAF + write_uint(buf, 0) # angle (uint, positive) + write_uint(buf, 90) # (angle) + write_sint(buf, 1000) # placement-y (relative) # PLACEMENT 6 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0001_0011) # CNXY_RMAF - write_uint(buf, 1) # angle (uint, negative) - write_uint(buf, 90) # (angle) - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0001_0011) # CNXY_RMAF + write_uint(buf, 1) # angle (uint, negative) + write_uint(buf, 90) # (angle) + write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name write_rectangle(buf) @@ -757,71 +751,71 @@ def write_file_8(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'TOPTOP') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'TOPTOP') # Cell name - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record - write_uint(buf, 18) # PLACEMENT (mag 0.5, arbitrary angle) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'TOP') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 0.5) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 22.5) # (angle) - write_sint(buf, 100) # placement-x (absolute) - write_sint(buf, 0) # placement-y (absolute) + write_uint(buf, 18) # PLACEMENT (mag 0.5, arbitrary angle) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'TOP') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 0.5) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 22.5) # (angle) + write_sint(buf, 100) # placement-x (absolute) + write_sint(buf, 0) # placement-y (absolute) - write_uint(buf, 18) # PLACEMENT (mag 1.0, manhattan) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'TOP') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 1.0) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 0.0) # (angle) - write_sint(buf, 1100) # placement-x (absolute) - write_sint(buf, 0) # placement-y (absolute) + write_uint(buf, 18) # PLACEMENT (mag 1.0, manhattan) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'TOP') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 1.0) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 0.0) # (angle) + write_sint(buf, 1100) # placement-x (absolute) + write_sint(buf, 0) # placement-y (absolute) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'TOP') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'TOP') # Cell name - write_uint(buf, 18) # PLACEMENT (mag 2.0, manhattan) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'A') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 2.0) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 0.0) # (angle) - write_sint(buf, -100) # placement-x (absolute) - write_sint(buf, 100) # placement-y (absolute) + write_uint(buf, 18) # PLACEMENT (mag 2.0, manhattan) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'A') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 2.0) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 0.0) # (angle) + write_sint(buf, -100) # placement-x (absolute) + write_sint(buf, 100) # placement-y (absolute) - write_uint(buf, 18) # PLACEMENT (mag 1.0, arbitrary angle) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'A') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 1.0) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 45.0) # (angle) - write_sint(buf, -150) # placement-x (absolute) - write_sint(buf, 1100) # placement-y (absolute) + write_uint(buf, 18) # PLACEMENT (mag 1.0, arbitrary angle) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'A') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 1.0) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 45.0) # (angle) + write_sint(buf, -150) # placement-x (absolute) + write_sint(buf, 1100) # placement-y (absolute) - write_uint(buf, 18) # PLACEMENT (mag 0.5, arbitrary angle) - write_byte(buf, 0b1011_1111) # CNXY_RMAF - write_bstring(buf, b'A') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 0.5) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 135.0) # (angle) - write_sint(buf, -200) # placement-x (absolute) - write_sint(buf, 2100) # placement-y (absolute) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 18) # PLACEMENT (mag 0.5, arbitrary angle) + write_byte(buf, 0b1011_1111) # CNXY_RMAF + write_bstring(buf, b'A') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 0.5) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 135.0) # (angle) + write_sint(buf, -200) # placement-x (absolute) + write_sint(buf, 2100) # placement-y (absolute) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name write_rectangle(buf, pos=(30, -40)) diff --git a/fatamorgana/test/test_files_polygons.py b/fatamorgana/test/test_files_polygons.py index fc5d0c2..2deb808 100644 --- a/fatamorgana/test/test_files_polygons.py +++ b/fatamorgana/test/test_files_polygons.py @@ -1,17 +1,12 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore import numpy from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -85,8 +80,11 @@ def common_tests(layout: OasisLayout) -> None: for ii in range(4): msg = f'Fail on poly {ii}' assert len(geometry[0].point_list) == 6, msg - assert_equal(geometry[0].point_list, [[150, 0], [0, 50], [-50, 0], [0, 50], - [-100, 0], [0, -100]], err_msg=msg) + assert_equal( + geometry[0].point_list, + [[150, 0], [0, 50], [-50, 0], [0, 50], [-100, 0], [0, -100]], + err_msg=msg, + ) assert len(geometry[4].point_list) == 6 assert_equal(geometry[4].point_list, [[0, 150], [50, 0], [0, -50], [50, 0], [0, -100], [-100, 0]]) @@ -97,8 +95,10 @@ def common_tests(layout: OasisLayout) -> None: assert len(geometry[7].point_list) == 9 assert_equal(geometry[7].point_list, [[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25], [40, 0]]) assert len(geometry[8].point_list) == 9 - assert_equal(geometry[8].point_list, - numpy.cumsum([[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25], [45, -575]], axis=0)) + assert_equal( + geometry[8].point_list, + numpy.cumsum([[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25], [45, -575]], axis=0), + ) for ii in range(9, 12): msg = f'Fail on poly {ii}' @@ -114,49 +114,49 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: buf.write(HEADER) if variant == 3: - write_uint(buf, 7) # PROPNAME record (implict id 0) - write_bstring(buf, b'PROP0') # property name + write_uint(buf, 7) # PROPNAME record (implict id 0) + write_bstring(buf, b'PROP0') # property name - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'ABC') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'ABC') # Cell name # POLYGON 0 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_1011) # 00PX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 0) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_1011) # 00PX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 0) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) if variant == 3: # PROPERTY 0 - write_uint(buf, 28) # PROPERTY record (explicit) - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 2) # property value (real: positive reciprocal) - write_uint(buf, 5) # (real) 1/5 + write_uint(buf, 28) # PROPERTY record (explicit) + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 2) # property value (real: positive reciprocal) + write_uint(buf, 5) # (real) 1/5 write_uint(buf, 16) # XYRELATIVE record # Polygon 1 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_1011) # 00PX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -200) # geometry-x (relative) - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_1011) # 00PX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -200) # geometry-x (relative) + write_sint(buf, 300) # geometry-y (relative) if variant == 3: # PROPERTY 1 @@ -165,55 +165,55 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 15) # XYABSOLUTE record # Polygon 2 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 0) # geometry-x (absolute) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 0) # geometry-x (absolute) if variant == 3: # PROPERTY 2 write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 3 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0000_1000) # 00PX_YRDL - write_sint(buf, 1000) # geometry-y (absolute) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0000_1000) # 00PX_YRDL + write_sint(buf, 1000) # geometry-y (absolute) if variant == 3: # PROPERTY 3 write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 4 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 1) # pointlist: 1-delta, vert-fisrt - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 200) # geometry-x (absolute) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 1) # pointlist: 1-delta, vert-fisrt + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 200) # geometry-x (absolute) if variant == 3: # PROPERTY 4 write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 5 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 2) # pointlist: 2-delta - write_uint(buf, 7) # (pointlist) dimension + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 2) # pointlist: 2-delta + write_uint(buf, 7) # (pointlist) dimension write_uint(buf, 150 << 2 | 0b00) # (pointlist) write_uint(buf, 50 << 2 | 0b01) # (pointlist) write_uint(buf, 50 << 2 | 0b10) # (pointlist) @@ -228,12 +228,12 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 6 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 3) # pointlist: 3-delta - write_uint(buf, 8) # (pointlist) dimension + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 3) # pointlist: 3-delta + write_uint(buf, 8) # (pointlist) dimension write_uint(buf, 25 << 3 | 0b000) # (pointlist) write_uint(buf, 50 << 3 | 0b100) # (pointlist) write_uint(buf, 50 << 3 | 0b001) # (pointlist) @@ -249,12 +249,12 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 7 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 4) # pointlist: g-delta - write_uint(buf, 8) # (pointlist) dimension + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 4) # pointlist: g-delta + write_uint(buf, 8) # (pointlist) dimension write_uint(buf, 25 << 4 | 0b0000) # (pointlist) write_uint(buf, 50 << 4 | 0b1000) # (pointlist) write_uint(buf, 50 << 4 | 0b0010) # (pointlist) @@ -263,7 +263,7 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 50 << 4 | 0b0100) # (pointlist) write_uint(buf, 50 << 4 | 0b1100) # (pointlist) write_uint(buf, 10 << 2 | 0b01) # (pointlist) - write_sint(buf, -75 ) + write_sint(buf, -75) write_uint(buf, 25 << 4 | 0b1110) # (pointlist) write_sint(buf, 900) # geometry-x (absolute) @@ -272,12 +272,12 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 8 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 5) # pointlist: double g-delta - write_uint(buf, 8) # (pointlist) dimension + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 5) # pointlist: double g-delta + write_uint(buf, 8) # (pointlist) dimension write_uint(buf, 25 << 4 | 0b0000) # (pointlist) write_uint(buf, 50 << 4 | 0b1000) # (pointlist) write_uint(buf, 50 << 4 | 0b0010) # (pointlist) @@ -286,7 +286,7 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 50 << 4 | 0b0100) # (pointlist) write_uint(buf, 50 << 4 | 0b1100) # (pointlist) write_uint(buf, 10 << 2 | 0b01) # (pointlist) - write_sint(buf, -75 ) + write_sint(buf, -75) write_uint(buf, 25 << 4 | 0b1110) # (pointlist) write_sint(buf, 1100) # geometry-x (absolute) @@ -295,62 +295,62 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 9 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_1111) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 1) # pointlist: 1-delta (vert. first) - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 0) # geometry-x (absolute) - write_sint(buf, 2000) # geometry-y (absolute) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_1111) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 1) # pointlist: 1-delta (vert. first) + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 0) # geometry-x (absolute) + write_sint(buf, 2000) # geometry-y (absolute) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing if variant == 3: # PROPERTY 9 write_uint(buf, 29) # PROPERTY record (repeat) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # Polygon 10 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0110) # 00PX_YRDL - write_uint(buf, 1) # datatype - write_uint(buf, 1) # pointlist: 1-delta (vert. first) - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 1000) # geometry-x (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0110) # 00PX_YRDL + write_uint(buf, 1) # datatype + write_uint(buf, 1) # pointlist: 1-delta (vert. first) + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 1000) # geometry-x (relative) + write_uint(buf, 0) # repetition (reuse) if variant == 3: # PROPERTY 10 write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 11 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0110) # 00PX_YRDL - write_uint(buf, 1) # datatype - write_uint(buf, 1) # pointlist: 1-delta (vert. first) - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 1000) # geometry-x (relative) - write_uint(buf, 6) # repetition (3 rows) - write_uint(buf, 1) # (repetition) dimension - write_uint(buf, 200) # (repetition) y-delta - write_uint(buf, 300) # (repetition) y-delta + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0110) # 00PX_YRDL + write_uint(buf, 1) # datatype + write_uint(buf, 1) # pointlist: 1-delta (vert. first) + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 1000) # geometry-x (relative) + write_uint(buf, 6) # repetition (3 rows) + write_uint(buf, 1) # (repetition) dimension + write_uint(buf, 200) # (repetition) y-delta + write_uint(buf, 300) # (repetition) y-delta if variant == 3: # PROPERTY 11 @@ -386,21 +386,21 @@ def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: write_uint(buf, 15) # XYRELATIVE record # POLYGON 0 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 4) # pointlist: g-delta - write_uint(buf, 8002) # (pointlist) dimension - write_uint(buf, 1000 << 2 | 0b11) # (pointlist) - write_sint(buf, 0) # (pointlist) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 4) # pointlist: g-delta + write_uint(buf, 8002) # (pointlist) dimension + write_uint(buf, 1000 << 2 | 0b11) # (pointlist) + write_sint(buf, 0) # (pointlist) for _ in range(4000): - write_uint(buf, 10 << 2 | 0b01) # (pointlist) - write_sint(buf, 20) # (pointlist) - write_uint(buf, 10 << 2 | 0b11) # (pointlist) - write_sint(buf, 20) # (pointlist) - write_uint(buf, 1000 << 2 | 0b01) # (pointlist) - write_sint(buf, 0) # (pointlist) + write_uint(buf, 10 << 2 | 0b01) # (pointlist) + write_sint(buf, 20) # (pointlist) + write_uint(buf, 10 << 2 | 0b11) # (pointlist) + write_sint(buf, 20) # (pointlist) + write_uint(buf, 1000 << 2 | 0b01) # (pointlist) + write_sint(buf, 0) # (pointlist) write_sint(buf, 0) # geometry-x (absolute) buf.write(FOOTER) @@ -425,7 +425,8 @@ def test_file_2() -> None: assert_equal(poly.point_list, ([[-1000, 0]] + [[(-1) ** nn * 10, 20] for nn in range(8000)] - + [[1000, 0], [0, -20 * 8000]])) + + [[1000, 0], [0, -20 * 8000]]), + ) def test_file_3() -> None: diff --git a/fatamorgana/test/test_files_properties.py b/fatamorgana/test/test_files_properties.py index a49d7e1..107b64a 100644 --- a/fatamorgana/test/test_files_properties.py +++ b/fatamorgana/test/test_files_properties.py @@ -1,17 +1,13 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore -import numpy +import pytest from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte +from ..basic import InvalidDataError from ..main import OasisLayout @@ -54,7 +50,6 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 7) # PROPNAME record (implicit id 1) write_bstring(buf, b'PROP1') - write_uint(buf, 14) # CELL record (explicit) write_bstring(buf, b'A') # Cell name @@ -74,11 +69,29 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 300) # (repetition) x-spacing write_uint(buf, 320) # (repetition) y-spacing - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_0100) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_0100) # UUUU_VCNS write_bstring(buf, b'PROPX') # RECTANGLE 1 + write_uint(buf, 20) # RECTANGLE record + var_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) + if include_repetitions: + write_uint(buf, 0) # repetition (reuse) + + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 1) # property value 0 (real type 1, negative int) + write_uint(buf, 5) # (real 1) + + # RECTANGLE 2 write_uint(buf, 20) # RECTANGLE record var_byte(buf, 0b0111_1011) # SWHX_YRDL write_uint(buf, 1) # layer @@ -90,60 +103,20 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: if include_repetitions: write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 1) # property value 0 (real type 1, negative int) - write_uint(buf, 5) # (real 1) - - # RECTANGLE 2 - write_uint(buf, 20) # RECTANGLE record - var_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) - if include_repetitions: - write_uint(buf, 0) # repetition (reuse) - - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0100_0110) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 8) # prop value 0 (unsigned int) - write_uint(buf, 25) # (prop value) - write_uint(buf, 9) # prop value 1 (signed int) - write_sint(buf, -124) # (prop value) - write_uint(buf, 10) # prop value 2 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0100_0110) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 8) # prop value 0 (unsigned int) + write_uint(buf, 25) # (prop value) + write_uint(buf, 9) # prop value 1 (signed int) + write_sint(buf, -124) # (prop value) + write_uint(buf, 10) # prop value 2 (a-string) write_bstring(buf, b'PROP_VALUE2') - write_uint(buf, 13) # prop value 3 (propstring ref.) + write_uint(buf, 13) # prop value 3 (propstring ref.) write_uint(buf, 12) # RECTANGLE 3 write_uint(buf, 20) # RECTANGLE record - var_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) - if include_repetitions: - write_uint(buf, 0) # repetition (reuse) - - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b1111_0000) # UUUU_VCNS - write_uint(buf, 3) # number of values - write_uint(buf, 0) # prop value 0 (unsigned int) - write_uint(buf, 25) # (prop value) - write_uint(buf, 9) # prop value 1 (signed int) - write_sint(buf, -124) # (prop value) - write_uint(buf, 14) # prop value 2 (propstring ref.) - write_uint(buf, 13) - - # RECTANGLE 4 - write_uint(buf, 20) # RECTANGLE record var_byte(buf, 0b0111_1011) # SWHX_YRDL write_uint(buf, 1) # layer write_uint(buf, 2) # datatype @@ -154,14 +127,36 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: if include_repetitions: write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_1000) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b1111_0000) # UUUU_VCNS + write_uint(buf, 3) # number of values + write_uint(buf, 0) # prop value 0 (unsigned int) + write_uint(buf, 25) # (prop value) + write_uint(buf, 9) # prop value 1 (signed int) + write_sint(buf, -124) # (prop value) + write_uint(buf, 14) # prop value 2 (propstring ref.) + write_uint(buf, 13) - write_uint(buf, 15) # XYABSOLUTE record + # RECTANGLE 4 + write_uint(buf, 20) # RECTANGLE record + var_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) + if include_repetitions: + write_uint(buf, 0) # repetition (reuse) + + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_1000) # UUUU_VCNS + + write_uint(buf, 15) # XYABSOLUTE record # TEXT 5 write_uint(buf, 19) # TEXT record - var_byte(buf, 0b0101_1011) # 0CNX_YRTL + var_byte(buf, 0b0101_1011) # 0CNX_YRTL write_bstring(buf, b'A') # text-string write_uint(buf, 2) # text-layer write_uint(buf, 1) # text-datatype @@ -173,47 +168,47 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 29) # PROPERTY (reuse) # PATH 6 - write_uint(buf, 22) # PATH record - var_byte(buf, 0b1111_1011) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 10) # half-width - write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE - write_sint(buf, 5) # (extension-scheme) - write_sint(buf, -5) # (extension-scheme) - write_uint(buf, 0) # pointlist (1-delta, horiz. first) - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 2000) # geometry-x (absolute) - write_sint(buf, 0) # geometry-y (absolute) + write_uint(buf, 22) # PATH record + var_byte(buf, 0b1111_1011) # EWPX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 10) # half-width + write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE + write_sint(buf, 5) # (extension-scheme) + write_sint(buf, -5) # (extension-scheme) + write_uint(buf, 0) # pointlist (1-delta, horiz. first) + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 2000) # geometry-x (absolute) + write_sint(buf, 0) # geometry-y (absolute) if include_repetitions: - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # POLYGON 7 - write_uint(buf, 21) # POLYGON record - var_byte(buf, 0b0011_1011) # 00PX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 0) # pointlist (1-delta, horiz. first) - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 3000) # geometry-x (absolute) - write_sint(buf, 0) # geometry-y (absolute) + write_uint(buf, 21) # POLYGON record + var_byte(buf, 0b0011_1011) # 00PX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 0) # pointlist (1-delta, horiz. first) + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 3000) # geometry-x (absolute) + write_sint(buf, 0) # geometry-y (absolute) if include_repetitions: - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_0110) # UUUU_VCNS - write_uint(buf, 1) # propname id + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_0110) # UUUU_VCNS + write_uint(buf, 1) # propname id if variant == 5: write_uint(buf, 10) # PROPSTRING (explicit id) @@ -375,141 +370,141 @@ def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: write_uint(buf, 7) # PROPNAME record (implicit id 0) write_bstring(buf, b'S_GDS_PROPERTY') - + # ** CELL ** write_uint(buf, 14) # CELL record (explicit) write_bstring(buf, b'A') # Cell name write_uint(buf, 16) # XYRELATIVE record # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0010_0111) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 8) # property value 0 (unsigned int) - write_uint(buf, 25) # (...) - write_uint(buf, 10) # property value 1 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0010_0111) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 8) # property value 0 (unsigned int) + write_uint(buf, 25) # (...) + write_uint(buf, 10) # property value 1 (a-string) write_bstring(buf, b'PROP_VALUE2') # RECTANGLE 1 - write_uint(buf, 20) # RECTANGLE record + write_uint(buf, 20) # RECTANGLE record write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b1111_0001) # UUUU_VCNS - write_uint(buf, 2) # number of values - write_uint(buf, 8) # property value 0 (unsigned int) - write_uint(buf, 10) # (...) - write_uint(buf, 14) # property value 1 (prop-string ref.) - write_uint(buf, 13) # (...) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b1111_0001) # UUUU_VCNS + write_uint(buf, 2) # number of values + write_uint(buf, 8) # property value 0 (unsigned int) + write_uint(buf, 10) # (...) + write_uint(buf, 14) # property value 1 (prop-string ref.) + write_uint(buf, 13) # (...) # RECTANGLE 2 - write_uint(buf, 20) # RECTANGLE record + write_uint(buf, 20) # RECTANGLE record write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_1001) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_1001) # UUUU_VCNS # RECTANGLE 3 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # RECTANGLE 4 - write_uint(buf, 20) # RECTANGLE record + write_uint(buf, 20) # RECTANGLE record write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_1001) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_1001) # UUUU_VCNS - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0010_0111) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 8) # prop value 0 (unsigned int) - write_uint(buf, 25) # (...) - write_uint(buf, 10) # prop-value 1 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0010_0111) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 8) # prop value 0 (unsigned int) + write_uint(buf, 25) # (...) + write_uint(buf, 10) # prop-value 1 (a-string) write_bstring(buf, b'PROP_VALUE2') # (...) write_uint(buf, 15) # XYABSOLUTE record # TEXT 5 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0101_1011) # 0CNX_YRTL - write_bstring(buf, b'A') # text-string - write_uint(buf, 2) # text-layer - write_uint(buf, 1) # text-datatype - write_sint(buf, 1000) # geometry-x (absolute) - write_sint(buf, 0) # geometry-y (absolute) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0101_1011) # 0CNX_YRTL + write_bstring(buf, b'A') # text-string + write_uint(buf, 2) # text-layer + write_uint(buf, 1) # text-datatype + write_sint(buf, 1000) # geometry-x (absolute) + write_sint(buf, 0) # geometry-y (absolute) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # PATH 6 - write_uint(buf, 22) # PATH record + write_uint(buf, 22) # PATH record write_byte(buf, 0b1111_1011) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 10) # half-width - write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE - write_sint(buf, 5) # (extension-scheme) - write_sint(buf, -5) # (extension-scheme) - write_uint(buf, 0) # pointlist (1-delta, horiz. first) - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 2000) # geometry-x (absolute) - write_sint(buf, 0) # geometry-y (absolute) + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 10) # half-width + write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE + write_sint(buf, 5) # (extension-scheme) + write_sint(buf, -5) # (extension-scheme) + write_uint(buf, 0) # pointlist (1-delta, horiz. first) + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 2000) # geometry-x (absolute) + write_sint(buf, 0) # geometry-y (absolute) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # POLYGON 7 - write_uint(buf, 21) # POLYGON record + write_uint(buf, 21) # POLYGON record write_byte(buf, 0b0011_1011) # 00PX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 0) # pointlist (1-delta, horiz. first) - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 3000) # geometry-x (absolute) - write_sint(buf, 0) # geometry-y (absolute) + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 0) # pointlist (1-delta, horiz. first) + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 3000) # geometry-x (absolute) + write_sint(buf, 0) # geometry-y (absolute) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) buf.write(FOOTER) return buf @@ -605,180 +600,180 @@ def write_file_4_6(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_bstring(buf, b'A') # Cell name # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 300) # geometry-x (relative) - write_sint(buf, -400) # geometry-y (relative) - + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 300) # geometry-x (relative) + write_sint(buf, -400) # geometry-y (relative) + # ** CELL ** write_uint(buf, 14) # CELL record (explicit) write_bstring(buf, b'TOP') # Cell name # PLACEMENT 0 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b1011_0000) # CNXY_RAAF - write_bstring(buf, b'A') # cell name - write_sint(buf, -300) # placement-x - write_sint(buf, 400) # placement-y + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b1011_0000) # CNXY_RAAF + write_bstring(buf, b'A') # cell name + write_sint(buf, -300) # placement-x + write_sint(buf, 400) # placement-y - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0010_0111) # UUUU_VCNS - write_uint(buf, 0) # propname-id - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 25) # (...) - write_uint(buf, 10) # prop-value 1 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0010_0111) # UUUU_VCNS + write_uint(buf, 0) # propname-id + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 25) # (...) + write_uint(buf, 10) # prop-value 1 (a-string) write_bstring(buf, b'PROP_VALUE2') if variant == 6: - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0010_0111) # UUUU_VCNS - write_uint(buf, 0) # propname-id - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 26) # (...) - write_uint(buf, 10) # prop-value 1 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0010_0111) # UUUU_VCNS + write_uint(buf, 0) # propname-id + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 26) # (...) + write_uint(buf, 10) # prop-value 1 (a-string) write_bstring(buf, b'PROP_VALUE26') # PLACEMENT 1 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_0000) # CNXY_RAAF - write_sint(buf, 0) # placement-x + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_0000) # CNXY_RAAF + write_sint(buf, 0) # placement-x if variant == 4: write_sint(buf, 200) # placement-y else: write_sint(buf, 400) # placement-y - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b1111_0001) # UUUU_VCNS - write_uint(buf, 2) # number of values - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 10) # (...) - write_uint(buf, 14) # prop-value 1 (prop-string ref.) - write_uint(buf, 13) # (...) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b1111_0001) # UUUU_VCNS + write_uint(buf, 2) # number of values + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 10) # (...) + write_uint(buf, 14) # prop-value 1 (prop-string ref.) + write_uint(buf, 13) # (...) # PLACEMENT 2 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0001_0000) # CNXY_RAAF - write_sint(buf, 400) # placement-y + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0001_0000) # CNXY_RAAF + write_sint(buf, 400) # placement-y - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_1001) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_1001) # UUUU_VCNS # PLACEMENT 3 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0010_0000) # CNXY_RAAF - write_sint(buf, 300) # placement-x + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0010_0000) # CNXY_RAAF + write_sint(buf, 300) # placement-x - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 4 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_0001) # CNXY_RAAF - write_sint(buf, 700) # placement-x (absolute) - write_sint(buf, 400) # placement-y (absolute) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_0001) # CNXY_RAAF + write_sint(buf, 700) # placement-x (absolute) + write_sint(buf, 400) # placement-y (absolute) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_1001) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_1001) # UUUU_VCNS - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 5 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0001_0010) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0001_0010) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0010_0111) # UUUU_VCNS - write_uint(buf, 0) # propname-id - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 25) # (...) - write_uint(buf, 10) # prop-value 1 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0010_0111) # UUUU_VCNS + write_uint(buf, 0) # propname-id + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 25) # (...) + write_uint(buf, 10) # prop-value 1 (a-string) write_bstring(buf, b'PROP_VALUE2') # PLACEMENT 6 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0001_0011) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0001_0011) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 7 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (absolute) - write_sint(buf, 0) # placement-y (absolute) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 300) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (absolute) + write_sint(buf, 0) # placement-y (absolute) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 300) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 8 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x - write_sint(buf, 0) # placement-y - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x + write_sint(buf, 0) # placement-y + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # PLACEMENT 9 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x - write_sint(buf, 0) # placement-y - write_uint(buf, 2) # repetition (3 cols.) - write_uint(buf, 1) # (repetition) dimension - write_uint(buf, 320) # (repetition) offset + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x + write_sint(buf, 0) # placement-y + write_uint(buf, 2) # repetition (3 cols.) + write_uint(buf, 1) # (repetition) dimension + write_uint(buf, 320) # (repetition) offset - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # PLACEMENT 10 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x - write_sint(buf, 0) # placement-y - write_uint(buf, 3) # repetition (4 rows) - write_uint(buf, 2) # (repetition) dimension - write_uint(buf, 310) # (repetition) offset + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x + write_sint(buf, 0) # placement-y + write_uint(buf, 3) # repetition (4 rows) + write_uint(buf, 2) # (repetition) dimension + write_uint(buf, 310) # (repetition) offset - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # PLACEMENT 11 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x - write_sint(buf, 0) # placement-y - write_uint(buf, 4) # repetition (4 arbitrary cols.) - write_uint(buf, 2) # (repetition) dimension - write_uint(buf, 320) # (repetition) - write_uint(buf, 330) # (repetition) - write_uint(buf, 340) # (repetition) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x + write_sint(buf, 0) # placement-y + write_uint(buf, 4) # repetition (4 arbitrary cols.) + write_uint(buf, 2) # (repetition) dimension + write_uint(buf, 320) # (repetition) + write_uint(buf, 330) # (repetition) + write_uint(buf, 340) # (repetition) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # PLACEMENT 12 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x - write_sint(buf, 0) # placement-y - write_uint(buf, 8) # repetition (3x4 matrix, arbitrary vectors) - write_uint(buf, 1) # (repetition) n-dimension - write_uint(buf, 2) # (repetition) m-dimension - write_uint(buf, 310 << 2 | 0b01) # (repetition) n-displacement g-delta (310, 320) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x + write_sint(buf, 0) # placement-y + write_uint(buf, 8) # repetition (3x4 matrix, arbitrary vectors) + write_uint(buf, 1) # (repetition) n-dimension + write_uint(buf, 2) # (repetition) m-dimension + write_uint(buf, 310 << 2 | 0b01) # (repetition) n-displacement g-delta (310, 320) write_sint(buf, 320) - write_uint(buf, 330 << 4 | 0b1010) # (repetition) m-dispalcement g-delta 330/northwest = (-330, 330) + write_uint(buf, 330 << 4 | 0b1010) # (repetition) m-dispalcement g-delta 330/northwest = (-330, 330) write_uint(buf, 29) # PROPERTY (reuse) @@ -937,16 +932,16 @@ def write_file_7_8_9(buf: BufferedIOBase, variant: int) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_0100) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_0100) # UUUU_VCNS write_bstring(buf, b'FileProp1') # property name - write_uint(buf, 10) # prop-value 0 (a-string) + write_uint(buf, 10) # prop-value 0 (a-string) write_bstring(buf, b'FileProp1Value') - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 13) # prop-name reference - write_uint(buf, 10) # prop-value 0 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 13) # prop-name reference + write_uint(buf, 10) # prop-value 0 (a-string) write_bstring(buf, b'FileProp1Value') write_uint(buf, 8) # PROPNAME record (explicit id) @@ -957,70 +952,69 @@ def write_file_7_8_9(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 28) # PROPERTY record if variant == 8: # Will give an error since the value modal variable is reset by PROPNAME_ID - write_byte(buf, 0b0001_1110) # UUUU_VCNS + write_byte(buf, 0b0001_1110) # UUUU_VCNS else: - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 13) # prop-name reference + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 13) # prop-name reference if variant != 8: - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 17) # (...) + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 17) # (...) write_uint(buf, 10) # PROPSTRING (explicit id) write_bstring(buf, b'FileProp2Value') write_uint(buf, 12) # id # associated with PROPSTRING? - write_uint(buf, 28) # PROPERTY record + write_uint(buf, 28) # PROPERTY record if variant == 9: # Will give an error since the value modal variable is unset - write_byte(buf, 0b0001_1110) # UUUU_VCNS + write_byte(buf, 0b0001_1110) # UUUU_VCNS else: - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 13) # prop-name reference + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 13) # prop-name reference if variant != 9: - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 42) # (...) + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 42) # (...) write_uint(buf, 3) # CELLNAME record (implicit id 0) write_bstring(buf, b'A') # associated with cell A, through CELLNAME # TODO - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_0100) # UUUU_VCNS - write_bstring(buf, b'CellProp0') # prop name - write_uint(buf, 10) # prop-value 0 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_0100) # UUUU_VCNS + write_bstring(buf, b'CellProp0') # prop name + write_uint(buf, 10) # prop-value 0 (a-string) write_bstring(buf, b'CPValue0') - + # ** CELL ** write_uint(buf, 13) # CELL record (name ref.) write_uint(buf, 0) # Cell name 0 (XYZ) # associated with cell A - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_0100) # UUUU_VCNS - write_bstring(buf, b'CellProp1') # prop name - write_uint(buf, 10) # prop-value 0 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_0100) # UUUU_VCNS + write_bstring(buf, b'CellProp1') # prop name + write_uint(buf, 10) # prop-value 0 (a-string) write_bstring(buf, b'CPValue') - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_1100) # UUUU_VCNS - write_bstring(buf, b'CellProp2') # prop name + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_1100) # UUUU_VCNS + write_bstring(buf, b'CellProp2') # prop name # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 300) # geometry-x - write_sint(buf, -400) # geometry-y + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 300) # geometry-x + write_sint(buf, -400) # geometry-y buf.write(FOOTER) return buf - def test_file_7() -> None: buf = write_file_7_8_9(BytesIO(), 7) diff --git a/fatamorgana/test/test_files_rectangles.py b/fatamorgana/test/test_files_rectangles.py index f47503f..e9f0b99 100644 --- a/fatamorgana/test/test_files_rectangles.py +++ b/fatamorgana/test/test_files_rectangles.py @@ -1,15 +1,9 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct - -import pytest # type: ignore from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -88,149 +82,149 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: buf.write(HEADER) if variant == 2: - write_uint(buf, 7) # PROPNAME record (implict id 0) - write_bstring(buf, b'PROP0') # property name + write_uint(buf, 7) # PROPNAME record (implict id 0) + write_bstring(buf, b'PROP0') # property name write_uint(buf, 14) # CELL record (explicit) write_bstring(buf, b'ABC') # Cell name # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 300) # geometry-x (absolute) - write_sint(buf, -400) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 300) # geometry-x (absolute) + write_sint(buf, -400) # geometry-y (absolute) if variant == 2: # PROPERTY 0 - write_uint(buf, 28) # PROPERTY record (explicit) - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 2) # property value (real: positive reciprocal) - write_uint(buf, 5) # (real) 1/5 + write_uint(buf, 28) # PROPERTY record (explicit) + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 2) # property value (real: positive reciprocal) + write_uint(buf, 5) # (real) 1/5 write_uint(buf, 16) # XYRELATIVE record # RECTANGLE 1 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 100) # geometry-x (relative) - write_sint(buf, -100) # geometry-y (relative) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 100) # geometry-x (relative) + write_sint(buf, -100) # geometry-y (relative) if variant == 2: # PROPERTY 1 write_uint(buf, 29) # PROPERTY record (repeat) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # RECTANGLE 2 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 600) # geometry-x (absolute) - write_sint(buf, -300) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 600) # geometry-x (absolute) + write_sint(buf, -300) # geometry-y (absolute) if variant == 2: # PROPERTY 2 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 3 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_0011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 800) # geometry-x (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_0011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 800) # geometry-x (absolute) if variant == 2: # PROPERTY 3 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 4 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0110_1011) # SWHX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, -600) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0110_1011) # SWHX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, -600) # geometry-y (absolute) if variant == 2: # PROPERTY 4 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 5 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0110_1000) # SWHX_YRDL - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, -900) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0110_1000) # SWHX_YRDL + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, -900) # geometry-y (absolute) if variant == 2: # PROPERTY 5 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 6 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_1000) # SWHX_YRDL - write_sint(buf, -1200) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_1000) # SWHX_YRDL + write_sint(buf, -1200) # geometry-y (absolute) if variant == 2: # PROPERTY 6 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 7 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b1100_1000) # SWHX_YRDL - write_uint(buf, 150) # width - write_sint(buf, -1500) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b1100_1000) # SWHX_YRDL + write_uint(buf, 150) # width + write_sint(buf, -1500) # geometry-y (absolute) if variant == 2: # PROPERTY 7 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 8 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_1000) # SWHX_YRDL - write_sint(buf, -1800) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_1000) # SWHX_YRDL + write_sint(buf, -1800) # geometry-y (absolute) if variant == 2: # PROPERTY 8 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 9 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_1100) # SWHX_YRDL - write_sint(buf, 500) # geometry-y (absolute) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_1100) # SWHX_YRDL + write_sint(buf, 500) # geometry-y (absolute) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing if variant == 2: # PROPERTY 9 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 10 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_1100) # SWHX_YRDL - write_sint(buf, 2000) # geometry-y (absolute) - write_uint(buf, 4) # repetition (3 arbitrary cols.) - write_uint(buf, 1) # (repetition) dimension - write_uint(buf, 200) # (repetition) x-delta - write_uint(buf, 300) # (repetition) x-delta + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_1100) # SWHX_YRDL + write_sint(buf, 2000) # geometry-y (absolute) + write_uint(buf, 4) # repetition (3 arbitrary cols.) + write_uint(buf, 1) # (repetition) dimension + write_uint(buf, 200) # (repetition) x-delta + write_uint(buf, 300) # (repetition) x-delta if variant == 2: # PROPERTY 10 diff --git a/fatamorgana/test/test_files_texts.py b/fatamorgana/test/test_files_texts.py index c23877c..0ee22a0 100644 --- a/fatamorgana/test/test_files_texts.py +++ b/fatamorgana/test/test_files_texts.py @@ -1,14 +1,11 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore +import pytest from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..basic import InvalidRecordError, InvalidDataError from ..basic import GridRepetition, ArbitraryRepetition from ..main import OasisLayout @@ -86,12 +83,12 @@ def common_tests(layout: OasisLayout) -> None: assert geometry[13].repetition.b_vector == [-10, 10] assert geometry[14].repetition.a_count == 3 - assert geometry[14].repetition.b_count == None + assert geometry[14].repetition.b_count is None assert geometry[14].repetition.a_vector == [11, 12] assert geometry[14].repetition.b_vector is None assert geometry[15].repetition.a_count == 4 - assert geometry[15].repetition.b_count == None + assert geometry[15].repetition.b_count is None assert geometry[15].repetition.a_vector == [-10, 10] assert geometry[15].repetition.b_vector is None @@ -256,9 +253,9 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 8) # repetition (3x4 matrix w/arb. vectors) write_uint(buf, 1) # (repetition) n-dimension write_uint(buf, 2) # (repetition) m-dimension - write_uint(buf, (10 << 4) | 0b0000) # (repetition) n-displacement g-delta: 10/east = (10, 0) - write_uint(buf, (11 << 2) | 0b11) # (repetition) m-displacement g-delta: (-11, -12) - write_sint(buf, -12) # (repetition g-delta) + write_uint(buf, (10 << 4) | 0b0000) # (repetition) n-displacement g-delta: 10/east = (10, 0) + write_uint(buf, (11 << 2) | 0b11) # (repetition) m-displacement g-delta: (-11, -12) + write_sint(buf, -12) # (repetition g-delta) # TEXT 13 write_uint(buf, 19) # TEXT record @@ -267,9 +264,9 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 8) # repetition (3x4 matrix w/arb. vectors) write_uint(buf, 1) # (repetition) n-dimension write_uint(buf, 2) # (repetition) m-dimension - write_uint(buf, (11 << 2) | 0b01) # (repetition) n-displacement g-delta: (11, 12) + write_uint(buf, (11 << 2) | 0b01) # (repetition) n-displacement g-delta: (11, 12) write_sint(buf, 12) - write_uint(buf, (10 << 4) | 0b1010) # (repetition) n-displacement g-delta: 10/northwest = (-10, 10) + write_uint(buf, (10 << 4) | 0b1010) # (repetition) n-displacement g-delta: 10/northwest = (-10, 10) # TEXT 14 write_uint(buf, 19) # TEXT record diff --git a/fatamorgana/test/test_files_trapezoids.py b/fatamorgana/test/test_files_trapezoids.py index 1bd67e1..574054d 100644 --- a/fatamorgana/test/test_files_trapezoids.py +++ b/fatamorgana/test/test_files_trapezoids.py @@ -1,17 +1,9 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct - -import pytest # type: ignore -import numpy -from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -37,145 +29,145 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'ABC') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'ABC') # Cell name # Trapezoid 0 - write_uint(buf, 23) # TRAPEZOID record - write_byte(buf, 0b0111_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 50) # height - write_sint(buf, -20) # delta-a - write_sint(buf, 40) # delta-b - write_sint(buf, 0) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 23) # TRAPEZOID record + write_byte(buf, 0b0111_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 50) # height + write_sint(buf, -20) # delta-a + write_sint(buf, 40) # delta-b + write_sint(buf, 0) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # Trapezoid 1 - write_uint(buf, 23) # TRAPEZOID record - write_byte(buf, 0b1010_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 50) # height - write_sint(buf, 20) # delta-a - write_sint(buf, 40) # delta-b - write_sint(buf, 300) # geometry-y (absolute) + write_uint(buf, 23) # TRAPEZOID record + write_byte(buf, 0b1010_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 50) # height + write_sint(buf, 20) # delta-a + write_sint(buf, 40) # delta-b + write_sint(buf, 300) # geometry-y (absolute) # Trapezoid 2 - write_uint(buf, 23) # TRAPEZOID record - write_byte(buf, 0b1100_1001) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, 20) # delta-a - write_sint(buf, -20) # delta-b - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 23) # TRAPEZOID record + write_byte(buf, 0b1100_1001) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, 20) # delta-a + write_sint(buf, -20) # delta-b + write_sint(buf, 300) # geometry-y (relative) # Trapezoid 3 - write_uint(buf, 23) # TRAPEZOID record - write_byte(buf, 0b0100_1101) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, 20) # delta-a - write_sint(buf, -20) # delta-b - write_sint(buf, 300) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 23) # TRAPEZOID record + write_byte(buf, 0b0100_1101) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, 20) # delta-a + write_sint(buf, -20) # delta-b + write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # Trapezoid 4 - write_uint(buf, 24) # TRAPEZOID record - write_byte(buf, 0b0111_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 50) # height - write_sint(buf, -20) # delta-a - write_sint(buf, 1000) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 24) # TRAPEZOID record + write_byte(buf, 0b0111_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 50) # height + write_sint(buf, -20) # delta-a + write_sint(buf, 1000) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # Trapezoid 5 - write_uint(buf, 24) # TRAPEZOID record - write_byte(buf, 0b1010_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 50) # height - write_sint(buf, 20) # delta-a - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 24) # TRAPEZOID record + write_byte(buf, 0b1010_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 50) # height + write_sint(buf, 20) # delta-a + write_sint(buf, 300) # geometry-y (relative) # Trapezoid 6 - write_uint(buf, 24) # TRAPEZOID record - write_byte(buf, 0b1100_1001) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, 20) # delta-a - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 24) # TRAPEZOID record + write_byte(buf, 0b1100_1001) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, 20) # delta-a + write_sint(buf, 300) # geometry-y (relative) # Trapezoid 7 - write_uint(buf, 24) # TRAPEZOID record - write_byte(buf, 0b0100_1101) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, 20) # delta-a - write_sint(buf, 300) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 24) # TRAPEZOID record + write_byte(buf, 0b0100_1101) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, 20) # delta-a + write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # Trapezoid 8 - write_uint(buf, 25) # TRAPEZOID record - write_byte(buf, 0b0111_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 50) # height - write_sint(buf, 40) # delta-b - write_sint(buf, 2000) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 25) # TRAPEZOID record + write_byte(buf, 0b0111_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 50) # height + write_sint(buf, 40) # delta-b + write_sint(buf, 2000) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # Trapezoid 9 - write_uint(buf, 25) # TRAPEZOID record - write_byte(buf, 0b1010_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 50) # height - write_sint(buf, 40) # delta-b - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 25) # TRAPEZOID record + write_byte(buf, 0b1010_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 50) # height + write_sint(buf, 40) # delta-b + write_sint(buf, 300) # geometry-y (relative) # Trapezoid 10 - write_uint(buf, 25) # TRAPEZOID record - write_byte(buf, 0b1100_1001) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, -20) # delta-b - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 25) # TRAPEZOID record + write_byte(buf, 0b1100_1001) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, -20) # delta-b + write_sint(buf, 300) # geometry-y (relative) # Trapezoid 11 - write_uint(buf, 25) # TRAPEZOID record - write_byte(buf, 0b0100_1101) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, -20) # delta-b - write_sint(buf, 300) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 25) # TRAPEZOID record + write_byte(buf, 0b0100_1101) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, -20) # delta-b + write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing buf.write(FOOTER) return buf diff --git a/fatamorgana/test/test_int.py b/fatamorgana/test/test_int.py index 5f44053..c974535 100644 --- a/fatamorgana/test/test_int.py +++ b/fatamorgana/test/test_int.py @@ -1,9 +1,6 @@ -from typing import List, Tuple, Iterable from itertools import chain from io import BytesIO -import pytest # type: ignore - from ..basic import read_uint, read_sint, write_uint, write_sint diff --git a/fatamorgana/test/utils.py b/fatamorgana/test/utils.py index 0f60e7c..7985908 100644 --- a/fatamorgana/test/utils.py +++ b/fatamorgana/test/utils.py @@ -1,12 +1,6 @@ -from typing import List, Tuple, Iterable -from itertools import chain -from io import BytesIO, BufferedIOBase -import struct +from io import BytesIO -import pytest # type: ignore - -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte -from ..main import OasisLayout +from ..basic import write_uint, write_bstring, write_byte MAGIC_BYTES = b'%SEMI-OASIS\r\n' From 18319e0a0bc6002b0d147471599cefda45129441 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Thu, 26 Jan 2023 13:48:20 -0800 Subject: [PATCH 04/40] Use IO[bytes] everywhere --- fatamorgana/test/build_testfiles.py | 6 ++--- fatamorgana/test/test_files_cblocks.py | 6 ++--- fatamorgana/test/test_files_cells.py | 18 ++++++------- fatamorgana/test/test_files_circles.py | 6 ++--- fatamorgana/test/test_files_ctrapezoids.py | 8 +++--- fatamorgana/test/test_files_empty.py | 14 +++++----- fatamorgana/test/test_files_layernames.py | 31 +++++++++++----------- fatamorgana/test/test_files_modals.py | 6 ++--- fatamorgana/test/test_files_paths.py | 6 ++--- fatamorgana/test/test_files_placements.py | 21 ++++++++------- fatamorgana/test/test_files_polygons.py | 8 +++--- fatamorgana/test/test_files_properties.py | 12 ++++----- fatamorgana/test/test_files_rectangles.py | 6 ++--- fatamorgana/test/test_files_texts.py | 22 +++++++-------- fatamorgana/test/test_files_trapezoids.py | 6 ++--- 15 files changed, 88 insertions(+), 88 deletions(-) diff --git a/fatamorgana/test/build_testfiles.py b/fatamorgana/test/build_testfiles.py index e776c61..5bb7525 100644 --- a/fatamorgana/test/build_testfiles.py +++ b/fatamorgana/test/build_testfiles.py @@ -1,10 +1,8 @@ ''' Build files equivalent to the test cases used by KLayout. ''' -# type: ignore -from typing import Callable -from io import BufferedIOBase +from typing import Callable, IO from . import ( @@ -16,7 +14,7 @@ from . import ( ) -def build_file(num: str, func: Callable[[BufferedIOBase], BufferedIOBase]) -> None: +def build_file(num: str, func: Callable[[IO[bytes]], IO[bytes]]) -> None: with open('t' + num + '.oas', 'wb') as f: func(f) diff --git a/fatamorgana/test/test_files_cblocks.py b/fatamorgana/test/test_files_cblocks.py index cf3f2ec..3f02e93 100644 --- a/fatamorgana/test/test_files_cblocks.py +++ b/fatamorgana/test/test_files_cblocks.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from numpy.testing import assert_equal @@ -26,7 +26,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cells[0].properties -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_cells.py b/fatamorgana/test/test_files_cells.py index 9fae7b8..59bc6d4 100644 --- a/fatamorgana/test/test_files_cells.py +++ b/fatamorgana/test/test_files_cells.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO import pytest @@ -23,7 +23,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' Single cell with explicit name 'XYZ' ''' @@ -48,7 +48,7 @@ def test_file_1() -> None: assert not layout.cellnames -def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_2(buf: IO[bytes]) -> IO[bytes]: ''' Two cellnames ('XYZ', 'ABC') and two cells with name references. ''' @@ -85,7 +85,7 @@ def test_file_2() -> None: assert layout.cells[1].name == 1 -def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_3(buf: IO[bytes]) -> IO[bytes]: ''' Invalid file, contains a mix of explicit and implicit cellnames ''' @@ -116,7 +116,7 @@ def test_file_3() -> None: layout = OasisLayout.read(buf) -def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_4(buf: IO[bytes]) -> IO[bytes]: ''' Two cells referencing two names with explicit ids (unsorted) ''' @@ -155,7 +155,7 @@ def test_file_4() -> None: assert layout.cells[1].name == 1 -def write_file_5(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_5(buf: IO[bytes]) -> IO[bytes]: ''' Reference to non-existent cell name. ''' @@ -196,7 +196,7 @@ def test_file_5() -> None: #TODO add optional error checking for this case -def write_file_6(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_6(buf: IO[bytes]) -> IO[bytes]: ''' Cellname with invalid n-string. ''' @@ -237,7 +237,7 @@ def test_file_6() -> None: #assert layout.cells[1].name == 1 -def write_file_7(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_7(buf: IO[bytes]) -> IO[bytes]: ''' Unused cellname. ''' diff --git a/fatamorgana/test/test_files_circles.py b/fatamorgana/test/test_files_circles.py index 794c18f..f29b18f 100644 --- a/fatamorgana/test/test_files_circles.py +++ b/fatamorgana/test/test_files_circles.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte @@ -24,7 +24,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cells[0].properties -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_ctrapezoids.py b/fatamorgana/test/test_files_ctrapezoids.py index fdcc6cf..095909f 100644 --- a/fatamorgana/test/test_files_ctrapezoids.py +++ b/fatamorgana/test/test_files_ctrapezoids.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte @@ -20,7 +20,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -153,7 +153,7 @@ def test_file_1() -> None: assert geometry[55].repetition.b_vector == [0, 300] -def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_2(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_empty.py b/fatamorgana/test/test_files_empty.py index acf651d..8554c28 100644 --- a/fatamorgana/test/test_files_empty.py +++ b/fatamorgana/test/test_files_empty.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO import struct from .utils import MAGIC_BYTES, FOOTER @@ -22,7 +22,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' File contains one PAD record. 1000 units/micron @@ -55,7 +55,7 @@ def test_file_1() -> None: assert layout.unit == 1000 -def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_2(buf: IO[bytes]) -> IO[bytes]: ''' File contains no records. 1/2 unit/micron @@ -86,7 +86,7 @@ def test_file_2() -> None: assert layout.unit == 0.5 -def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_3(buf: IO[bytes]) -> IO[bytes]: ''' File contains no records. 10/4 unit/micron @@ -118,7 +118,7 @@ def test_file_3() -> None: assert layout.unit == 10 / 4 -def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_4(buf: IO[bytes]) -> IO[bytes]: ''' File contains no records. 12.5 unit/micron (float32) @@ -149,7 +149,7 @@ def test_file_4() -> None: assert layout.unit == 12.5 -def write_file_5(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_5(buf: IO[bytes]) -> IO[bytes]: ''' File contains no records. 12.5 unit/micron (float64) diff --git a/fatamorgana/test/test_files_layernames.py b/fatamorgana/test/test_files_layernames.py index 94a2cc8..d430aaf 100644 --- a/fatamorgana/test/test_files_layernames.py +++ b/fatamorgana/test/test_files_layernames.py @@ -1,18 +1,19 @@ # type: ignore -from typing import Sequence +from typing import Sequence, IO -from io import BytesIO, BufferedIOBase +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout -LAYERS = [(1, 2), (1, 5), (1, 6), (1, 8), - (5, 2), (5, 5), (5, 6), (5, 8), - (6, 2), (6, 5), (6, 6), (6, 8), - (7, 2), (7, 5), (7, 6), (7, 8), - ] +LAYERS = [ + (1, 2), (1, 5), (1, 6), (1, 8), + (5, 2), (5, 5), (5, 6), (5, 8), + (6, 2), (6, 5), (6, 6), (6, 8), + (7, 2), (7, 5), (7, 6), (7, 8), + ] def base_tests(layout: OasisLayout) -> None: assert layout.version.string == '1.0' @@ -30,7 +31,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cells[0].properties -def write_names_geom(buf: BufferedIOBase, short: bool = False) -> BufferedIOBase: +def write_names_geom(buf: IO[bytes], short: bool = False) -> IO[bytes]: write_uint(buf, 11) # LAYERNAME record (geometry) write_bstring(buf, b'AA') # name write_uint(buf, 0) # all layers @@ -96,7 +97,7 @@ def write_names_geom(buf: BufferedIOBase, short: bool = False) -> BufferedIOBase return buf -def write_names_text(buf: BufferedIOBase, prefix: bytes = b'') -> BufferedIOBase: +def write_names_text(buf: IO[bytes], prefix: bytes = b'') -> IO[bytes]: write_uint(buf, 12) # LAYERNAME record (geometry) write_bstring(buf, prefix + b'AA') # name write_uint(buf, 0) # all layers @@ -128,7 +129,7 @@ def write_names_text(buf: BufferedIOBase, prefix: bytes = b'') -> BufferedIOBase write_uint(buf, 0) # all datatypes return buf -def write_geom(buf: BufferedIOBase) -> BufferedIOBase: +def write_geom(buf: IO[bytes]) -> IO[bytes]: for ll, dt in LAYERS: write_uint(buf, 27) # CIRCLE record write_byte(buf, 0b0011_1011) # 00rX_YRDL @@ -140,7 +141,7 @@ def write_geom(buf: BufferedIOBase) -> BufferedIOBase: return buf -def write_text(buf: BufferedIOBase) -> BufferedIOBase: +def write_text(buf: IO[bytes]) -> IO[bytes]: for ll, dt in LAYERS: write_uint(buf, 19) # TEXT record write_byte(buf, 0b0101_1011) # 0CNX_YRTL @@ -205,7 +206,7 @@ def elem_test_text(geometry: Sequence) -> None: assert not gg.properties, msg -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -235,7 +236,7 @@ def test_file_1() -> None: name_test(layout.layers, is_textlayer=False) -def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_2(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -265,7 +266,7 @@ def test_file_2() -> None: name_test(layout.layers, is_textlayer=True) -def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_3(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -281,7 +282,7 @@ def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: return buf -def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_4(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_modals.py b/fatamorgana/test/test_files_modals.py index d2417f2..9eac770 100644 --- a/fatamorgana/test/test_files_modals.py +++ b/fatamorgana/test/test_files_modals.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte @@ -20,7 +20,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_paths.py b/fatamorgana/test/test_files_paths.py index 8fb2cc0..3243a79 100644 --- a/fatamorgana/test/test_files_paths.py +++ b/fatamorgana/test/test_files_paths.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from numpy.testing import assert_equal @@ -26,7 +26,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cells[0].properties -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_placements.py b/fatamorgana/test/test_files_placements.py index 390876e..290ffee 100644 --- a/fatamorgana/test/test_files_placements.py +++ b/fatamorgana/test/test_files_placements.py @@ -1,11 +1,12 @@ # type: ignore -from typing import Tuple -from io import BytesIO, BufferedIOBase +from typing import Tuple, IO, cast, List +from io import BytesIO from numpy.testing import assert_equal from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte, write_float32, write_float64 +from ..records import Rectangle from ..main import OasisLayout @@ -21,7 +22,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_rectangle(buf: BufferedIOBase, pos: Tuple[int, int] = (300, -400)) -> None: +def write_rectangle(buf: IO[bytes], pos: Tuple[int, int] = (300, -400)) -> None: write_uint(buf, 20) # RECTANGLE record write_byte(buf, 0b0111_1011) # SWHX_YRDL write_uint(buf, 1) # layer @@ -32,7 +33,7 @@ def write_rectangle(buf: BufferedIOBase, pos: Tuple[int, int] = (300, -400)) -> write_sint(buf, pos[1]) # geometry-y (absolute) -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -173,7 +174,7 @@ def test_file_1() -> None: assert not layout.cells[1].properties assert not layout.cells[1].geometry - geometry = layout.cells[0].geometry + geometry = cast(List[Rectangle], layout.cells[0].geometry) assert len(geometry) == 1 assert geometry[0].layer == 1 assert geometry[0].datatype == 2 @@ -248,7 +249,7 @@ def test_file_1() -> None: assert placements[12].repetition.b_vector == [-330, 330] -def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' assert variant in (2, 3, 5, 7), 'Error in test definition!' @@ -514,7 +515,7 @@ def common_tests(layout: OasisLayout, variant: int) -> None: assert placements[6].y == 2400 -def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_4(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -593,7 +594,7 @@ def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: return buf -def write_file_6(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_6(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -746,7 +747,7 @@ def test_file_6() -> None: assert pp.y == [0, 1000][ii], msg -def write_file_8(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_8(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -842,7 +843,7 @@ def test_file_8() -> None: assert not layout.cells[2].properties assert not layout.cells[2].placements - geometry = layout.cells[2].geometry + geometry = cast(List[Rectangle], layout.cells[2].geometry) assert len(geometry) == 1 assert geometry[0].layer == 1 assert geometry[0].datatype == 2 diff --git a/fatamorgana/test/test_files_polygons.py b/fatamorgana/test/test_files_polygons.py index 2deb808..f89a019 100644 --- a/fatamorgana/test/test_files_polygons.py +++ b/fatamorgana/test/test_files_polygons.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO import numpy from numpy.testing import assert_equal @@ -106,7 +106,7 @@ def common_tests(layout: OasisLayout) -> None: assert_equal(geometry[ii].point_list, [[0, 150], [50, 0], [0, -50], [50, 0], [0, -100], [-100, 0]], err_msg=msg) -def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' assert variant in (1, 3), 'Error in test!!' @@ -375,7 +375,7 @@ def test_file_1() -> None: assert not gg.properties, f'Fail on polygon {ii}' -def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_2(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_properties.py b/fatamorgana/test/test_files_properties.py index 107b64a..99bdc37 100644 --- a/fatamorgana/test/test_files_properties.py +++ b/fatamorgana/test/test_files_properties.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO import pytest from numpy.testing import assert_equal @@ -23,7 +23,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' include_repetitions = variant in (2, 5) @@ -354,7 +354,7 @@ def test_file_5() -> None: assert gg.repetition.b_vector == [0, 320], msg -def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_3(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -579,7 +579,7 @@ def test_file_3() -> None: assert geometry[ii].properties[0].values[1].string == 'PROP_VALUE2', msg -def write_file_4_6(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_4_6(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -927,7 +927,7 @@ def test_file_6() -> None: assert placements[ii].properties[0].values[1].string == 'PROP_VALUE2', msg -def write_file_7_8_9(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_7_8_9(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_rectangles.py b/fatamorgana/test/test_files_rectangles.py index e9f0b99..a7ffdc7 100644 --- a/fatamorgana/test/test_files_rectangles.py +++ b/fatamorgana/test/test_files_rectangles.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte @@ -74,7 +74,7 @@ def base_tests(layout: OasisLayout) -> None: assert geometry[10].repetition.x_displacements == [200, 300] -def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' assert variant in (1, 2), 'Error in test!!' diff --git a/fatamorgana/test/test_files_texts.py b/fatamorgana/test/test_files_texts.py index 0ee22a0..0d10744 100644 --- a/fatamorgana/test/test_files_texts.py +++ b/fatamorgana/test/test_files_texts.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO import pytest @@ -99,7 +99,7 @@ def common_tests(layout: OasisLayout) -> None: assert geometry[19].repetition.y_displacements == [12, -9] -def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: ''' Single cell with explicit name 'XYZ' ''' @@ -460,7 +460,7 @@ def test_file_12() -> None: assert layout.textstrings[2].string == 'B' -def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_3(buf: IO[bytes]) -> IO[bytes]: ''' File with one textstring with explicit id, and one with an implicit id. Should fail. @@ -497,7 +497,7 @@ def test_file_3() -> None: layout = OasisLayout.read(buf) -def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_4(buf: IO[bytes]) -> IO[bytes]: ''' File with a TEXT record that references a non-existent TEXTSTRING @@ -537,7 +537,7 @@ def test_file_4() -> None: base_tests(layout) -def write_file_6(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_6(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses an un-filled modal for the repetition ''' @@ -570,7 +570,7 @@ def test_file_6() -> None: layout = OasisLayout.read(buf) -def write_file_7(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_7(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses an un-filled modal for the layer ''' @@ -601,7 +601,7 @@ def test_file_7() -> None: layout = OasisLayout.read(buf) -def write_file_8(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_8(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses an un-filled modal for the datatype ''' @@ -632,7 +632,7 @@ def test_file_8() -> None: layout = OasisLayout.read(buf) -def write_file_9(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_9(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses a default modal for the x coordinate ''' @@ -668,7 +668,7 @@ def test_file_9() -> None: assert text.y == -200 -def write_file_10(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_10(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses a default modal for the y coordinate ''' @@ -704,7 +704,7 @@ def test_file_10() -> None: assert text.x == 100 -def write_file_11(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_11(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses an un-filled modal for the text string ''' diff --git a/fatamorgana/test/test_files_trapezoids.py b/fatamorgana/test/test_files_trapezoids.py index 574054d..cea3123 100644 --- a/fatamorgana/test/test_files_trapezoids.py +++ b/fatamorgana/test/test_files_trapezoids.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte @@ -24,7 +24,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cells[0].properties -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) From cd90571c2fa80c8c5a399de384f6fe1b14b6203b Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sat, 30 Mar 2024 19:44:47 -0700 Subject: [PATCH 05/40] Modernize type annotations --- README.md | 4 +- fatamorgana/basic.py | 203 +++++----- fatamorgana/main.py | 109 +++--- fatamorgana/records.py | 819 ++++++++++++++++++++--------------------- pyproject.toml | 2 +- 5 files changed, 547 insertions(+), 590 deletions(-) diff --git a/README.md b/README.md index fc5f845..b7aa3d8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ **fatamorgana** is a Python package for reading and writing OASIS format layout files. **Homepage:** https://mpxd.net/code/jan/fatamorgana +* [PyPI](https://pypi.org/project/fatamorgana) +* [Github mirror](https://github.com/anewusername/fatamorgana) **Capabilities:** * This package is a work-in-progress and is largely untested -- it works for @@ -20,7 +22,7 @@ ## Installation **Dependencies:** -* python 3.5 or newer +* python >=3.10 * (optional) numpy diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 476e5f6..ea96528 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -2,7 +2,7 @@ This module contains all datatypes and parsing/writing functions for all abstractions below the 'record' or 'block' level. """ -from typing import List, Tuple, Type, Union, Optional, Any, Sequence, IO +from typing import Type, Union, Any, Sequence, IO from fractions import Fraction from enum import Enum import math @@ -132,7 +132,7 @@ def write_byte(stream: IO[bytes], n: int) -> int: return stream.write(bytes((n,))) -def _py_read_bool_byte(stream: IO[bytes]) -> List[bool]: +def _py_read_bool_byte(stream: IO[bytes]) -> list[bool]: """ Read a single byte from the stream, and interpret its bits as a list of 8 booleans. @@ -147,7 +147,7 @@ def _py_read_bool_byte(stream: IO[bytes]) -> List[bool]: bits = [bool((byte >> i) & 0x01) for i in reversed(range(8))] return bits -def _py_write_bool_byte(stream: IO[bytes], bits: Tuple[Union[bool, int], ...]) -> int: +def _py_write_bool_byte(stream: IO[bytes], bits: tuple[bool | int, ...]) -> int: """ Pack 8 booleans into a byte, and write it to the stream. @@ -184,7 +184,7 @@ if _USE_NUMPY: byte_arr = _read(stream, 1) return numpy.unpackbits(numpy.frombuffer(byte_arr, dtype=numpy.uint8)) - def _np_write_bool_byte(stream: IO[bytes], bits: Tuple[Union[bool, int], ...]) -> int: + def _np_write_bool_byte(stream: IO[bytes], bits: tuple[Union[bool, int], ...]) -> int: """ Pack 8 booleans into a byte, and write it to the stream. @@ -457,7 +457,7 @@ def write_float64(stream: IO[bytes], f: float) -> int: return stream.write(b) -def read_real(stream: IO[bytes], real_type: Optional[int] = None) -> real_t: +def read_real(stream: IO[bytes], real_type: int | None = None) -> real_t: """ Read a real number from the stream. @@ -783,13 +783,12 @@ def write_astring(stream: IO[bytes], string: str) -> int: class ManhattanDelta: """ Class representing an axis-aligned ("Manhattan") vector. - - Attributes: - vertical (bool): `True` if aligned along y-axis - value (int): signed length of the vector """ vertical: bool + """`True` if aligned along y-axis""" + value: int + """signed length of the vector""" def __init__(self, x: int, y: int) -> None: """ @@ -810,7 +809,7 @@ class ManhattanDelta: self.vertical = True self.value = y - def as_list(self) -> List[int]: + def as_list(self) -> list[int]: """ Return a list representation of this vector. @@ -892,25 +891,26 @@ class ManhattanDelta: class OctangularDelta: """ Class representing an axis-aligned or 45-degree ("Octangular") vector. - - Attributes: - proj_mag (int): projection of the vector onto the x or y axis (non-zero) - octangle (int): bitfield: - bit 2: 1 if non-axis-aligned (non-Manhattan) - if Manhattan: - bit 1: 1 if direction is negative - bit 0: 1 if direction is y - if non-Manhattan: - bit 1: 1 if in lower half-plane - bit 0: 1 if x==-y - - Resulting directions: - 0: +x, 1: +y, 2: -x, 3: -y, - 4: +x+y, 5: -x+y, - 6: +x-y, 7: -x-y """ proj_mag: int + """projection of the vector onto the x or y axis (non-zero)""" + octangle: int + """ + bitfield: + bit 2: 1 if non-axis-aligned (non-Manhattan) + if Manhattan: + bit 1: 1 if direction is negative + bit 0: 1 if direction is y + if non-Manhattan: + bit 1: 1 if in lower half-plane + bit 0: 1 if x==-y + + Resulting directions: + 0: +x, 1: +y, 2: -x, 3: -y, + 4: +x+y, 5: -x+y, + 6: +x-y, 7: -x-y + """ def __init__(self, x: int, y: int) -> None: """ @@ -936,7 +936,7 @@ class OctangularDelta: else: raise InvalidDataError(f'Non-octangular delta! ({x}, {y})') - def as_list(self) -> List[int]: + def as_list(self) -> list[int]: """ Return a list representation of this vector. @@ -1028,13 +1028,12 @@ class OctangularDelta: class Delta: """ Class representing an arbitrary vector - - Attributes - x (int): x-displacement - y (int): y-displacement """ x: int + """x-displacement""" + y: int + """y-displacement""" def __init__(self, x: int, y: int) -> None: """ @@ -1047,7 +1046,7 @@ class Delta: self.x = x self.y = y - def as_list(self) -> List[int]: + def as_list(self) -> list[int]: """ Return a list representation of this vector. @@ -1168,32 +1167,35 @@ class ReuseRepetition: class GridRepetition: """ - Class representing a repetition entry denoting a 1D or 2D array - of regularly-spaced elements. The spacings are stored as one or - two lattice vectors, and the extent of the grid is stored as the - number of elements along each lattice vector. - - Attributes: - a_vector (Tuple[int, int]): `(xa, ya)` vector specifying a center-to-center - displacement between adjacent elements in the grid. - b_vector (Optional[Tuple[int, int]]): `(xb, yb)`, a second displacement, - present if a 2D grid is being specified. - a_count (int): number of elements (>=1) along the grid axis specified by - `a_vector`. - b_count (Optional[int]): Number of elements (>=1) along the grid axis - specified by `b_vector`, if `b_vector` is not `None`. + A repetition entry denoting a 1D or 2D array of regularly-spaced elements. The + spacings are stored as one or two lattice vectors, and the extent of the grid + is stored as the number of elements along each lattice vector. """ - a_vector: List[int] - b_vector: Optional[List[int]] = None + + a_vector: list[int] + """`(xa, ya)` vector specifying a center-to-center + displacement between adjacent elements in the grid. + """ + + b_vector: list[int] | None = None + """`(xb, yb)`, a second displacement, + present if a 2D grid is being specified. + """ + a_count: int - b_count: Optional[int] = None + """number of elements (>=1) along the grid axis specified by `a_vector`.""" + + b_count: int | None = None + """Number of elements (>=1) along the grid axis + specified by `b_vector`, if `b_vector` is not `None`. + """ def __init__( self, a_vector: Sequence[int], a_count: int, - b_vector: Optional[Sequence[int]] = None, - b_count: Optional[int] = None): + b_vector: Sequence[int] | None = None, + b_count: int | None = None): """ Args: a_vector: First lattice vector, of the form `[x, y]`. @@ -1245,8 +1247,8 @@ class GridRepetition: Raises: InvalidDataError: if `repetition_type` is invalid. """ - nb: Optional[int] - b_vector: Optional[List[int]] + nb: int | None + b_vector: list[int] | None if repetition_type == 1: na = read_uint(stream) + 2 nb = read_uint(stream) + 2 @@ -1352,14 +1354,13 @@ class ArbitraryRepetition: """ Class representing a repetition entry denoting a 1D or 2D array of arbitrarily-spaced elements. - - Attributes: - x_displacements (List[int]): x-displacements between consecutive elements - y_displacements (List[int]): y-displacements between consecutive elements """ - x_displacements: List[int] - y_displacements: List[int] + x_displacements: list[int] + """x-displacements between consecutive elements""" + + y_displacements: list[int] + """y-displacements between consecutive elements""" def __init__( self, @@ -1443,7 +1444,7 @@ class ArbitraryRepetition: Returns: Number of bytes written. """ - def get_gcd(vals: List[int]) -> int: + def get_gcd(vals: list[int]) -> int: """ Get the greatest common denominator of a list of ints. """ @@ -1506,7 +1507,7 @@ class ArbitraryRepetition: def read_point_list( stream: IO[bytes], implicit_closed: bool, - ) -> List[List[int]]: + ) -> Sequence[Sequence[int]]: """ Read a point list from a stream. @@ -1594,7 +1595,7 @@ def read_point_list( def write_point_list( stream: IO[bytes], - points: List[Sequence[int]], + points: list[Sequence[int]], fast: bool = False, implicit_closed: bool = True ) -> int: @@ -1655,7 +1656,7 @@ def write_point_list( return size # Try writing a bunch of Manhattan or Octangular deltas - deltas: Union[List[ManhattanDelta], List[OctangularDelta], List[Delta]] + deltas: list[ManhattanDelta] | list[OctangularDelta] | list[Delta] list_type = None try: deltas = [ManhattanDelta(x, y) for x, y in points] @@ -1717,13 +1718,12 @@ def write_point_list( class PropStringReference: """ Reference to a property string. - - Attributes: - ref (int): ID of the target - ref_type (Type): Type of the target: `bytes`, `NString`, or `AString` """ ref: int + """ID of the target""" + reference_type: Type + """Type of the target: `bytes`, `NString`, or `AString`""" def __init__(self, ref: int, ref_type: Type) -> None: """ @@ -1854,7 +1854,7 @@ def write_property_value( return size -def read_interval(stream: IO[bytes]) -> Tuple[Optional[int], Optional[int]]: +def read_interval(stream: IO[bytes]) -> tuple[int | None, int | None]: """ Read an interval from a stream. These are used for storing layer info. @@ -1896,8 +1896,8 @@ def read_interval(stream: IO[bytes]) -> Tuple[Optional[int], Optional[int]]: def write_interval( stream: IO[bytes], - min_bound: Optional[int] = None, - max_bound: Optional[int] = None, + min_bound: int | None = None, + max_bound: int | None = None, ) -> int: """ Write an interval to a stream. @@ -1931,23 +1931,24 @@ def write_interval( class OffsetEntry: """ Entry for the file's offset table. - - Attributes: - strict (bool): If `False`, the records pointed to by this - offset entry may also appear elsewhere in the file. If `True`, all - records of the type pointed to by this offset entry must be present - in a contiuous block at the specified offset [pad records also allowed]. - Additionally: - - All references to strict-mode records must be - explicit (using reference_number). - - The offset may point to an encapsulating CBlock record, if the first - record in that CBlock is of the target record type. A strict modei - table cannot begin in the middle of a CBlock. - offset (int): offset from the start of the file; may be 0 - for records that are not present. """ + strict: bool = False + """ + If `False`, the records pointed to by this offset entry may also appear + elsewhere in the file. If `True`, all records of the type pointed to by + this offset entry must be present in a contiuous block at the specified + offset [pad records also allowed]. + Additionally: + - All references to strict-mode records must be explicit (using + `reference_number`). + - The offset may point to an encapsulating CBlock record, if the first + record in that CBlock is of the target record type. A strict mode + table cannot begin in the middle of a CBlock. + """ + offset: int = 0 + """offset from the start of the file; 0 for records that are not present.""" def __init__(self, strict: bool = False, offset: int = 0) -> None: """ @@ -2006,14 +2007,6 @@ class OffsetTable: XName which are stored in the above order in the file's offset table. - - Attributes: - cellnames (OffsetEntry): Offset for CellNames - textstrings (OffsetEntry): Offset for TextStrings - propnames (OffsetEntry): Offset for PropNames - propstrings (OffsetEntry): Offset for PropStrings - layernames (OffsetEntry): Offset for LayerNames - xnames (OffsetEntry): Offset for XNames """ cellnames: OffsetEntry textstrings: OffsetEntry @@ -2024,12 +2017,12 @@ class OffsetTable: def __init__( self, - cellnames: Optional[OffsetEntry] = None, - textstrings: Optional[OffsetEntry] = None, - propnames: Optional[OffsetEntry] = None, - propstrings: Optional[OffsetEntry] = None, - layernames: Optional[OffsetEntry] = None, - xnames: Optional[OffsetEntry] = None, + cellnames: OffsetEntry | None = None, + textstrings: OffsetEntry | None = None, + propnames: OffsetEntry | None = None, + propstrings: OffsetEntry | None = None, + layernames: OffsetEntry | None = None, + xnames: OffsetEntry | None = None, ) -> None: """ All parameters default to a non-strict entry with offset `0`. @@ -2149,14 +2142,18 @@ class Validation: The checksum is calculated using the entire file, excluding the final 4 bytes (the value of the checksum itself). - Attributes: - checksum_type (int): `0` for no checksum, `1` for crc32, `2` for checksum32 - checksum (Optional[int]): value of the checksum """ checksum_type: int - checksum: Optional[int] = None + """ + `0` for no checksum, + `1` for crc32, + `2` for checksum32, + """ - def __init__(self, checksum_type: int, checksum: Optional[int] = None) -> None: + checksum: int | None = None + """value of the checksum""" + + def __init__(self, checksum_type: int, checksum: int | None = None) -> None: """ Args: checksum_type: 0,1,2 (No checksum, crc32, checksum32) diff --git a/fatamorgana/main.py b/fatamorgana/main.py index 8748d7f..1bb7258 100644 --- a/fatamorgana/main.py +++ b/fatamorgana/main.py @@ -3,7 +3,7 @@ This module contains data structures and functions for reading from and writing to whole OASIS layout files, and provides a few additional abstractions for the data contained inside them. """ -from typing import List, Dict, Union, Optional, Type, IO +from typing import Type, IO import io import logging @@ -27,20 +27,20 @@ class FileModals: """ File-scoped modal variables """ - cellname_implicit: Optional[bool] = None - propname_implicit: Optional[bool] = None - xname_implicit: Optional[bool] = None - textstring_implicit: Optional[bool] = None - propstring_implicit: Optional[bool] = None + cellname_implicit: bool | None = None + propname_implicit: bool | None = None + xname_implicit: bool | None = None + textstring_implicit: bool | None = None + propstring_implicit: bool | None = None - property_target: List[records.Property] + property_target: list[records.Property] within_cell: bool = False within_cblock: bool = False end_has_offset_table: bool = False started: bool = False - def __init__(self, property_target: List[records.Property]) -> None: + def __init__(self, property_target: list[records.Property]) -> None: self.property_target = property_target @@ -53,46 +53,48 @@ class OasisLayout: record objects. Cells are stored using `Cell` objects (different from `records.Cell` record objects). - - Attributes: - (File properties) - version (AString): Version string ('1.0') - unit (real_t): grid steps per micron - validation (Validation): checksum data - - (Names) - cellnames (Dict[int, CellName]): Cell names - propnames (Dict[int, NString]): Property names - xnames (Dict[int, XName]): Custom names - - (Strings) - textstrings (Dict[int, AString]): Text strings - propstrings (Dict[int, AString]): Property strings - - (Data) - layers (List[records.LayerName]): Layer definitions - properties (List[records.Property]): Property values - cells (List[Cell]): Layout cells """ + # File properties version: AString + """File format version string ('1.0')""" + unit: real_t + """grid steps per micron""" + validation: Validation + """checksum data""" - properties: List[records.Property] - cells: List['Cell'] + # Data + properties: list[records.Property] + """Property values""" - cellnames: Dict[int, 'CellName'] - propnames: Dict[int, NString] - xnames: Dict[int, 'XName'] + cells: list['Cell'] + """Layout cells""" - textstrings: Dict[int, AString] - propstrings: Dict[int, AString] - layers: List[records.LayerName] + layers: list[records.LayerName] + """Layer definitions""" + + # Names + cellnames: dict[int, 'CellName'] + """Cell names""" + + propnames: dict[int, NString] + """Property names""" + + xnames: dict[int, 'XName'] + """Custom names""" + + # String storage + textstrings: dict[int, AString] + """Text strings""" + + propstrings: dict[int, AString] + """Property strings""" def __init__( self, unit: real_t, - validation: Optional[Validation] = None, + validation: Validation | None = None, ) -> None: """ Args: @@ -404,26 +406,21 @@ class OasisLayout: class Cell: """ Representation of an OASIS cell. - - Attributes: - name (Union[NString, int]): name or "CellName reference" number - - properties (List[records.Property]): Properties of this cell - placements (List[records.Placement]): Placement record objects - geometry: (List[records.geometry_t]): Geometry record objectes """ - name: Union[NString, int] - properties: List[records.Property] - placements: List[records.Placement] - geometry: List[records.geometry_t] + name: NString | int + """name or "CellName reference" number""" + + properties: list[records.Property] + placements: list[records.Placement] + geometry: list[records.geometry_t] def __init__( self, - name: Union[NString, str, int], + name: NString | str | int, *, - properties: Optional[List[records.Property]] = None, - placements: Optional[List[records.Placement]] = None, - geometry: Optional[List[records.geometry_t]] = None, + properties: list[records.Property] | None = None, + placements: list[records.Placement] | None = None, + geometry: list[records.geometry_t] | None = None, ) -> None: self.name = name if isinstance(name, (NString, int)) else NString(name) self.properties = [] if properties is None else properties @@ -464,12 +461,12 @@ class CellName: with the reference data stripped out. """ nstring: NString - properties: List[records.Property] + properties: list[records.Property] def __init__( self, - nstring: Union[NString, str], - properties: Optional[List[records.Property]] = None, + nstring: NString | str, + properties: list[records.Property] | None = None, ) -> None: """ Args: @@ -531,7 +528,7 @@ class XName: # Mapping from record id to record class. -_GEOMETRY: Dict[int, Type[records.geometry_t]] = { +_GEOMETRY: dict[int, Type[records.geometry_t]] = { 19: records.Text, 20: records.Rectangle, 21: records.Polygon, diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 46beb48..3650262 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -10,7 +10,7 @@ Higher-level code (e.g. monitoring for combinations of records with parse, or code for dealing with nested records in a CBlock) should live in main.py instead. """ -from typing import List, Dict, Tuple, Union, Optional, Sequence, Any, TypeVar, IO +from typing import Union, Sequence, Any, TypeVar, IO from abc import ABCMeta, abstractmethod import copy import math @@ -40,7 +40,7 @@ logger = logging.getLogger(__name__) ''' geometry_t = Union['Text', 'Rectangle', 'Polygon', 'Path', 'Trapezoid', 'CTrapezoid', 'Circle', 'XElement', 'XGeometry'] -pathextension_t = Tuple['PathExtensionScheme', Optional[int]] +pathextension_t = tuple['PathExtensionScheme', int | None] point_list_t = Sequence[Sequence[int]] @@ -49,32 +49,32 @@ class Modals: Modal variables, used to store data about previously-written or -read records. """ - repetition: Optional[repetition_t] = None + repetition: repetition_t | None = None placement_x: int = 0 placement_y: int = 0 - placement_cell: Optional[NString] = None - layer: Optional[int] = None - datatype: Optional[int] = None - text_layer: Optional[int] = None - text_datatype: Optional[int] = None + placement_cell: NString | None = None + layer: int | None = None + datatype: int | None = None + text_layer: int | None = None + text_datatype: int | None = None text_x: int = 0 text_y: int = 0 - text_string: Union[AString, int, None] = None + text_string: AString | int | None = None geometry_x: int = 0 geometry_y: int = 0 xy_relative: bool = False - geometry_w: Optional[int] = None - geometry_h: Optional[int] = None - polygon_point_list: Optional[point_list_t] = None - path_half_width: Optional[int] = None - path_point_list: Optional[point_list_t] = None - path_extension_start: Optional[pathextension_t] = None - path_extension_end: Optional[pathextension_t] = None - ctrapezoid_type: Optional[int] = None - circle_radius: Optional[int] = None - property_value_list: Optional[Sequence[property_value_t]] = None - property_name: Union[int, NString, None] = None - property_is_standard: Optional[bool] = None + geometry_w: int | None = None + geometry_h: int | None = None + polygon_point_list: point_list_t | None = None + path_half_width: int | None = None + path_point_list: point_list_t | None = None + path_extension_start: pathextension_t | None = None + path_extension_end: pathextension_t | None = None + ctrapezoid_type: int | None = None + circle_radius: int | None = None + property_value_list: Sequence[property_value_t] | None = None + property_name: int | NString | None = None + property_is_standard: bool | None = None def __init__(self) -> None: self.reset() @@ -116,17 +116,17 @@ class Modals: T = TypeVar('T') -def verify_modal(var: Optional[T]) -> T: +def verify_modal(var: T | None) -> T: if var is None: raise UnfilledModalError return var -''' - - Records - -''' +# +# +# Records +# +# class Record(metaclass=ABCMeta): """ @@ -231,10 +231,10 @@ class GeometryMixin(metaclass=ABCMeta): """ Mixin defining common functions for geometry records """ - x: Optional[int] - y: Optional[int] - layer: Optional[int] - datatype: Optional[int] + x: int | None + y: int | None + layer: int | None + datatype: int | None def get_x(self) -> int: return verify_modal(self.x) @@ -242,7 +242,7 @@ class GeometryMixin(metaclass=ABCMeta): def get_y(self) -> int: return verify_modal(self.y) - def get_xy(self) -> Tuple[int, int]: + def get_xy(self) -> tuple[int, int]: return (self.get_x(), self.get_y()) def get_layer(self) -> int: @@ -251,15 +251,15 @@ class GeometryMixin(metaclass=ABCMeta): def get_datatype(self) -> int: return verify_modal(self.datatype) - def get_layer_tuple(self) -> Tuple[int, int]: + def get_layer_tuple(self) -> tuple[int, int]: return (self.get_layer(), self.get_datatype()) def read_refname( stream: IO[bytes], - is_present: Union[bool, int], - is_reference: Union[bool, int] - ) -> Union[None, int, NString]: + is_present: bool | int, + is_reference: bool | int, + ) -> int | NString | None: """ Helper function for reading a possibly-absent, possibly-referenced NString. @@ -282,9 +282,9 @@ def read_refname( def read_refstring( stream: IO[bytes], - is_present: Union[bool, int], - is_reference: Union[bool, int], - ) -> Union[None, int, AString]: + is_present: bool | int, + is_reference: bool | int, + ) -> int | AString | None: """ Helper function for reading a possibly-absent, possibly-referenced `AString`. @@ -369,22 +369,21 @@ class XYMode(Record): class Start(Record): """ Start Record (ID 1) - - Attributes: - version (AString): - unit (real_t): positive real number, grid steps per micron - offset_table (Optional[OffsetTable]): If `None` then table must be - placed in the `End` record) """ version: AString + """File format version string""" + unit: real_t - offset_table: Optional[OffsetTable] + """positive real number, grid steps per micron""" + + offset_table: OffsetTable | None + """If `None` then table must be placed in the `End` record""" def __init__( self, unit: real_t, - version: Union[AString, str] = "1.0", - offset_table: Optional[OffsetTable] = None, + version: AString | str = "1.0", + offset_table: OffsetTable | None = None, ) -> None: """ Args @@ -423,7 +422,7 @@ class Start(Record): version = AString.read(stream) unit = read_real(stream) has_offset_table = read_uint(stream) == 0 - offset_table: Optional[OffsetTable] + offset_table: OffsetTable | None if has_offset_table: offset_table = OffsetTable.read(stream) else: @@ -447,19 +446,17 @@ class End(Record): End record (ID 2) The end record is always padded to a total length of 256 bytes. - - Attributes: - offset_table (Optional[OffsetTable]): `None` if offset table was - written into the `Start` record instead - validation (Validation): object containing checksum """ - offset_table: Optional[OffsetTable] + offset_table: OffsetTable | None + """`None` if offset table was written into the `Start` record instead""" + validation: Validation + """object containing checksum""" def __init__( self, validation: Validation, - offset_table: Optional[OffsetTable] = None, + offset_table: OffsetTable | None = None, ) -> None: """ Args: @@ -485,7 +482,7 @@ class End(Record): if record_id != 2: raise InvalidDataError(f'Invalid record id for End {record_id}') if has_offset_table: - offset_table: Optional[OffsetTable] = OffsetTable.read(stream) + offset_table: OffsetTable | None = OffsetTable.read(stream) else: offset_table = None _padding_string = read_bstring(stream) # noqa @@ -514,15 +511,15 @@ class End(Record): class CBlock(Record): """ CBlock (Compressed Block) record (ID 34) - - Attributes: - compression_type (int): `0` for zlib - decompressed_byte_count (int): size after decompressing - compressed_bytes (bytes): compressed data """ compression_type: int + """ `0` for zlib""" + decompressed_byte_count: int + """size after decompressing""" + compressed_bytes: bytes + """compressed data""" def __init__( self, @@ -571,7 +568,7 @@ class CBlock(Record): def from_decompressed( decompressed_bytes: bytes, compression_type: int = 0, - compression_args: Optional[Dict[str, Any]] = None, + compression_args: dict[str, Any] | None = None, ) -> 'CBlock': """ Create a CBlock record from uncompressed data. @@ -600,7 +597,7 @@ class CBlock(Record): return CBlock(compression_type, count, compressed_bytes) - def decompress(self, decompression_args: Optional[Dict[str, Any]] = None) -> bytes: + def decompress(self, decompression_args: dict[str, Any] | None = None) -> bytes: """ Decompress the contents of this CBlock. @@ -630,18 +627,17 @@ class CBlock(Record): class CellName(Record): """ CellName record (ID 3, 4) - - Attributes: - nstring (NString): name - reference_number (Optional[int]): `None` results in implicit assignment """ nstring: NString - reference_number: Optional[int] + """name string""" + + reference_number: int | None + """`None` results in implicit assignment""" def __init__( self, - nstring: Union[NString, str], - reference_number: Optional[int] = None, + nstring: str | NString, + reference_number: int | None = None, ) -> None: """ Args: @@ -667,7 +663,7 @@ class CellName(Record): raise InvalidDataError(f'Invalid record id for CellName {record_id}') nstring = NString.read(stream) if record_id == 4: - reference_number: Optional[int] = read_uint(stream) + reference_number: int | None = read_uint(stream) else: reference_number = None record = CellName(nstring, reference_number) @@ -685,18 +681,17 @@ class CellName(Record): class PropName(Record): """ PropName record (ID 7, 8) - - Attributes: - nstring (NString): name - reference_number (Optional[int]): `None` results in implicit assignment """ nstring: NString - reference_number: Optional[int] = None + """name string""" + + reference_number: int | None = None + """`None` results in implicit assignment""" def __init__( self, - nstring: Union[NString, str], - reference_number: Optional[int] = None, + nstring: str | NString, + reference_number: int | None = None, ) -> None: """ Args: @@ -722,7 +717,7 @@ class PropName(Record): raise InvalidDataError(f'Invalid record id for PropName {record_id}') nstring = NString.read(stream) if record_id == 8: - reference_number: Optional[int] = read_uint(stream) + reference_number: int | None = read_uint(stream) else: reference_number = None record = PropName(nstring, reference_number) @@ -741,18 +736,17 @@ class PropName(Record): class TextString(Record): """ TextString record (ID 5, 6) - - Attributes: - astring (AString): string data - reference_number (Optional[int]): `None` results in implicit assignment """ astring: AString - reference_number: Optional[int] = None + """string contents""" + + reference_number: int | None = None + """`None` results in implicit assignment""" def __init__( self, - string: Union[AString, str], - reference_number: Optional[int] = None, + string: AString | str, + reference_number: int | None = None, ) -> None: """ Args: @@ -778,7 +772,7 @@ class TextString(Record): raise InvalidDataError(f'Invalid record id for TextString: {record_id}') astring = AString.read(stream) if record_id == 6: - reference_number: Optional[int] = read_uint(stream) + reference_number: int | None = read_uint(stream) else: reference_number = None record = TextString(astring, reference_number) @@ -797,18 +791,17 @@ class TextString(Record): class PropString(Record): """ PropString record (ID 9, 10) - - Attributes: - astring (AString): string data - reference_number (Optional[int]): `None` results in implicit assignment """ astring: AString - reference_number: Optional[int] + """string contents""" + + reference_number: int | None + """`None` results in implicit assignment""" def __init__( self, - string: Union[AString, str], - reference_number: Optional[int] = None, + string: AString | str, + reference_number: int | None = None, ) -> None: """ Args: @@ -834,7 +827,7 @@ class PropString(Record): raise InvalidDataError(f'Invalid record id for PropString: {record_id}') astring = AString.read(stream) if record_id == 10: - reference_number: Optional[int] = read_uint(stream) + reference_number: int | None = read_uint(stream) else: reference_number = None record = PropString(astring, reference_number) @@ -853,32 +846,31 @@ class PropString(Record): class LayerName(Record): """ LayerName record (ID 11, 12) - - Attributes: - nstring (NString): name - layer_interval (Tuple[Optional[int], Optional[int]]): bounds on the interval - type_interval (Tuple[Optional[int], Optional[int]]): bounds on the interval - is_textlayer (bool): Is this a text layer? """ nstring: NString - layer_interval: Tuple[Optional[int], Optional[int]] - type_interval: Tuple[Optional[int], Optional[int]] + """name string""" + + layer_interval: tuple[int | None, int | None] + """bounds on the interval""" + + type_interval: tuple[int | None, int | None] + """bounds on the interval""" + is_textlayer: bool + """Is this a text layer?""" def __init__( self, - nstring: Union[NString, str], - layer_interval: Tuple[Optional[int], Optional[int]], - type_interval: Tuple[Optional[int], Optional[int]], + nstring: str | NString, + layer_interval: tuple[int | None, int | None], + type_interval: tuple[int | None, int | None], is_textlayer: bool, ) -> None: """ Args: nstring: The layer name. - layer_interval: Tuple (int or None, int or None) giving bounds - (or lack of thereof) on the layer number. - type_interval: Tuple (int or None, int or None) giving bounds - (or lack of thereof) on the type number. + layer_interval: Tuple giving bounds (or lack of thereof) on the layer number. + type_interval: Tuple giving bounds (or lack of thereof) on the type number. is_textlayer: `True` if the layer is a text layer. """ if isinstance(nstring, NString): @@ -919,22 +911,18 @@ class LayerName(Record): class Property(Record): """ LayerName record (ID 28, 29) - - Attributes: - name (Union[NString, int, None]): `int` is an explicit reference, - `None` is a flag to use Modal) - values (Optional[List[property_value_t]]): List of property values. - is_standard (bool): Whether this is a standard property. """ - name: Optional[Union[NString, int]] - values: Optional[List[property_value_t]] - is_standard: Optional[bool] + name: NString | int | None + """`int` is an explicit reference, `None` is a flag to use Modal""" + values: list[property_value_t] | None + is_standard: bool | None + """Whether this is a standard property.""" def __init__( self, - name: Union[NString, str, int, None] = None, - values: Optional[List[property_value_t]] = None, - is_standard: Optional[bool] = None, + name: NString | str | int | None = None, + values: list[property_value_t] | None= None, + is_standard: bool | None = None, ) -> None: """ Args: @@ -952,10 +940,10 @@ class Property(Record): self.values = values self.is_standard = is_standard - def get_name(self) -> Union[NString, int]: + def get_name(self) -> NString | int: return verify_modal(self.name) # type: ignore - def get_values(self) -> List[property_value_t]: + def get_values(self) -> list[property_value_t]: return verify_modal(self.values) def get_is_standard(self) -> bool: @@ -992,8 +980,8 @@ class Property(Record): value_count = u else: value_count = read_uint(stream) - values: Optional[List[property_value_t]] = [read_property_value(stream) - for _ in range(value_count)] + values: list[property_value_t] | None = [read_property_value(stream) + for _ in range(value_count)] else: values = None # if u != 0: @@ -1041,21 +1029,21 @@ class Property(Record): class XName(Record): """ XName record (ID 30, 31) - - Attributes: - attribute (int): Attribute number - bstring (bytes): XName data - reference_number (Optional[int]): None means to use implicit numbering """ attribute: int + """Attribute number""" + bstring: bytes - reference_number: Optional[int] + """XName data""" + + reference_number: int | None + """None means to use implicit numbering""" def __init__( self, attribute: int, bstring: bytes, - reference_number: Optional[int] = None, + reference_number: int | None = None, ) -> None: """ Args: @@ -1081,7 +1069,7 @@ class XName(Record): attribute = read_uint(stream) bstring = read_bstring(stream) if record_id == 31: - reference_number: Optional[int] = read_uint(stream) + reference_number: int | None = read_uint(stream) else: reference_number = None record = XName(attribute, bstring, reference_number) @@ -1101,20 +1089,20 @@ class XName(Record): class XElement(Record): """ XElement record (ID 32) - - Attributes: - attribute (int): Attribute number. - bstring (bytes): XElement data. """ attribute: int + """Attribute number""" + bstring: bytes - properties: List['Property'] + """XElement data""" + + properties: list['Property'] def __init__( self, attribute: int, bstring: bytes, - properties: Optional[List['Property']] = None, + properties: list['Property'] | None = None, ) -> None: """ Args: @@ -1152,36 +1140,30 @@ class XElement(Record): class XGeometry(Record, GeometryMixin): """ XGeometry record (ID 33) - - Attributes: - attribute (int): Attribute number. - bstring (bytes): XGeometry data. - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): None means reuse modal - y (Optional[int]): None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ attribute: int + """Attribute number""" + bstring: bytes - layer: Optional[int] = None - datatype: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - properties: List['Property'] + """XGeometry data""" + + layer: int | None = None + datatype: int | None = None + x: int | None = None + y: int | None = None + repetition: repetition_t | None = None + properties: list['Property'] def __init__( self, attribute: int, bstring: bytes, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + layer: int | None = None, + datatype: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Args: @@ -1224,7 +1206,7 @@ class XGeometry(Record, GeometryMixin): if z0 or z1 or z2: raise InvalidDataError('Malformed XGeometry header') attribute = read_uint(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -1268,13 +1250,11 @@ class XGeometry(Record, GeometryMixin): class Cell(Record): """ Cell record (ID 13, 14) - - Attributes: - name (Union[int, NString]): int specifies "CellName reference" number """ - name: Union[int, NString] + name: int | NString + """int specifies "CellName reference" number""" - def __init__(self, name: Union[int, str, NString]) -> None: + def __init__(self, name: int | str | NString) -> None: """ Args: name: `NString`, or an int specifying a `CellName` reference number. @@ -1289,7 +1269,7 @@ class Cell(Record): @staticmethod def read(stream: IO[bytes], record_id: int) -> 'Cell': - name: Union[int, NString] + name: int | NString if record_id == 13: name = read_uint(stream) elif record_id == 14: @@ -1314,37 +1294,34 @@ class Cell(Record): class Placement(Record): """ Placement record (ID 17, 18) - - Attributes: - name (Union[NString, int, None]): name, "CellName reference" - number, or reuse modal - magnification (real_t): Magnification factor - angle (real_t): Rotation, degrees counterclockwise - x (Optional[int]): x-offset, None means reuse modal - y (Optional[int]): y-offset, None means reuse modal - repetition (repetition_t or None): Repetition, if any - flip (bool): Whether to perform reflection about the x-axis. - properties (List[Property]): List of property records associate with this record. """ - name: Union[NString, int, None] = None - magnification: Optional[real_t] = None - angle: Optional[real_t] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None + name: int | NString | None = None + """name, "CellName reference" number, or reuse modal""" + + magnification: real_t | None = None + """magnification factor""" + + angle: real_t | None = None + """Rotation, degrees counterclockwise""" + + x: int | None = None + y: int | None = None + repetition: repetition_t | None = None flip: bool - properties: List['Property'] + """Whether to perform reflection about the x-axis""" + + properties: list['Property'] def __init__( self, flip: bool, - name: Union[NString, str, int, None] = None, - magnification: Optional[real_t] = None, - angle: Optional[real_t] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + name: NString | str | int | None = None, + magnification: real_t | None = None, + angle: real_t | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Args: @@ -1371,7 +1348,7 @@ class Placement(Record): self.name = NString(name) self.properties = [] if properties is None else properties - def get_name(self) -> Union[NString, int]: + def get_name(self) -> NString | int: return verify_modal(self.name) # type: ignore def get_x(self) -> int: @@ -1398,7 +1375,7 @@ class Placement(Record): #CNXYRAAF (17) or CNXYRMAF (18) c, n, x, y, r, ma0, ma1, flip = read_bool_byte(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} name = read_refname(stream, c, n) if record_id == 17: aa = (ma0 << 1) | ma1 @@ -1466,33 +1443,24 @@ class Placement(Record): class Text(Record, GeometryMixin): """ Text record (ID 19) - - Attributes: - string (Union[AString, int, None]): None means reuse modal - layer (Optiona[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset, None means reuse modal - y (Optional[int]): y-offset, None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ - string: Optional[Union[AString, int]] = None - layer: Optional[int] = None - datatype: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - properties: List['Property'] + string: AString | int | None = None + layer: int | None = None + datatype: int | None = None + x: int | None = None + y: int | None = None + repetition: repetition_t | None = None + properties: list['Property'] def __init__( self, - string: Union[AString, str, int, None] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + string: AString | str | int | None = None, + layer: int | None = None, + datatype: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Args: @@ -1516,7 +1484,7 @@ class Text(Record, GeometryMixin): self.string = AString(string) self.properties = [] if properties is None else properties - def get_string(self) -> Union[AString, int]: + def get_string(self) -> AString | int: return verify_modal(self.string) # type: ignore def merge_with_modals(self, modals: Modals) -> None: @@ -1542,7 +1510,7 @@ class Text(Record, GeometryMixin): if z0: raise InvalidDataError('Malformed Text header') - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} string = read_refstring(stream, c, n) if l: optional['layer'] = read_uint(stream) @@ -1593,43 +1561,43 @@ class Rectangle(Record, GeometryMixin): Rectangle record (ID 20) (x, y) denotes the lower-left (min-x, min-y) corner of the rectangle. - - Attributes: - is_square (bool): `True` if this is a square. - If `True`, `height` must be `None`. - width (Optional[int]): X-width. `None` means reuse modal. - height (Optional[int]): Y-height. Must be `None` if `is_square` is `True`. - If `is_square` is `False`, `None` means reuse modal. - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset of the rectangle's lower-left (min-x) point. - None means reuse modal. - y (Optional[int]): y-offset of the rectangle's lower-left (min-y) point. - None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any. - properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] - datatype: Optional[int] - width: Optional[int] - height: Optional[int] - x: Optional[int] - y: Optional[int] - repetition: Optional[repetition_t] + layer: int | None + datatype: int | None + width: int | None + """X-width. `None` means reuse modal""" + + height: int | None + """Y-height. Must be `None` if `is_square` is `True`. + If `is_square` is `False`, `None` means reuse modal + """ + + x: int | None + """x-offset of the rectangle's lower-left (min-x) point. + None means reuse modal. + """ + y: int | None + """y-offset of the rectangle's lower-left (min-y) point. + None means reuse modal + """ + + repetition: repetition_t | None is_square: bool - properties: List['Property'] + """If `True`, `height` must be `None`""" + + properties: list['Property'] def __init__( self, is_square: bool = False, - layer: Optional[int] = None, - datatype: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + layer: int | None = None, + datatype: int | None = None, + width: int | None = None, + height: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: self.is_square = is_square self.layer = layer @@ -1679,7 +1647,7 @@ class Rectangle(Record, GeometryMixin): raise InvalidDataError(f'Invalid record id for Rectangle: {record_id}') is_square, w, h, x, y, r, d, l = read_bool_byte(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -1730,42 +1698,38 @@ class Rectangle(Record, GeometryMixin): class Polygon(Record, GeometryMixin): """ Polygon record (ID 21) - - Attributes: - point_list (Optional[point_list_t]): List of offsets from the - initial vertex (x, y) to the remaining vertices, - `[[dx0, dy0], [dx1, dy1], ...]`. - The list is an implicitly closed path, vertices are [int, int], - The initial vertex is located at (x, y) and is not represented - in `point_list`. - `None` means reuse modal. - layer (Optional[int]): Layer number. None means reuse modal - datatype (Optional[int]): Datatype number. None means reuse modal - x (Optional[int]): x-offset of the polygon's first point. - None means reuse modal - y (Optional[int]): y-offset of the polygon's first point. - None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any. - Default no repetition. - properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] - datatype: Optional[int] - x: Optional[int] - y: Optional[int] - repetition: Optional[repetition_t] - point_list: Optional[point_list_t] - properties: List['Property'] + layer: int | None + datatype: int | None + x: int | None + """x-offset of the polygon's first point. + None means reuse modal + """ + y: int | None + """y-offset of the polygon's first point. + None means reuse modal + """ + repetition: repetition_t | None + point_list: point_list_t | None + """ + List of offsets from the initial vertex (x, y) to the remaining + vertices, `[[dx0, dy0], [dx1, dy1], ...]`. + The list is an implicitly closed path, vertices are [int, int]. + The initial vertex is located at (x, y) and is not represented in `point_list`. + `None` means reuse modal. + """ + + properties: list['Property'] def __init__( self, - point_list: Optional[point_list_t] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + point_list: point_list_t | None = None, + layer: int | None = None, + datatype: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: self.layer = layer self.datatype = datatype @@ -1805,7 +1769,7 @@ class Polygon(Record, GeometryMixin): if z0 or z1: raise InvalidDataError('Invalid polygon header') - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -1851,51 +1815,50 @@ class Polygon(Record, GeometryMixin): class Path(Record, GeometryMixin): """ Polygon record (ID 22) - - Attributes: - point_list (Optional[point_list_t]): List of offsets from the - initial vertex (x, y) to the remaining vertices, - `[[dx0, dy0], [dx1, dy1], ...]`. - The initial vertex is located at (x, y) and is not represented - in `point_list`. - Offsets are [int, int]; `None` means reuse modal. - half_width (Optional[int]): None means reuse modal - extension_start (Optional[Tuple]): None means reuse modal. - Tuple is of the form (`PathExtensionScheme`, Optional[int]) - Second value is None unless using `PathExtensionScheme.Arbitrary` - Value determines extension past start point. - extension_end (Optional[Tuple]): Same form as `extension_end`. - Value determines extension past end point. - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset, None means reuse modal - y (Optional[int]): y-offset, None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] = None - datatype: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - point_list: Optional[point_list_t] = None - half_width: Optional[int] = None - extension_start: Optional[pathextension_t] = None - extension_end: Optional[pathextension_t] = None - properties: List['Property'] + layer: int | None = None + datatype: int | None = None + x: int | None = None + y: int | None = None + repetition: repetition_t | None = None + point_list: point_list_t | None = None + """ + List of offsets from the initial vertex (x, y) to the remaining vertices, + `[[dx0, dy0], [dx1, dy1], ...]`. + The initial vertex is located at (x, y) and is not represented in `point_list`. + Offsets are [int, int]; `None` means reuse modal. + """ + + half_width: int | None = None + """None means reuse modal""" + + extension_start: pathextension_t | None = None + """ + `None` means reuse modal. + Tuple is of the form (`PathExtensionScheme`, int | None) + Second value is None unless using `PathExtensionScheme.Arbitrary` + Value determines extension past start point. + """ + + extension_end: pathextension_t | None = None + """ + Same form as `extension_end`. Value determines extension past end point. + """ + + properties: list['Property'] def __init__( self, - point_list: Optional[point_list_t] = None, - half_width: Optional[int] = None, - extension_start: Optional[pathextension_t] = None, - extension_end: Optional[pathextension_t] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + point_list: point_list_t | None = None, + half_width: int | None = None, + extension_start: pathextension_t | None = None, + extension_end: pathextension_t | None = None, + layer: int | None = None, + datatype: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: self.layer = layer self.datatype = datatype @@ -1946,7 +1909,7 @@ class Path(Record, GeometryMixin): raise InvalidDataError(f'Invalid record id for Path: {record_id}') e, w, p, x, y, r, d, l = read_bool_byte(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -1958,7 +1921,7 @@ class Path(Record, GeometryMixin): scheme_end = scheme & 0b11 scheme_start = (scheme >> 2) & 0b11 - def get_pathext(ext_scheme: int) -> Optional[pathextension_t]: + def get_pathext(ext_scheme: int) -> pathextension_t | None: if ext_scheme == 0: return None elif ext_scheme == 1: @@ -2031,55 +1994,61 @@ class Trapezoid(Record, GeometryMixin): Trapezoid with at least two sides parallel to the x- or y-axis. (x, y) denotes the lower-left (min-x, min-y) corner of the trapezoid's bounding box. - - Attributes: - delta_a (Optional[int]): If horizontal, signed x-distance from top left - vertex to bottom left vertex. If vertical, signed y-distance from - bottom left vertex to bottom right vertex. - None means reuse modal. - delta_b (Optional[int]): If horizontal, signed x-distance from bottom right - vertex to top right vertex. If vertical, signed y-distance from top - right vertex to top left vertex. - None means reuse modal. - is_vertical (bool): `True` if the left and right sides are aligned to - the y-axis. If the trapezoid is a rectangle, either `True` or `False` - can be used. - width (Optional[int]): Bounding box x-width, None means reuse modal. - height (Optional[int]): Bounding box y-height, None means reuse modal. - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset to lower-left corner of the trapezoid's bounding box. - None means reuse modal - y (Optional[int]): y-offset to lower-left corner of the trapezoid's bounding box. - None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] = None - datatype: Optional[int] = None - width: Optional[int] = None - height: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None + layer: int | None = None + datatype: int | None = None + width: int | None = None + """Bounding box x-width, None means reuse modal.""" + + height: int | None = None + """Bounding box y-height, None means reuse modal.""" + + x: int | None = None + """x-offset to lower-left corner of the trapezoid's bounding box. + None means reuse modal + """ + + y: int | None = None + """y-offset to lower-left corner of the trapezoid's bounding box. + None means reuse modal + """ + + repetition: repetition_t | None = None delta_a: int = 0 + """ + If horizontal, signed x-distance from top left vertex to bottom left vertex. + If vertical, signed y-distance from bottom left vertex to bottom right vertex. + None means reuse modal. + """ + delta_b: int = 0 + """ + If horizontal, signed x-distance from bottom right vertex to top right vertex. + If vertical, signed y-distance from top right vertex to top left vertex. + None means reuse modal. + """ + is_vertical: bool - properties: List['Property'] + """ + `True` if the left and right sides are aligned to the y-axis. + If the trapezoid is a rectangle, either `True` or `False` can be used. + """ + + properties: list['Property'] def __init__( self, is_vertical: bool, delta_a: int = 0, delta_b: int = 0, - layer: Optional[int] = None, - datatype: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + layer: int | None = None, + datatype: int | None = None, + width: int | None = None, + height: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Raises: @@ -2141,7 +2110,7 @@ class Trapezoid(Record, GeometryMixin): raise InvalidDataError(f'Invalid record id for Trapezoid: {record_id}') is_vertical, w, h, x, y, r, d, l = read_bool_byte(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -2241,44 +2210,45 @@ class CTrapezoid(Record, GeometryMixin): w = h w = 2h w = h set h = None set w = None set h = None - - Attributes: - ctrapezoid_type (Optional[int]): See above for details. - None means reuse modal. - width (Optional[int]): Bounding box x-width. - None means unnecessary, or reuse modal if necessary. - height (Optional[int]): Bounding box y-height. - None means unnecessary, or reuse modal if necessary. - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset of lower-left (min-x) point of bounding box. - None means reuse modal - y (Optional[int]): y-offset of lower-left (min-y) point of bounding box. - None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ - ctrapezoid_type: Optional[int] = None - layer: Optional[int] = None - datatype: Optional[int] = None - width: Optional[int] = None - height: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - properties: List['Property'] + ctrapezoid_type: int | None = None + """See class docstring for details. None means reuse modal.""" + + layer: int | None = None + datatype: int | None = None + width: int | None = None + """width: Bounding box x-width + None means unnecessary, or reuse modal if necessary. + """ + + height: int | None = None + """Bounding box y-height. + None means unnecessary, or reuse modal if necessary. + """ + + x: int | None = None + """x-offset of lower-left (min-x) point of bounding box. + None means reuse modal + """ + y: int | None = None + """y-offset of lower-left (min-y) point of bounding box. + None means reuse modal + """ + + repetition: repetition_t | None = None + properties: list['Property'] def __init__( self, - ctrapezoid_type: Optional[int] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + ctrapezoid_type: int | None = None, + layer: int | None = None, + datatype: int | None = None, + width: int | None = None, + height: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Raises: @@ -2363,7 +2333,7 @@ class CTrapezoid(Record, GeometryMixin): raise InvalidDataError(f'Invalid record id for CTrapezoid: {record_id}') t, w, h, x, y, r, d, l = read_bool_byte(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -2441,33 +2411,24 @@ class CTrapezoid(Record, GeometryMixin): class Circle(Record, GeometryMixin): """ Circle record (ID 27) - - Attributes: - radius (Optional[int]): None means reuse modal - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset, None means reuse modal - y (Optional[int]): y-offset, None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] - datatype: Optional[int] - x: Optional[int] - y: Optional[int] - repetition: Optional[repetition_t] - radius: Optional[int] - properties: List['Property'] + layer: int | None + datatype: int | None + x: int | None + y: int | None + repetition: repetition_t | None + radius: int | None + properties: list['Property'] def __init__( self, - radius: Optional[int] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + radius: int | None = None, + layer: int | None = None, + datatype: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Args: @@ -2516,7 +2477,7 @@ class Circle(Record, GeometryMixin): if z0 or z1: raise InvalidDataError('Malformed circle header') - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: diff --git a/pyproject.toml b/pyproject.toml index 146471e..3e6d0d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ classifiers = [ "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", ] -requires-python = ">=3.8" +requires-python = ">=3.10" dynamic = ["version"] dependencies = [ ] From f9d4cfec33f80e1317b5ca0fac2e1b3fb0fda5af Mon Sep 17 00:00:00 2001 From: jan Date: Thu, 19 Jan 2023 22:20:50 -0800 Subject: [PATCH 06/40] WIP indentation and f-string conversions --- fatamorgana/basic.py | 210 ++++----- fatamorgana/main.py | 52 ++- fatamorgana/records.py | 657 ++++++++++++++-------------- fatamorgana/test/build_testfiles.py | 3 +- 4 files changed, 468 insertions(+), 454 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 6194ab0..b745f2f 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -11,7 +11,8 @@ import io import warnings try: - import numpy # type: ignore + import numpy + from numpy.typing import NDArray _USE_NUMPY = True except ImportError: _USE_NUMPY = False @@ -161,7 +162,7 @@ def _py_write_bool_byte(stream: io.BufferedIOBase, bits: Tuple[Union[bool, int], InvalidDataError if didn't receive 8 bits. """ if len(bits) != 8: - raise InvalidDataError('write_bool_byte received {} bits, requires 8'.format(len(bits))) + raise InvalidDataError(f'write_bool_byte received {len(bits)} bits, requires 8') byte = 0 for i, bit in enumerate(reversed(bits)): byte |= bit << i @@ -169,7 +170,7 @@ def _py_write_bool_byte(stream: io.BufferedIOBase, bits: Tuple[Union[bool, int], if _USE_NUMPY: - def _np_read_bool_byte(stream: io.BufferedIOBase) -> List[bool]: + def _np_read_bool_byte(stream: io.BufferedIOBase) -> NDArray[numpy.uint8]: """ Read a single byte from the stream, and interpret its bits as a list of 8 booleans. @@ -198,13 +199,13 @@ if _USE_NUMPY: InvalidDataError if didn't receive 8 bits. """ if len(bits) != 8: - raise InvalidDataError('write_bool_byte received {} bits, requires 8'.format(len(bits))) + raise InvalidDataError(f'write_bool_byte received {len(bits)} bits, requires 8') return stream.write(numpy.packbits(bits)[0]) - read_bool_byte = _np_read_bool_byte + read_bool_byte = _np_read_bool_byte # type: ignore write_bool_byte = _np_write_bool_byte else: - read_bool_byte = _py_read_bool_byte + read_bool_byte = _py_read_bool_byte # type: ignore write_bool_byte = _py_write_bool_byte def read_uint(stream: io.BufferedIOBase) -> int: @@ -249,7 +250,7 @@ def write_uint(stream: io.BufferedIOBase, n: int) -> int: SignedError: if `n` is negative. """ if n < 0: - raise SignedError('uint must be positive: {}'.format(n)) + raise SignedError(f'uint must be positive: {n}') current = n byte_list = [] @@ -392,7 +393,7 @@ def write_ratio(stream: io.BufferedIOBase, r: Fraction) -> int: SignedError: if r is negative. """ if r < 0: - raise SignedError('Ratio must be unsigned: {}'.format(r)) + raise SignedError(f'Ratio must be unsigned: {r}') size = write_uint(stream, r.numerator) size += write_uint(stream, r.denominator) return size @@ -456,7 +457,7 @@ def write_float64(stream: io.BufferedIOBase, f: float) -> int: return stream.write(b) -def read_real(stream: io.BufferedIOBase, real_type: int = None) -> real_t: +def read_real(stream: io.BufferedIOBase, real_type: Optional[int] = None) -> real_t: """ Read a real number from the stream. @@ -503,13 +504,14 @@ def read_real(stream: io.BufferedIOBase, real_type: int = None) -> real_t: return read_float32(stream) if real_type == 7: return read_float64(stream) - raise InvalidDataError('Invalid real type: {}'.format(real_type)) + raise InvalidDataError(f'Invalid real type: {real_type}') -def write_real(stream: io.BufferedIOBase, - r: real_t, - force_float32: bool = False - ) -> int: +def write_real( + stream: io.BufferedIOBase, + r: real_t, + force_float32: bool = False + ) -> int: """ Write a real number to the stream. See read_real() for format details. @@ -561,7 +563,7 @@ class NString: """ _string: str - def __init__(self, string_or_bytes: Union[bytes, str]): + def __init__(self, string_or_bytes: Union[bytes, str]) -> None: """ Args: string_or_bytes: Content of the `NString`. @@ -576,9 +578,9 @@ class NString: return self._string @string.setter - def string(self, string: str): + def string(self, string: str) -> None: if len(string) == 0 or not all(0x21 <= ord(c) <= 0x7e for c in string): - raise InvalidDataError('Invalid n-string {}'.format(string)) + raise InvalidDataError(f'Invalid n-string {string}') self._string = string @property @@ -586,9 +588,9 @@ class NString: return self._string.encode('ascii') @bytes.setter - def bytes(self, bstring: bytes): + def bytes(self, bstring: bytes) -> None: if len(bstring) == 0 or not all(0x21 <= c <= 0x7e for c in bstring): - raise InvalidDataError('Invalid n-string {!r}'.format(bstring)) + raise InvalidDataError(f'Invalid n-string {bstring!r}') self._string = bstring.decode('ascii') @staticmethod @@ -675,7 +677,7 @@ class AString: """ _string: str - def __init__(self, string_or_bytes: Union[bytes, str]): + def __init__(self, string_or_bytes: Union[bytes, str]) -> None: """ Args: string_or_bytes: Content of the AString. @@ -690,9 +692,9 @@ class AString: return self._string @string.setter - def string(self, string: str): + def string(self, string: str) -> None: if not all(0x20 <= ord(c) <= 0x7e for c in string): - raise InvalidDataError('Invalid a-string {}'.format(string)) + raise InvalidDataError(f'Invalid a-string "{string}"') self._string = string @property @@ -700,9 +702,9 @@ class AString: return self._string.encode('ascii') @bytes.setter - def bytes(self, bstring: bytes): + def bytes(self, bstring: bytes) -> None: if not all(0x20 <= c <= 0x7e for c in bstring): - raise InvalidDataError('Invalid a-string {!r}'.format(bstring)) + raise InvalidDataError(f'Invalid a-string "{bstring!r}"') self._string = bstring.decode('ascii') @staticmethod @@ -786,10 +788,10 @@ class ManhattanDelta: vertical (bool): `True` if aligned along y-axis value (int): signed length of the vector """ - vertical = None # type: bool - value = None # type: int + vertical: bool + value: int - def __init__(self, x: int, y: int): + def __init__(self, x: int, y: int) -> None: """ One of `x` or `y` _must_ be zero! @@ -801,7 +803,7 @@ class ManhattanDelta: y = int(y) if x != 0: if y != 0: - raise InvalidDataError('Non-Manhattan ManhattanDelta ({}, {})'.format(x, y)) + raise InvalidDataError(f'Non-Manhattan ManhattanDelta ({x}, {y})') self.vertical = False self.value = x else: @@ -884,7 +886,7 @@ class ManhattanDelta: return hasattr(other, 'as_list') and self.as_list() == other.as_list() def __repr__(self) -> str: - return '{}'.format(self.as_list()) + return str(self.as_list()) class OctangularDelta: @@ -910,7 +912,7 @@ class OctangularDelta: proj_mag: int octangle: int - def __init__(self, x: int, y: int): + def __init__(self, x: int, y: int) -> None: """ Either `abs(x)==abs(y)`, `x==0`, or `y==0` _must_ be true! @@ -932,7 +934,7 @@ class OctangularDelta: self.proj_mag = abs(x) self.octangle = (1 << 2) | (yn << 1) | (xn != yn) else: - raise InvalidDataError('Non-octangular delta! ({}, {})'.format(x, y)) + raise InvalidDataError(f'Non-octangular delta! ({x}, {y})') def as_list(self) -> List[int]: """ @@ -1020,7 +1022,7 @@ class OctangularDelta: return hasattr(other, 'as_list') and self.as_list() == other.as_list() def __repr__(self) -> str: - return '{}'.format(self.as_list()) + return str(self.as_list()) class Delta: @@ -1034,7 +1036,7 @@ class Delta: x: int y: int - def __init__(self, x: int, y: int): + def __init__(self, x: int, y: int) -> None: """ Args: x: x-displacement @@ -1104,7 +1106,7 @@ class Delta: return hasattr(other, 'as_list') and self.as_list() == other.as_list() def __repr__(self) -> str: - return '{}'.format(self.as_list()) + return str(self.as_list()) def read_repetition(stream: io.BufferedIOBase) -> repetition_t: @@ -1128,7 +1130,7 @@ def read_repetition(stream: io.BufferedIOBase) -> repetition_t: elif rtype in (4, 5, 6, 7, 10, 11): return ArbitraryRepetition.read(stream, rtype) else: - raise InvalidDataError('Unexpected repetition type: {}'.format(rtype)) + raise InvalidDataError(f'Unexpected repetition type: {rtype}') def write_repetition(stream: io.BufferedIOBase, repetition: repetition_t) -> int: @@ -1186,11 +1188,12 @@ class GridRepetition: a_count: int b_count: Optional[int] = None - def __init__(self, - a_vector: List[int], - a_count: int, - b_vector: Optional[List[int]] = None, - b_count: Optional[int] = None): + def __init__( + self, + a_vector: Sequence[int], + a_count: int, + b_vector: Optional[Sequence[int]] = None, + b_count: Optional[int] = None): """ Args: a_vector: First lattice vector, of the form `[x, y]`. @@ -1219,10 +1222,10 @@ class GridRepetition: warnings.warn('Removed b_count and b_vector since b_count == 1') if a_count < 2: - raise InvalidDataError('Repetition has too-small a_count: ' - '{}'.format(a_count)) - self.a_vector = a_vector - self.b_vector = b_vector + raise InvalidDataError(f'Repetition has too-small a_count: {a_count}') + + self.a_vector = list(a_vector) + self.b_vector = list(b_vector) if b_vector is not None else None self.a_count = a_count self.b_count = b_count @@ -1270,8 +1273,7 @@ class GridRepetition: a_vector = Delta.read(stream).as_list() b_vector = None else: - raise InvalidDataError('Invalid type for grid repetition ' - '{}'.format(repetition_type)) + raise InvalidDataError(f'Invalid type for grid repetition {repetition_type}') return GridRepetition(a_vector, na, b_vector, nb) def write(self, stream: io.BufferedIOBase) -> int: @@ -1292,7 +1294,7 @@ class GridRepetition: """ if self.b_vector is None or self.b_count is None: if self.b_vector is not None or self.b_count is not None: - raise InvalidDataError('Malformed repetition {}'.format(self)) + raise InvalidDataError(f'Malformed repetition {self}') if self.a_vector[1] == 0: size = write_uint(stream, 2) @@ -1343,8 +1345,7 @@ class GridRepetition: return True def __repr__(self) -> str: - return 'GridRepetition: ({} : {} | {} : {})'.format(self.a_count, self.a_vector, - self.b_count, self.b_vector) + return f'GridRepetition: ({self.a_count} : {self.a_vector} | {self.b_count} : {self.b_vector})' class ArbitraryRepetition: @@ -1360,16 +1361,18 @@ class ArbitraryRepetition: x_displacements: List[int] y_displacements: List[int] - def __init__(self, - x_displacements: List[int], - y_displacements: List[int]): + def __init__( + self, + x_displacements: Sequence[int], + y_displacements: Sequence[int], + ) -> None: """ Args: x_displacements: x-displacements between consecutive elements y_displacements: y-displacements between consecutive elements """ - self.x_displacements = x_displacements - self.y_displacements = y_displacements + self.x_displacements = list(x_displacements) + self.y_displacements = list(y_displacements) @staticmethod def read(stream: io.BufferedIOBase, repetition_type: int) -> 'ArbitraryRepetition': @@ -1423,7 +1426,7 @@ class ArbitraryRepetition: x_displacements.append(x * mult) y_displacements.append(y * mult) else: - raise InvalidDataError('Invalid ArbitraryRepetition repetition_type: {}'.format(repetition_type)) + raise InvalidDataError(f'Invalid ArbitraryRepetition repetition_type: {repetition_type}') return ArbitraryRepetition(x_displacements, y_displacements) def write(self, stream: io.BufferedIOBase) -> int: @@ -1497,12 +1500,13 @@ class ArbitraryRepetition: and self.y_displacements == other.y_displacements) def __repr__(self) -> str: - return 'ArbitraryRepetition: x{} y{})'.format(self.x_displacements, self.y_displacements) + return f'ArbitraryRepetition: x{self.x_displacements} y{self.y_displacements})' -def read_point_list(stream: io.BufferedIOBase, - implicit_closed: bool, - ) -> List[List[int]]: +def read_point_list( + stream: io.BufferedIOBase, + implicit_closed: bool, + ) -> List[List[int]]: """ Read a point list from a stream. @@ -1583,16 +1587,17 @@ def read_point_list(stream: io.BufferedIOBase, if _USE_NUMPY: points = numpy.vstack((points, close_points)) else: - points.append(close_points) + points += close_points return points -def write_point_list(stream: io.BufferedIOBase, - points: List[Sequence[int]], - fast: bool = False, - implicit_closed: bool = True - ) -> int: +def write_point_list( + stream: io.BufferedIOBase, + points: List[Sequence[int]], + fast: bool = False, + implicit_closed: bool = True + ) -> int: """ Write a point list to a stream. @@ -1689,19 +1694,19 @@ def write_point_list(stream: io.BufferedIOBase, deltas = [Delta(*points[0])] + [Delta(x, y) for x, y in diff] else: previous = [0, 0] - diff = [] + diffl = [] for point in points: d = [point[0] - previous[0], point[1] - previous[1]] previous = point - diff.append(d) + diffl.append(d) - if sum(sum(p) for p in points) < sum(sum(d) for d in diff) * decision_factor: + if sum(sum(p) for p in points) < sum(sum(d) for d in diffl) * decision_factor: list_type = 4 deltas = [Delta(x, y) for x, y in points] else: list_type = 5 - deltas = [Delta(x, y) for x, y in diff] + deltas = [Delta(x, y) for x, y in diffl] size = write_uint(stream, list_type) size += write_uint(stream, len(points)) @@ -1720,7 +1725,7 @@ class PropStringReference: ref: int reference_type: Type - def __init__(self, ref: int, ref_type: Type): + def __init__(self, ref: int, ref_type: Type) -> None: """ :param ref: ID number of the target. :param ref_type: Type of the target. One of bytes, NString, AString. @@ -1732,7 +1737,7 @@ class PropStringReference: return isinstance(other, type(self)) and self.ref == other.ref and self.reference_type == other.reference_type def __repr__(self) -> str: - return '[{} : {}]'.format(self.ref_type, self.ref) + return f'[{self.ref_type} : {self.ref}]' def read_property_value(stream: io.BufferedIOBase) -> property_value_t: @@ -1789,15 +1794,16 @@ def read_property_value(stream: io.BufferedIOBase) -> property_value_t: ref = read_uint(stream) return PropStringReference(ref, ref_type) else: - raise InvalidDataError('Invalid property type: {}'.format(prop_type)) + raise InvalidDataError(f'Invalid property type: {prop_type}') -def write_property_value(stream: io.BufferedIOBase, - value: property_value_t, - force_real: bool = False, - force_signed_int: bool = False, - force_float32: bool = False - ) -> int: +def write_property_value( + stream: io.BufferedIOBase, + value: property_value_t, + force_real: bool = False, + force_signed_int: bool = False, + force_float32: bool = False, + ) -> int: """ Write a property value to a stream. @@ -1844,7 +1850,7 @@ def write_property_value(stream: io.BufferedIOBase, size = write_uint(stream, 15) size += write_uint(stream, value.ref) else: - raise Exception('Invalid property type: {} ({})'.format(type(value), value)) + raise Exception(f'Invalid property type: {type(value)} ({value})') return size @@ -1885,13 +1891,14 @@ def read_interval(stream: io.BufferedIOBase) -> Tuple[Optional[int], Optional[in elif interval_type == 4: return read_uint(stream), read_uint(stream) else: - raise InvalidDataError('Unrecognized interval type: {}'.format(interval_type)) + raise InvalidDataError(f'Unrecognized interval type: {interval_type}') -def write_interval(stream: io.BufferedIOBase, - min_bound: Optional[int] = None, - max_bound: Optional[int] = None - ) -> int: +def write_interval( + stream: io.BufferedIOBase, + min_bound: Optional[int] = None, + max_bound: Optional[int] = None, + ) -> int: """ Write an interval to a stream. Used for layer data; see `read_interval()` for format details. @@ -1942,7 +1949,7 @@ class OffsetEntry: strict: bool = False offset: int = 0 - def __init__(self, strict: bool = False, offset: int = 0): + def __init__(self, strict: bool = False, offset: int = 0) -> None: """ Args: strict: `True` if the records referenced are written in @@ -1983,7 +1990,7 @@ class OffsetEntry: return write_uint(stream, self.strict) + write_uint(stream, self.offset) def __repr__(self) -> str: - return 'Offset(s: {}, o: {})'.format(self.strict, self.offset) + return f'Offset(s: {self.strict}, o: {self.offset})' class OffsetTable: @@ -2015,13 +2022,15 @@ class OffsetTable: layernames: OffsetEntry xnames: OffsetEntry - def __init__(self, - cellnames: Optional[OffsetEntry] = None, - textstrings: Optional[OffsetEntry] = None, - propnames: Optional[OffsetEntry] = None, - propstrings: Optional[OffsetEntry] = None, - layernames: Optional[OffsetEntry] = None, - xnames: Optional[OffsetEntry] = None): + def __init__( + self, + cellnames: Optional[OffsetEntry] = None, + textstrings: Optional[OffsetEntry] = None, + propnames: Optional[OffsetEntry] = None, + propstrings: Optional[OffsetEntry] = None, + layernames: Optional[OffsetEntry] = None, + xnames: Optional[OffsetEntry] = None, + ) -> None: """ All parameters default to a non-strict entry with offset `0`. @@ -2127,7 +2136,7 @@ def write_u32(stream: io.BufferedIOBase, n: int) -> int: SignedError: if `n` is negative. """ if n < 0: - raise SignedError('Negative u32: {}'.format(n)) + raise SignedError(f'Negative u32: {n}') return stream.write(struct.pack(' None: """ Args: checksum_type: 0,1,2 (No checksum, crc32, checksum32) @@ -2207,18 +2216,16 @@ class Validation: if self.checksum_type == 0: return write_uint(stream, 0) elif self.checksum is None: - raise InvalidDataError('Checksum is empty but type is ' - '{}'.format(self.checksum_type)) + raise InvalidDataError(f'Checksum is empty but type is {self.checksum_type}') elif self.checksum_type == 1: return write_uint(stream, 1) + write_u32(stream, self.checksum) elif self.checksum_type == 2: return write_uint(stream, 2) + write_u32(stream, self.checksum) else: - raise InvalidDataError('Unrecognized checksum type: ' - '{}'.format(self.checksum_type)) + raise InvalidDataError(f'Unrecognized checksum type: {self.checksum_type}') def __repr__(self) -> str: - return 'Validation(type: {} sum: {})'.format(self.checksum_type, self.checksum) + return f'Validation(type: {self.checksum_type} sum: {self.checksum})' def write_magic_bytes(stream: io.BufferedIOBase) -> int: @@ -2247,5 +2254,4 @@ def read_magic_bytes(stream: io.BufferedIOBase): """ magic = _read(stream, len(MAGIC_BYTES)) if magic != MAGIC_BYTES: - raise InvalidDataError('Could not read magic bytes, ' - 'found {!r}'.format(magic)) + raise InvalidDataError(f'Could not read magic bytes, found {magic!r}') diff --git a/fatamorgana/main.py b/fatamorgana/main.py index b73d4c2..a11af4e 100644 --- a/fatamorgana/main.py +++ b/fatamorgana/main.py @@ -40,7 +40,7 @@ class FileModals: end_has_offset_table: bool = False started: bool = False - def __init__(self, property_target: List[records.Property]): + def __init__(self, property_target: List[records.Property]) -> None: self.property_target = property_target @@ -89,7 +89,11 @@ class OasisLayout: propstrings: Dict[int, AString] layers: List[records.LayerName] - def __init__(self, unit: real_t, validation: Validation = None): + def __init__( + self, + unit: real_t, + validation: Optional[Validation] = None, + ) -> None: """ Args: unit: Real number (i.e. int, float, or `Fraction`), grid steps per micron. @@ -132,11 +136,12 @@ class OasisLayout: pass return layout - def read_record(self, - stream: io.BufferedIOBase, - modals: Modals, - file_state: FileModals - ) -> bool: + def read_record( + self, + stream: io.BufferedIOBase, + modals: Modals, + file_state: FileModals + ) -> bool: """ Read a single record of unspecified type from a stream, adding its contents into this `OasisLayout` object. @@ -162,7 +167,7 @@ class OasisLayout: else: raise e - logger.info('read_record of type {} at position 0x{:x}'.format(record_id, stream.tell())) + logger.info(f'read_record of type {record_id} at position 0x{stream.tell():x}') record: Record @@ -182,7 +187,7 @@ class OasisLayout: # Make sure order is valid (eg, no out-of-cell geometry) if not file_state.started and record_id != 1: - raise InvalidRecordError('Non-Start record {} before Start'.format(record_id)) + raise InvalidRecordError(f'Non-Start record {record_id} before Start') if record_id == 1: if file_state.started: raise InvalidRecordError('Duplicate Start record') @@ -201,7 +206,7 @@ class OasisLayout: elif record_id in (13, 14): file_state.within_cell = True else: - raise InvalidRecordError('Unknown record id: {}'.format(record_id)) + raise InvalidRecordError(f'Unknown record id: {record_id}') if record_id == 0: ''' Pad ''' @@ -335,7 +340,7 @@ class OasisLayout: self.cells[-1].geometry.append(record) file_state.property_target = record.properties else: - raise InvalidRecordError('Unknown record id: {}'.format(record_id)) + raise InvalidRecordError(f'Unknown record id: {record_id}') return False def write(self, stream: io.BufferedIOBase) -> int: @@ -412,13 +417,14 @@ class Cell: placements: List[records.Placement] geometry: List[records.geometry_t] - def __init__(self, - name: Union[NString, str, int], - *, - properties: Optional[List[records.Property]] = None, - placements: Optional[List[records.Placement]] = None, - geometry: Optional[List[records.geometry_t]] = None, - ): + def __init__( + self, + name: Union[NString, str, int], + *, + properties: Optional[List[records.Property]] = None, + placements: Optional[List[records.Placement]] = None, + geometry: Optional[List[records.geometry_t]] = None, + ) -> None: self.name = name if isinstance(name, (NString, int)) else NString(name) self.properties = [] if properties is None else properties self.placements = [] if placements is None else placements @@ -460,9 +466,11 @@ class CellName: nstring: NString properties: List[records.Property] - def __init__(self, - nstring: Union[NString, str], - properties: Optional[List[records.Property]] = None): + def __init__( + self, + nstring: Union[NString, str], + properties: Optional[List[records.Property]] = None, + ) -> None: """ Args: nstring: The contained string. @@ -499,7 +507,7 @@ class XName: attribute: int bstring: bytes - def __init__(self, attribute: int, bstring: bytes): + def __init__(self, attribute: int, bstring: bytes) -> None: """ Args: attribute: Attribute number. diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 19d50f1..453ad03 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -29,7 +29,7 @@ from .basic import ( ) if _USE_NUMPY: - import numpy # type: ignore + import numpy logger = logging.getLogger(__name__) @@ -76,10 +76,10 @@ class Modals: property_name: Union[int, NString, None] = None property_is_standard: Optional[bool] = None - def __init__(self): + def __init__(self) -> None: self.reset() - def reset(self): + def reset(self) -> None: """ Resets all modal variables to their default values. Default values are: @@ -133,7 +133,7 @@ class Record(metaclass=ABCMeta): Common interface for records. """ @abstractmethod - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: """ Copy all defined values from this record into the modal variables. Fill all undefined values in this record from the modal variables. @@ -144,7 +144,7 @@ class Record(metaclass=ABCMeta): pass @abstractmethod - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: """ Check all defined values in this record against those in the modal variables. If any values are equal, remove them from @@ -224,7 +224,7 @@ class Record(metaclass=ABCMeta): return copy.deepcopy(self) def __repr__(self) -> str: - return '{}: {}'.format(self.__class__, pprint.pformat(self.__dict__)) + return f'{self.__class__}: ' + pprint.pformat(self.__dict__) class GeometryMixin(metaclass=ABCMeta): @@ -255,10 +255,11 @@ class GeometryMixin(metaclass=ABCMeta): return (self.get_layer(), self.get_datatype()) -def read_refname(stream: io.BufferedIOBase, - is_present: Union[bool, int], - is_reference: Union[bool, int] - ) -> Union[None, int, NString]: +def read_refname( + stream: io.BufferedIOBase, + is_present: Union[bool, int], + is_reference: Union[bool, int] + ) -> Union[None, int, NString]: """ Helper function for reading a possibly-absent, possibly-referenced NString. @@ -279,10 +280,11 @@ def read_refname(stream: io.BufferedIOBase, return NString.read(stream) -def read_refstring(stream: io.BufferedIOBase, - is_present: Union[bool, int], - is_reference: Union[bool, int], - ) -> Union[None, int, AString]: +def read_refstring( + stream: io.BufferedIOBase, + is_present: Union[bool, int], + is_reference: Union[bool, int], + ) -> Union[None, int, AString]: """ Helper function for reading a possibly-absent, possibly-referenced `AString`. @@ -307,19 +309,18 @@ class Pad(Record): """ Pad record (ID 0) """ - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: pass - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: pass @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Pad': if record_id != 0: - raise InvalidDataError('Invalid record id for Pad ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Pad {record_id}') record = Pad() - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -329,31 +330,28 @@ class Pad(Record): class XYMode(Record): """ XYMode record (ID 15, 16) - - Attributes: - relative (bool): default `False` """ - relative: bool = False + relative: bool @property def absolute(self) -> bool: return not self.relative @absolute.setter - def absolute(self, b: bool): + def absolute(self, b: bool) -> None: self.relative = not b - def __init__(self, relative: bool): + def __init__(self, relative: bool) -> None: """ Args: relative: `True` if the mode is 'relative', `False` if 'absolute'. """ self.relative = relative - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.xy_relative = self.relative - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: pass @staticmethod @@ -361,7 +359,7 @@ class XYMode(Record): if record_id not in (15, 16): raise InvalidDataError('Invalid record id for XYMode') record = XYMode(record_id == 16) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -373,19 +371,21 @@ class Start(Record): Start Record (ID 1) Attributes: - version (AString): "1.0" + version (AString): unit (real_t): positive real number, grid steps per micron offset_table (Optional[OffsetTable]): If `None` then table must be placed in the `End` record) """ version: AString unit: real_t - offset_table: Optional[OffsetTable] = None + offset_table: Optional[OffsetTable] - def __init__(self, - unit: real_t, - version: Union[AString, str] = None, - offset_table: Optional[OffsetTable] = None): + def __init__( + self, + unit: real_t, + version: Union[AString, str] = "1.0", + offset_table: Optional[OffsetTable] = None, + ) -> None: """ Args unit: Grid steps per micron (positive real number) @@ -394,37 +394,32 @@ class Start(Record): it in the `End` record instead. """ if unit <= 0: - raise InvalidDataError('Non-positive unit: {}'.format(unit)) + raise InvalidDataError(f'Non-positive unit: {unit}') if math.isnan(unit): raise InvalidDataError('NaN unit') if math.isinf(unit): raise InvalidDataError('Non-finite unit') self.unit = unit - if version is None: - version = AString('1.0') if isinstance(version, AString): self.version = version else: self.version = AString(version) if self.version.string != '1.0': - raise InvalidDataError('Invalid version string, ' - 'only "1.0" is allowed: ' - + str(self.version.string)) + raise InvalidDataError(f'Invalid version string, only "1.0" is allowed: "{self.version.string}"') self.offset_table = offset_table - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Start': if record_id != 1: - raise InvalidDataError('Invalid record id for Start: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Start: {record_id}') version = AString.read(stream) unit = read_real(stream) has_offset_table = read_uint(stream) == 0 @@ -434,7 +429,7 @@ class Start(Record): else: offset_table = None record = Start(unit, version, offset_table) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -458,12 +453,14 @@ class End(Record): written into the `Start` record instead validation (Validation): object containing checksum """ - offset_table: Optional[OffsetTable] = None + offset_table: Optional[OffsetTable] validation: Validation - def __init__(self, - validation: Validation, - offset_table: Optional[OffsetTable] = None): + def __init__( + self, + validation: Validation, + offset_table: Optional[OffsetTable] = None, + ) -> None: """ Args: validation: `Validation` object for this file. @@ -480,12 +477,13 @@ class End(Record): pass @staticmethod - def read(stream: io.BufferedIOBase, - record_id: int, - has_offset_table: bool - ) -> 'End': + def read( + stream: io.BufferedIOBase, + record_id: int, + has_offset_table: bool + ) -> 'End': if record_id != 2: - raise InvalidDataError('Invalid record id for End {}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for End {record_id}') if has_offset_table: offset_table: Optional[OffsetTable] = OffsetTable.read(stream) else: @@ -493,7 +491,7 @@ class End(Record): _padding_string = read_bstring(stream) # noqa validation = Validation.read(stream) record = End(validation, offset_table) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -526,10 +524,12 @@ class CBlock(Record): decompressed_byte_count: int compressed_bytes: bytes - def __init__(self, - compression_type: int, - decompressed_byte_count: int, - compressed_bytes: bytes): + def __init__( + self, + compression_type: int, + decompressed_byte_count: int, + compressed_bytes: bytes, + ) -> None: """ Args: compression_type: `0` (zlib) @@ -537,29 +537,27 @@ class CBlock(Record): compressed_bytes: The compressed data. """ if compression_type != 0: - raise InvalidDataError('CBlock: Invalid compression scheme ' - '{}'.format(compression_type)) + raise InvalidDataError(f'CBlock: Invalid compression scheme {compression_type}') self.compression_type = compression_type self.decompressed_byte_count = decompressed_byte_count self.compressed_bytes = compressed_bytes - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: pass - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: pass @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'CBlock': if record_id != 34: - raise InvalidDataError('Invalid record id for CBlock: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for CBlock: {record_id}') compression_type = read_uint(stream) decompressed_count = read_uint(stream) compressed_bytes = read_bstring(stream) record = CBlock(compression_type, decompressed_count, compressed_bytes) - logger.debug('CBlock ending at 0x{:x} was read successfully'.format(stream.tell())) + logger.debug(f'CBlock ending at 0x{stream.tell():x} was read successfully') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -570,10 +568,11 @@ class CBlock(Record): return size @staticmethod - def from_decompressed(decompressed_bytes: bytes, - compression_type: int = 0, - compression_args: Dict = None - ) -> 'CBlock': + def from_decompressed( + decompressed_bytes: bytes, + compression_type: int = 0, + compression_args: Optional[Dict[str, Any]] = None, + ) -> 'CBlock': """ Create a CBlock record from uncompressed data. @@ -597,12 +596,11 @@ class CBlock(Record): compressed_bytes = (compressor.compress(decompressed_bytes) + compressor.flush()) else: - raise InvalidDataError('Unknown compression type: ' - '{}'.format(compression_type)) + raise InvalidDataError(f'Unknown compression type: {compression_type}') return CBlock(compression_type, count, compressed_bytes) - def decompress(self, decompression_args: Dict = None) -> bytes: + def decompress(self, decompression_args: Optional[Dict[str, Any]] = None) -> bytes: """ Decompress the contents of this CBlock. @@ -625,8 +623,7 @@ class CBlock(Record): if len(decompressed_bytes) != self.decompressed_byte_count: raise InvalidDataError('Decompressed data length does not match!') else: - raise InvalidDataError('Unknown compression type: ' - '{}'.format(self.compression_type)) + raise InvalidDataError(f'Unknown compression type: {self.compression_type}') return decompressed_bytes @@ -639,11 +636,13 @@ class CellName(Record): reference_number (Optional[int]): `None` results in implicit assignment """ nstring: NString - reference_number: Optional[int] = None + reference_number: Optional[int] - def __init__(self, - nstring: Union[NString, str], - reference_number: int = None): + def __init__( + self, + nstring: Union[NString, str], + reference_number: Optional[int] = None, + ) -> None: """ Args: nstring: The contained string. @@ -656,24 +655,23 @@ class CellName(Record): self.nstring = NString(nstring) self.reference_number = reference_number - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'CellName': if record_id not in (3, 4): - raise InvalidDataError('Invalid record id for CellName ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for CellName {record_id}') nstring = NString.read(stream) if record_id == 4: reference_number: Optional[int] = read_uint(stream) else: reference_number = None record = CellName(nstring, reference_number) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -695,9 +693,11 @@ class PropName(Record): nstring: NString reference_number: Optional[int] = None - def __init__(self, - nstring: Union[NString, str], - reference_number: int = None): + def __init__( + self, + nstring: Union[NString, str], + reference_number: Optional[int] = None, + ) -> None: """ Args: nstring: The contained string. @@ -719,15 +719,14 @@ class PropName(Record): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'PropName': if record_id not in (7, 8): - raise InvalidDataError('Invalid record id for PropName ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for PropName {record_id}') nstring = NString.read(stream) if record_id == 8: reference_number: Optional[int] = read_uint(stream) else: reference_number = None record = PropName(nstring, reference_number) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -750,9 +749,11 @@ class TextString(Record): astring: AString reference_number: Optional[int] = None - def __init__(self, - string: Union[AString, str], - reference_number: int = None): + def __init__( + self, + string: Union[AString, str], + reference_number: Optional[int] = None, + ) -> None: """ Args: string: The contained string. @@ -765,24 +766,23 @@ class TextString(Record): self.astring = AString(string) self.reference_number = reference_number - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'TextString': if record_id not in (5, 6): - raise InvalidDataError('Invalid record id for TextString: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for TextString: {record_id}') astring = AString.read(stream) if record_id == 6: reference_number: Optional[int] = read_uint(stream) else: reference_number = None record = TextString(astring, reference_number) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -803,11 +803,13 @@ class PropString(Record): reference_number (Optional[int]): `None` results in implicit assignment """ astring: AString - reference_number: Optional[int] = None + reference_number: Optional[int] - def __init__(self, - string: Union[AString, str], - reference_number: int = None): + def __init__( + self, + string: Union[AString, str], + reference_number: Optional[int] = None, + ) -> None: """ Args: string: The contained string. @@ -820,24 +822,23 @@ class PropString(Record): self.astring = AString(string) self.reference_number = reference_number - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'PropString': if record_id not in (9, 10): - raise InvalidDataError('Invalid record id for PropString: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for PropString: {record_id}') astring = AString.read(stream) if record_id == 10: reference_number: Optional[int] = read_uint(stream) else: reference_number = None record = PropString(astring, reference_number) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -860,15 +861,17 @@ class LayerName(Record): is_textlayer (bool): Is this a text layer? """ nstring: NString - layer_interval: Tuple - type_interval: Tuple + layer_interval: Tuple[Optional[int], Optional[int]] + type_interval: Tuple[Optional[int], Optional[int]] is_textlayer: bool - def __init__(self, - nstring: Union[NString, str], - layer_interval: Tuple, - type_interval: Tuple, - is_textlayer: bool): + def __init__( + self, + nstring: Union[NString, str], + layer_interval: Tuple[Optional[int], Optional[int]], + type_interval: Tuple[Optional[int], Optional[int]], + is_textlayer: bool, + ) -> None: """ Args: nstring: The layer name. @@ -886,23 +889,22 @@ class LayerName(Record): self.type_interval = type_interval self.is_textlayer = is_textlayer - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'LayerName': if record_id not in (11, 12): - raise InvalidDataError('Invalid record id for LayerName: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for LayerName: {record_id}') is_textlayer = (record_id == 12) nstring = NString.read(stream) layer_interval = read_interval(stream) type_interval = read_interval(stream) record = LayerName(nstring, layer_interval, type_interval, is_textlayer) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -924,14 +926,16 @@ class Property(Record): values (Optional[List[property_value_t]]): List of property values. is_standard (bool): Whether this is a standard property. """ - name: Optional[Union[NString, int]] = None - values: Optional[List[property_value_t]] = None - is_standard: Optional[bool] = None + name: Optional[Union[NString, int]] + values: Optional[List[property_value_t]] + is_standard: Optional[bool] - def __init__(self, - name: Union[NString, str, int, None] = None, - values: Optional[List[property_value_t]] = None, - is_standard: Optional[bool] = None): + def __init__( + self, + name: Union[NString, str, int, None] = None, + values: Optional[List[property_value_t]] = None, + is_standard: Optional[bool] = None, + ) -> None: """ Args: name: Property name, reference number, or `None` (i.e. use modal) @@ -957,12 +961,12 @@ class Property(Record): def get_is_standard(self) -> bool: return verify_modal(self.is_standard) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_field(self, 'name', modals, 'property_name') adjust_field(self, 'values', modals, 'property_value_list') adjust_field(self, 'is_standard', modals, 'property_is_standard') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_field(self, 'name', modals, 'property_name') dedup_field(self, 'values', modals, 'property_value_list') if self.values is None and self.name is None: @@ -971,8 +975,7 @@ class Property(Record): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Property': if record_id not in (28, 29): - raise InvalidDataError('Invalid record id for PropertyValue: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for PropertyValue: {record_id}') if record_id == 29: record = Property() else: @@ -997,7 +1000,7 @@ class Property(Record): # logger.warning('Malformed property record header; requested modal' # ' values but had nonzero count. Ignoring count.') record = Property(name, values, bool(s)) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1005,8 +1008,7 @@ class Property(Record): return write_uint(stream, 29) else: if self.is_standard is None: - raise InvalidDataError('Property has value or name, ' - 'but no is_standard flag!') + raise InvalidDataError('Property has value or name, but no is_standard flag!') if self.values is not None: value_count = len(self.values) v = 0 @@ -1047,12 +1049,14 @@ class XName(Record): """ attribute: int bstring: bytes - reference_number: Optional[int] = None + reference_number: Optional[int] - def __init__(self, - attribute: int, - bstring: bytes, - reference_number: int = None): + def __init__( + self, + attribute: int, + bstring: bytes, + reference_number: Optional[int] = None, + ) -> None: """ Args: attribute: Attribute number. @@ -1064,17 +1068,16 @@ class XName(Record): self.bstring = bstring self.reference_number = reference_number - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'XName': if record_id not in (30, 31): - raise InvalidDataError('Invalid record id for XName: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for XName: {record_id}') attribute = read_uint(stream) bstring = read_bstring(stream) if record_id == 31: @@ -1082,7 +1085,7 @@ class XName(Record): else: reference_number = None record = XName(attribute, bstring, reference_number) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1107,10 +1110,12 @@ class XElement(Record): bstring: bytes properties: List['Property'] - def __init__(self, - attribute: int, - bstring: bytes, - properties: Optional[List['Property']] = None): + def __init__( + self, + attribute: int, + bstring: bytes, + properties: Optional[List['Property']] = None, + ) -> None: """ Args: attribute: Attribute number. @@ -1121,21 +1126,20 @@ class XElement(Record): self.bstring = bstring self.properties = [] if properties is None else properties - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: pass - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: pass @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'XElement': if record_id != 32: - raise InvalidDataError('Invalid record id for XElement: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for XElement: {record_id}') attribute = read_uint(stream) bstring = read_bstring(stream) record = XElement(attribute, bstring) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1168,15 +1172,17 @@ class XGeometry(Record, GeometryMixin): repetition: Optional[repetition_t] = None properties: List['Property'] - def __init__(self, - attribute: int, - bstring: bytes, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + attribute: int, + bstring: bytes, + layer: Optional[int] = None, + datatype: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Args: attribute: Attribute number for this XGeometry. @@ -1197,13 +1203,13 @@ class XGeometry(Record, GeometryMixin): self.repetition = repetition self.properties = [] if properties is None else properties - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') adjust_field(self, 'datatype', modals, 'datatype') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -1212,8 +1218,7 @@ class XGeometry(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'XGeometry': if record_id != 33: - raise InvalidDataError('Invalid record id for XGeometry: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for XGeometry: {record_id}') z0, z1, z2, x, y, r, d, l = read_bool_byte(stream) if z0 or z1 or z2: @@ -1233,7 +1238,7 @@ class XGeometry(Record, GeometryMixin): optional['repetition'] = read_repetition(stream) record = XGeometry(attribute, bstring, **optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1269,17 +1274,17 @@ class Cell(Record): """ name: Union[int, NString] - def __init__(self, name: Union[int, str, NString]): + def __init__(self, name: Union[int, str, NString]) -> None: """ Args: name: `NString`, or an int specifying a `CellName` reference number. """ self.name = name if isinstance(name, (int, NString)) else NString(name) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod @@ -1290,10 +1295,9 @@ class Cell(Record): elif record_id == 14: name = NString.read(stream) else: - raise InvalidDataError('Invalid record id for Cell: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Cell: {record_id}') record = Cell(name) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1331,15 +1335,17 @@ class Placement(Record): flip: bool properties: List['Property'] - def __init__(self, - flip: bool, - name: Union[NString, str, int, None] = None, - magnification: Optional[real_t] = None, - angle: Optional[real_t] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + flip: bool, + name: Union[NString, str, int, None] = None, + magnification: Optional[real_t] = None, + angle: Optional[real_t] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Args: flip: Whether to perform reflection about the x-axis. @@ -1374,12 +1380,12 @@ class Placement(Record): def get_y(self) -> int: return verify_modal(self.y) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'placement_x', 'placement_y') adjust_repetition(self, modals) adjust_field(self, 'name', modals, 'placement_cell') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'placement_x', 'placement_y') dedup_repetition(self, modals) dedup_field(self, 'name', modals, 'placement_cell') @@ -1387,8 +1393,7 @@ class Placement(Record): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Placement': if record_id not in (17, 18): - raise InvalidDataError('Invalid record id for Placement: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Placement: {record_id}') #CNXYRAAF (17) or CNXYRMAF (18) c, n, x, y, r, ma0, ma1, flip = read_bool_byte(stream) @@ -1413,7 +1418,7 @@ class Placement(Record): optional['repetition'] = read_repetition(stream) record = Placement(flip, name, **optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1479,14 +1484,16 @@ class Text(Record, GeometryMixin): repetition: Optional[repetition_t] = None properties: List['Property'] - def __init__(self, - string: Union[AString, str, int, None] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + string: Union[AString, str, int, None] = None, + layer: Optional[int] = None, + datatype: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Args: string: Text content, or `TextString` reference number. @@ -1512,14 +1519,14 @@ class Text(Record, GeometryMixin): def get_string(self) -> Union[AString, int]: return verify_modal(self.string) # type: ignore - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'text_x', 'text_y') adjust_repetition(self, modals) adjust_field(self, 'string', modals, 'text_string') adjust_field(self, 'layer', modals, 'text_layer') adjust_field(self, 'datatype', modals, 'text_datatype') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'text_x', 'text_y') dedup_repetition(self, modals) dedup_field(self, 'string', modals, 'text_string') @@ -1529,8 +1536,7 @@ class Text(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Text': if record_id != 19: - raise InvalidDataError('Invalid record id for Text: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Text: {record_id}') z0, c, n, x, y, r, d, l = read_bool_byte(stream) if z0: @@ -1550,7 +1556,7 @@ class Text(Record, GeometryMixin): optional['repetition'] = read_repetition(stream) record = Text(string, **optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1613,16 +1619,18 @@ class Rectangle(Record, GeometryMixin): is_square: bool = False properties: List['Property'] - def __init__(self, - is_square: bool = False, - layer: Optional[int] = None, - datatype: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + is_square: bool = False, + layer: Optional[int] = None, + datatype: Optional[int] = None, + width: Optional[int] = None, + height: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: self.is_square = is_square self.layer = layer self.datatype = datatype @@ -1643,7 +1651,7 @@ class Rectangle(Record, GeometryMixin): return verify_modal(self.width) return verify_modal(self.height) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') @@ -1654,7 +1662,7 @@ class Rectangle(Record, GeometryMixin): else: adjust_field(self, 'height', modals, 'geometry_h') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -1668,8 +1676,7 @@ class Rectangle(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Rectangle': if record_id != 20: - raise InvalidDataError('Invalid record id for Rectangle: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Rectangle: {record_id}') is_square, w, h, x, y, r, d, l = read_bool_byte(stream) optional: Dict[str, Any] = {} @@ -1688,7 +1695,7 @@ class Rectangle(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = Rectangle(is_square, **optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -1750,14 +1757,16 @@ class Polygon(Record, GeometryMixin): point_list: Optional[point_list_t] = None properties: List['Property'] - def __init__(self, - point_list: Optional[point_list_t] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + point_list: Optional[point_list_t] = None, + layer: Optional[int] = None, + datatype: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: self.layer = layer self.datatype = datatype self.x = x @@ -1773,14 +1782,14 @@ class Polygon(Record, GeometryMixin): def get_point_list(self) -> point_list_t: return verify_modal(self.point_list) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') adjust_field(self, 'datatype', modals, 'datatype') adjust_field(self, 'point_list', modals, 'polygon_point_list') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -1790,8 +1799,7 @@ class Polygon(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Polygon': if record_id != 21: - raise InvalidDataError('Invalid record id for Polygon: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Polygon: {record_id}') z0, z1, p, x, y, r, d, l = read_bool_byte(stream) if z0 or z1: @@ -1811,7 +1819,7 @@ class Polygon(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = Polygon(**optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug('Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase, fast: bool = False) -> int: @@ -1876,17 +1884,19 @@ class Path(Record, GeometryMixin): extension_end: Optional[pathextension_t] = None properties: List['Property'] - def __init__(self, - point_list: Optional[point_list_t] = None, - half_width: Optional[int] = None, - extension_start: Optional[pathextension_t] = None, - extension_end: Optional[pathextension_t] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + point_list: Optional[point_list_t] = None, + half_width: Optional[int] = None, + extension_start: Optional[pathextension_t] = None, + extension_end: Optional[pathextension_t] = None, + layer: Optional[int] = None, + datatype: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: self.layer = layer self.datatype = datatype self.x = x @@ -1910,7 +1920,7 @@ class Path(Record, GeometryMixin): def get_extension_end(self) -> pathextension_t: return verify_modal(self.extension_end) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') @@ -1920,7 +1930,7 @@ class Path(Record, GeometryMixin): adjust_field(self, 'extension_start', modals, 'path_extension_start') adjust_field(self, 'extension_end', modals, 'path_extension_end') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -1933,8 +1943,7 @@ class Path(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Path': if record_id != 22: - raise InvalidDataError('Invalid record id for Path: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Path: {record_id}') e, w, p, x, y, r, d, l = read_bool_byte(stream) optional: Dict[str, Any] = {} @@ -1959,7 +1968,7 @@ class Path(Record, GeometryMixin): elif ext_scheme == 3: return PathExtensionScheme.Arbitrary, read_sint(stream) else: - raise InvalidDataError('Invalid ext_scheme: {}'.format(ext_scheme)) + raise InvalidDataError(f'Invalid ext_scheme: {ext_scheme}') optional['extension_start'] = get_pathext(scheme_start) optional['extension_end'] = get_pathext(scheme_end) @@ -1972,7 +1981,7 @@ class Path(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = Path(**optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase, fast: bool = False) -> int: @@ -2058,18 +2067,20 @@ class Trapezoid(Record, GeometryMixin): is_vertical: bool properties: List['Property'] - def __init__(self, - is_vertical: bool, - delta_a: int = 0, - delta_b: int = 0, - layer: int = None, - datatype: int = None, - width: int = None, - height: int = None, - x: int = None, - y: int = None, - repetition: repetition_t = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + is_vertical: bool, + delta_a: int = 0, + delta_b: int = 0, + layer: Optional[int] = None, + datatype: Optional[int] = None, + width: Optional[int] = None, + height: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Raises: InvalidDataError: if dimensions are impossible. @@ -2088,12 +2099,10 @@ class Trapezoid(Record, GeometryMixin): if self.is_vertical: if height is not None and delta_b - delta_a > height: - raise InvalidDataError('Trapezoid: h < delta_b - delta_a' - + ' ({} < {} - {})'.format(height, delta_b, delta_a)) + raise InvalidDataError(f'Trapezoid: h < delta_b - delta_a ({height} < {delta_b} - {delta_a})') else: if width is not None and delta_b - delta_a > width: - raise InvalidDataError('Trapezoid: w < delta_b - delta_a' - + ' ({} < {} - {})'.format(width, delta_b, delta_a)) + raise InvalidDataError(f'Trapezoid: w < delta_b - delta_a ({width} < {delta_b} - {delta_a})') def get_is_vertical(self) -> bool: return verify_modal(self.is_vertical) @@ -2110,7 +2119,7 @@ class Trapezoid(Record, GeometryMixin): def get_height(self) -> int: return verify_modal(self.height) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') @@ -2118,7 +2127,7 @@ class Trapezoid(Record, GeometryMixin): adjust_field(self, 'width', modals, 'geometry_w') adjust_field(self, 'height', modals, 'geometry_h') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -2129,8 +2138,7 @@ class Trapezoid(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Trapezoid': if record_id not in (23, 24, 25): - raise InvalidDataError('Invalid record id for Trapezoid: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Trapezoid: {record_id}') is_vertical, w, h, x, y, r, d, l = read_bool_byte(stream) optional: Dict[str, Any] = {} @@ -2153,7 +2161,7 @@ class Trapezoid(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = Trapezoid(bool(is_vertical), **optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -2260,16 +2268,18 @@ class CTrapezoid(Record, GeometryMixin): repetition: Optional[repetition_t] = None properties: List['Property'] - def __init__(self, - ctrapezoid_type: int = None, - layer: int = None, - datatype: int = None, - width: int = None, - height: int = None, - x: int = None, - y: int = None, - repetition: repetition_t = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + ctrapezoid_type: Optional[int] = None, + layer: Optional[int] = None, + datatype: Optional[int] = None, + width: Optional[int] = None, + height: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Raises: InvalidDataError: if dimensions are invalid. @@ -2303,7 +2313,7 @@ class CTrapezoid(Record, GeometryMixin): return verify_modal(self.height) return verify_modal(self.width) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') @@ -2312,21 +2322,19 @@ class CTrapezoid(Record, GeometryMixin): if self.ctrapezoid_type in (20, 21): if self.width is not None: - raise InvalidDataError('CTrapezoid has spurious width entry: ' - '{}'.format(self.width)) + raise InvalidDataError(f'CTrapezoid has spurious width entry: {self.width}') else: adjust_field(self, 'width', modals, 'geometry_w') if self.ctrapezoid_type in (16, 17, 18, 19, 22, 23, 25): if self.height is not None: - raise InvalidDataError('CTrapezoid has spurious height entry: ' - '{}'.format(self.height)) + raise InvalidDataError(f'CTrapezoid has spurious height entry: {self.height}') else: adjust_field(self, 'height', modals, 'geometry_h') self.check_valid() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -2337,15 +2345,13 @@ class CTrapezoid(Record, GeometryMixin): if self.ctrapezoid_type in (20, 21): if self.width is not None: - raise InvalidDataError('CTrapezoid has spurious width entry: ' - '{}'.format(self.width)) + raise InvalidDataError(f'CTrapezoid has spurious width entry: {self.width}') else: dedup_field(self, 'width', modals, 'geometry_w') if self.ctrapezoid_type in (16, 17, 18, 19, 22, 23, 25): if self.height is not None: - raise InvalidDataError('CTrapezoid has spurious height entry: ' - '{}'.format(self.height)) + raise InvalidDataError(f'CTrapezoid has spurious height entry: {self.height}') else: dedup_field(self, 'height', modals, 'geometry_h') @@ -2354,8 +2360,7 @@ class CTrapezoid(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'CTrapezoid': if record_id != 26: - raise InvalidDataError('Invalid record id for CTrapezoid: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for CTrapezoid: {record_id}') t, w, h, x, y, r, d, l = read_bool_byte(stream) optional: Dict[str, Any] = {} @@ -2376,7 +2381,7 @@ class CTrapezoid(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = CTrapezoid(**optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -2409,35 +2414,28 @@ class CTrapezoid(Record, GeometryMixin): size += self.repetition.write(stream) # type: ignore return size - def check_valid(self): + def check_valid(self) -> None: ctrapezoid_type = self.ctrapezoid_type width = self.width height = self.height if ctrapezoid_type in (20, 21) and width is not None: - raise InvalidDataError('CTrapezoid has spurious width entry: ' - '{}'.format(width)) + raise InvalidDataError(f'CTrapezoid has spurious width entry: {width}') if ctrapezoid_type in (16, 17, 18, 19, 22, 23, 25) and height is not None: - raise InvalidDataError('CTrapezoid has spurious height entry: ' - '{}'.format(height)) + raise InvalidDataError(f'CTrapezoid has spurious height entry: {height}') if width is not None and height is not None: if ctrapezoid_type in range(0, 4) and width < height: - raise InvalidDataError('CTrapezoid has width < height' - ' ({} < {})'.format(width, height)) + raise InvalidDataError(f'CTrapezoid has width < height ({width} < {height})') if ctrapezoid_type in range(4, 8) and width < 2 * height: - raise InvalidDataError('CTrapezoid has width < 2*height' - ' ({} < 2 * {})'.format(width, height)) + raise InvalidDataError(f'CTrapezoid has width < 2*height ({width} < 2 * {height})') if ctrapezoid_type in range(8, 12) and width > height: - raise InvalidDataError('CTrapezoid has width > height' - ' ({} > {})'.format(width, height)) + raise InvalidDataError(f'CTrapezoid has width > height ({width} > {height})') if ctrapezoid_type in range(12, 16) and 2 * width > height: - raise InvalidDataError('CTrapezoid has 2*width > height' - ' ({} > 2 * {})'.format(width, height)) + raise InvalidDataError(f'CTrapezoid has 2*width > height ({width} > 2 * {height})') if ctrapezoid_type is not None and ctrapezoid_type not in range(0, 26): - raise InvalidDataError('CTrapezoid has invalid type: ' - '{}'.format(ctrapezoid_type)) + raise InvalidDataError(f'CTrapezoid has invalid type: {ctrapezoid_type}') class Circle(Record, GeometryMixin): @@ -2453,22 +2451,24 @@ class Circle(Record, GeometryMixin): repetition (Optional[repetition_t]): Repetition, if any properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] = None - datatype: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - radius: Optional[int] = None + layer: Optional[int] + datatype: Optional[int] + x: Optional[int] + y: Optional[int] + repetition: Optional[repetition_t] + radius: Optional[int] properties: List['Property'] - def __init__(self, - radius: int = None, - layer: int = None, - datatype: int = None, - x: int = None, - y: int = None, - repetition: repetition_t = None, - properties: Optional[List['Property']] = None): + def __init__( + self, + radius: Optional[int] = None, + layer: Optional[int] = None, + datatype: Optional[int] = None, + x: Optional[int] = None, + y: Optional[int] = None, + repetition: Optional[repetition_t] = None, + properties: Optional[List['Property']] = None, + ) -> None: """ Args: radius: Radius. Default `None` (reuse modal). @@ -2493,14 +2493,14 @@ class Circle(Record, GeometryMixin): def get_radius(self) -> int: return verify_modal(self.radius) - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: adjust_coordinates(self, modals, 'geometry_x', 'geometry_y') adjust_repetition(self, modals) adjust_field(self, 'layer', modals, 'layer') adjust_field(self, 'datatype', modals, 'datatype') adjust_field(self, 'radius', modals, 'circle_radius') - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: dedup_coordinates(self, modals, 'geometry_x', 'geometry_y') dedup_repetition(self, modals) dedup_field(self, 'layer', modals, 'layer') @@ -2510,8 +2510,7 @@ class Circle(Record, GeometryMixin): @staticmethod def read(stream: io.BufferedIOBase, record_id: int) -> 'Circle': if record_id != 27: - raise InvalidDataError('Invalid record id for Circle: ' - '{}'.format(record_id)) + raise InvalidDataError(f'Invalid record id for Circle: {record_id}') z0, z1, has_radius, x, y, r, d, l = read_bool_byte(stream) if z0 or z1: @@ -2531,7 +2530,7 @@ class Circle(Record, GeometryMixin): if r: optional['repetition'] = read_repetition(stream) record = Circle(**optional) - logger.debug('Record ending at 0x{:x}:\n {}'.format(stream.tell(), record)) + logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: io.BufferedIOBase) -> int: @@ -2559,7 +2558,7 @@ class Circle(Record, GeometryMixin): return size -def adjust_repetition(record, modals: Modals): +def adjust_repetition(record, modals: Modals) -> None: """ Merge the record's repetition entry with the one in the modals @@ -2581,7 +2580,7 @@ def adjust_repetition(record, modals: Modals): modals.repetition = copy.copy(record.repetition) -def adjust_field(record, r_field: str, modals: Modals, m_field: str): +def adjust_field(record, r_field: str, modals: Modals, m_field: str) -> None: """ Merge `record.r_field` with `modals.m_field` @@ -2602,10 +2601,10 @@ def adjust_field(record, r_field: str, modals: Modals, m_field: str): if m is not None: setattr(record, r_field, copy.copy(m)) else: - raise InvalidDataError('Unfillable field: {}'.format(m_field)) + raise InvalidDataError(f'Unfillable field: {m_field}') -def adjust_coordinates(record, modals: Modals, mx_field: str, my_field: str): +def adjust_coordinates(record, modals: Modals, mx_field: str, my_field: str) -> None: """ Merge `record.x` and `record.y` with `modals.mx_field` and `modals.my_field`, taking into account the value of `modals.xy_relative`. @@ -2639,7 +2638,7 @@ def adjust_coordinates(record, modals: Modals, mx_field: str, my_field: str): # TODO: Clarify the docs on the dedup_* functions -def dedup_repetition(record, modals: Modals): +def dedup_repetition(record, modals: Modals) -> None: """ Deduplicate the record's repetition entry with the one in the modals. Update the one in the modals if they are different. @@ -2666,7 +2665,7 @@ def dedup_repetition(record, modals: Modals): modals.repetition = record.repetition -def dedup_field(record, r_field: str, modals: Modals, m_field: str): +def dedup_field(record, r_field: str, modals: Modals, m_field: str) -> None: """ Deduplicate `record.r_field` using `modals.m_field` Update the `modals.m_field` if they are different. @@ -2699,7 +2698,7 @@ def dedup_field(record, r_field: str, modals: Modals, m_field: str): raise InvalidDataError('Unfillable field') -def dedup_coordinates(record, modals: Modals, mx_field: str, my_field: str): +def dedup_coordinates(record, modals: Modals, mx_field: str, my_field: str) -> None: """ Deduplicate `record.x` and `record.y` using `modals.mx_field` and `modals.my_field`, taking into account the value of `modals.xy_relative`. diff --git a/fatamorgana/test/build_testfiles.py b/fatamorgana/test/build_testfiles.py index 0dedfc4..e776c61 100644 --- a/fatamorgana/test/build_testfiles.py +++ b/fatamorgana/test/build_testfiles.py @@ -12,7 +12,8 @@ from . import ( test_files_circles, test_files_ctrapezoids, test_files_trapezoids, test_files_placements, test_files_paths, test_files_modals, test_files_polygons, test_files_rectangles, test_files_empty, - test_files_texts, test_files_cells) + test_files_texts, test_files_cells, + ) def build_file(num: str, func: Callable[[BufferedIOBase], BufferedIOBase]) -> None: From b2928c8b1c8aa570133ca86b2ffb27d3eba6b5b3 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Thu, 26 Jan 2023 12:47:09 -0800 Subject: [PATCH 07/40] Use IO[bytes] instead of BinaryIO wherever possible --- fatamorgana/basic.py | 125 +++++++++++++++++++------------------- fatamorgana/main.py | 10 ++-- fatamorgana/records.py | 132 ++++++++++++++++++++--------------------- 3 files changed, 134 insertions(+), 133 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index b745f2f..2e41b6c 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -2,7 +2,7 @@ This module contains all datatypes and parsing/writing functions for all abstractions below the 'record' or 'block' level. """ -from typing import List, Tuple, Type, Union, Optional, Any, Sequence +from typing import List, Tuple, Type, Union, Optional, Any, Sequence, IO from fractions import Fraction from enum import Enum import math @@ -24,6 +24,7 @@ except ImportError: real_t = Union[int, float, Fraction] repetition_t = Union['ReuseRepetition', 'GridRepetition', 'ArbitraryRepetition'] property_value_t = Union[int, bytes, 'AString', 'NString', 'PropStringReference', float, Fraction] +bytes_t = bytes class FatamorganaError(Exception): @@ -85,7 +86,7 @@ MAGIC_BYTES: bytes = b'%SEMI-OASIS\r\n' ''' Basic IO ''' -def _read(stream: io.BufferedIOBase, n: int) -> bytes: +def _read(stream: IO[bytes], n: int) -> bytes: """ Read n bytes from the stream. Raise an EOFError if there were not enough bytes in the stream. @@ -106,7 +107,7 @@ def _read(stream: io.BufferedIOBase, n: int) -> bytes: return b -def read_byte(stream: io.BufferedIOBase) -> int: +def read_byte(stream: IO[bytes]) -> int: """ Read a single byte and return it. @@ -119,7 +120,7 @@ def read_byte(stream: io.BufferedIOBase) -> int: return _read(stream, 1)[0] -def write_byte(stream: io.BufferedIOBase, n: int) -> int: +def write_byte(stream: IO[bytes], n: int) -> int: """ Write a single byte to the stream. @@ -132,7 +133,7 @@ def write_byte(stream: io.BufferedIOBase, n: int) -> int: return stream.write(bytes((n,))) -def _py_read_bool_byte(stream: io.BufferedIOBase) -> List[bool]: +def _py_read_bool_byte(stream: IO[bytes]) -> List[bool]: """ Read a single byte from the stream, and interpret its bits as a list of 8 booleans. @@ -147,7 +148,7 @@ def _py_read_bool_byte(stream: io.BufferedIOBase) -> List[bool]: bits = [bool((byte >> i) & 0x01) for i in reversed(range(8))] return bits -def _py_write_bool_byte(stream: io.BufferedIOBase, bits: Tuple[Union[bool, int], ...]) -> int: +def _py_write_bool_byte(stream: IO[bytes], bits: Tuple[Union[bool, int], ...]) -> int: """ Pack 8 booleans into a byte, and write it to the stream. @@ -170,7 +171,7 @@ def _py_write_bool_byte(stream: io.BufferedIOBase, bits: Tuple[Union[bool, int], if _USE_NUMPY: - def _np_read_bool_byte(stream: io.BufferedIOBase) -> NDArray[numpy.uint8]: + def _np_read_bool_byte(stream: IO[bytes]) -> NDArray[numpy.uint8]: """ Read a single byte from the stream, and interpret its bits as a list of 8 booleans. @@ -184,7 +185,7 @@ if _USE_NUMPY: byte_arr = _read(stream, 1) return numpy.unpackbits(numpy.frombuffer(byte_arr, dtype=numpy.uint8)) - def _np_write_bool_byte(stream: io.BufferedIOBase, bits: Tuple[Union[bool, int], ...]) -> int: + def _np_write_bool_byte(stream: IO[bytes], bits: Tuple[Union[bool, int], ...]) -> int: """ Pack 8 booleans into a byte, and write it to the stream. @@ -208,7 +209,7 @@ else: read_bool_byte = _py_read_bool_byte # type: ignore write_bool_byte = _py_write_bool_byte -def read_uint(stream: io.BufferedIOBase) -> int: +def read_uint(stream: IO[bytes]) -> int: """ Read an unsigned integer from the stream. @@ -234,7 +235,7 @@ def read_uint(stream: io.BufferedIOBase) -> int: return result -def write_uint(stream: io.BufferedIOBase, n: int) -> int: +def write_uint(stream: IO[bytes], n: int) -> int: """ Write an unsigned integer to the stream. See format details in `read_uint()`. @@ -297,7 +298,7 @@ def encode_sint(sint: int) -> int: return (abs(sint) << 1) | (sint < 0) -def read_sint(stream: io.BufferedIOBase) -> int: +def read_sint(stream: IO[bytes]) -> int: """ Read a signed integer from the stream. See `decode_sint()` for format details. @@ -311,7 +312,7 @@ def read_sint(stream: io.BufferedIOBase) -> int: return decode_sint(read_uint(stream)) -def write_sint(stream: io.BufferedIOBase, n: int) -> int: +def write_sint(stream: IO[bytes], n: int) -> int: """ Write a signed integer to the stream. See `decode_sint()` for format details. @@ -326,7 +327,7 @@ def write_sint(stream: io.BufferedIOBase, n: int) -> int: return write_uint(stream, encode_sint(n)) -def read_bstring(stream: io.BufferedIOBase) -> bytes: +def read_bstring(stream: IO[bytes]) -> bytes: """ Read a binary string from the stream. The format is: @@ -343,7 +344,7 @@ def read_bstring(stream: io.BufferedIOBase) -> bytes: return _read(stream, length) -def write_bstring(stream: io.BufferedIOBase, bstring: bytes): +def write_bstring(stream: IO[bytes], bstring: bytes): """ Write a binary string to the stream. See `read_bstring()` for format details. @@ -359,7 +360,7 @@ def write_bstring(stream: io.BufferedIOBase, bstring: bytes): return stream.write(bstring) -def read_ratio(stream: io.BufferedIOBase) -> Fraction: +def read_ratio(stream: IO[bytes]) -> Fraction: """ Read a ratio (unsigned) from the stream. The format is: @@ -377,7 +378,7 @@ def read_ratio(stream: io.BufferedIOBase) -> Fraction: return Fraction(numer, denom) -def write_ratio(stream: io.BufferedIOBase, r: Fraction) -> int: +def write_ratio(stream: IO[bytes], r: Fraction) -> int: """ Write an unsigned ratio to the stream. See `read_ratio()` for format details. @@ -399,7 +400,7 @@ def write_ratio(stream: io.BufferedIOBase, r: Fraction) -> int: return size -def read_float32(stream: io.BufferedIOBase) -> float: +def read_float32(stream: IO[bytes]) -> float: """ Read a 32-bit float from the stream. @@ -413,7 +414,7 @@ def read_float32(stream: io.BufferedIOBase) -> float: return struct.unpack(" int: +def write_float32(stream: IO[bytes], f: float) -> int: """ Write a 32-bit float to the stream. @@ -428,7 +429,7 @@ def write_float32(stream: io.BufferedIOBase, f: float) -> int: return stream.write(b) -def read_float64(stream: io.BufferedIOBase) -> float: +def read_float64(stream: IO[bytes]) -> float: """ Read a 64-bit float from the stream. @@ -442,7 +443,7 @@ def read_float64(stream: io.BufferedIOBase) -> float: return struct.unpack(" int: +def write_float64(stream: IO[bytes], f: float) -> int: """ Write a 64-bit float to the stream. @@ -457,7 +458,7 @@ def write_float64(stream: io.BufferedIOBase, f: float) -> int: return stream.write(b) -def read_real(stream: io.BufferedIOBase, real_type: Optional[int] = None) -> real_t: +def read_real(stream: IO[bytes], real_type: Optional[int] = None) -> real_t: """ Read a real number from the stream. @@ -508,7 +509,7 @@ def read_real(stream: io.BufferedIOBase, real_type: Optional[int] = None) -> rea def write_real( - stream: io.BufferedIOBase, + stream: IO[bytes], r: real_t, force_float32: bool = False ) -> int: @@ -594,7 +595,7 @@ class NString: self._string = bstring.decode('ascii') @staticmethod - def read(stream: io.BufferedIOBase) -> 'NString': + def read(stream: IO[bytes_t]) -> 'NString': """ Create an NString object by reading a bstring from the provided stream. @@ -609,7 +610,7 @@ class NString: """ return NString(read_bstring(stream)) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes_t]) -> int: """ Write this NString to a stream. @@ -631,7 +632,7 @@ class NString: return self._string -def read_nstring(stream: io.BufferedIOBase) -> str: +def read_nstring(stream: IO[bytes]) -> str: """ Read a name string from the provided stream. See `NString` for constraints on name strings. @@ -648,7 +649,7 @@ def read_nstring(stream: io.BufferedIOBase) -> str: return NString.read(stream).string -def write_nstring(stream: io.BufferedIOBase, string: str) -> int: +def write_nstring(stream: IO[bytes], string: str) -> int: """ Write a name string to a stream. See `NString` for constraints on name strings. @@ -708,7 +709,7 @@ class AString: self._string = bstring.decode('ascii') @staticmethod - def read(stream: io.BufferedIOBase) -> 'AString': + def read(stream: IO[bytes_t]) -> 'AString': """ Create an `AString` object by reading a bstring from the provided stream. @@ -723,7 +724,7 @@ class AString: """ return AString(read_bstring(stream)) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes_t]) -> int: """ Write this `AString` to a stream. @@ -745,7 +746,7 @@ class AString: return self._string -def read_astring(stream: io.BufferedIOBase) -> str: +def read_astring(stream: IO[bytes]) -> str: """ Read an ASCII string from the provided stream. See `AString` for constraints on ASCII strings. @@ -762,7 +763,7 @@ def read_astring(stream: io.BufferedIOBase) -> str: return AString.read(stream).string -def write_astring(stream: io.BufferedIOBase, string: str) -> int: +def write_astring(stream: IO[bytes], string: str) -> int: """ Write an ASCII string to a stream. See AString for constraints on ASCII strings. @@ -853,7 +854,7 @@ class ManhattanDelta: return d @staticmethod - def read(stream: io.BufferedIOBase) -> 'ManhattanDelta': + def read(stream: IO[bytes]) -> 'ManhattanDelta': """ Read a `ManhattanDelta` object from the provided stream. @@ -868,7 +869,7 @@ class ManhattanDelta: n = read_uint(stream) return ManhattanDelta.from_uint(n) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write a `ManhattanDelta` object to the provided stream. @@ -989,7 +990,7 @@ class OctangularDelta: return d @staticmethod - def read(stream: io.BufferedIOBase) -> 'OctangularDelta': + def read(stream: IO[bytes]) -> 'OctangularDelta': """ Read an `OctangularDelta` object from the provided stream. @@ -1004,7 +1005,7 @@ class OctangularDelta: n = read_uint(stream) return OctangularDelta.from_uint(n) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write an `OctangularDelta` object to the provided stream. @@ -1057,7 +1058,7 @@ class Delta: return [self.x, self.y] @staticmethod - def read(stream: io.BufferedIOBase) -> 'Delta': + def read(stream: IO[bytes]) -> 'Delta': """ Read a `Delta` object from the provided stream. @@ -1083,7 +1084,7 @@ class Delta: y = read_sint(stream) return Delta(x, y) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write a `Delta` object to the provided stream. @@ -1109,7 +1110,7 @@ class Delta: return str(self.as_list()) -def read_repetition(stream: io.BufferedIOBase) -> repetition_t: +def read_repetition(stream: IO[bytes]) -> repetition_t: """ Read a repetition entry from the given stream. @@ -1133,7 +1134,7 @@ def read_repetition(stream: io.BufferedIOBase) -> repetition_t: raise InvalidDataError(f'Unexpected repetition type: {rtype}') -def write_repetition(stream: io.BufferedIOBase, repetition: repetition_t) -> int: +def write_repetition(stream: IO[bytes], repetition: repetition_t) -> int: """ Write a repetition entry to the given stream. @@ -1153,10 +1154,10 @@ class ReuseRepetition: the most recently written repetition should be reused. """ @staticmethod - def read(_stream: io.BufferedIOBase, _repetition_type: int) -> 'ReuseRepetition': + def read(_stream: IO[bytes], _repetition_type: int) -> 'ReuseRepetition': return ReuseRepetition() - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: return write_uint(stream, 0) def __eq__(self, other: Any) -> bool: @@ -1230,7 +1231,7 @@ class GridRepetition: self.b_count = b_count @staticmethod - def read(stream: io.BufferedIOBase, repetition_type: int) -> 'GridRepetition': + def read(stream: IO[bytes], repetition_type: int) -> 'GridRepetition': """ Read a `GridRepetition` from a stream. @@ -1276,7 +1277,7 @@ class GridRepetition: raise InvalidDataError(f'Invalid type for grid repetition {repetition_type}') return GridRepetition(a_vector, na, b_vector, nb) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write the `GridRepetition` to a stream. @@ -1375,7 +1376,7 @@ class ArbitraryRepetition: self.y_displacements = list(y_displacements) @staticmethod - def read(stream: io.BufferedIOBase, repetition_type: int) -> 'ArbitraryRepetition': + def read(stream: IO[bytes], repetition_type: int) -> 'ArbitraryRepetition': """ Read an `ArbitraryRepetition` from a stream. @@ -1429,7 +1430,7 @@ class ArbitraryRepetition: raise InvalidDataError(f'Invalid ArbitraryRepetition repetition_type: {repetition_type}') return ArbitraryRepetition(x_displacements, y_displacements) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write the `ArbitraryRepetition` to a stream. @@ -1504,7 +1505,7 @@ class ArbitraryRepetition: def read_point_list( - stream: io.BufferedIOBase, + stream: IO[bytes], implicit_closed: bool, ) -> List[List[int]]: """ @@ -1537,7 +1538,7 @@ def read_point_list( for i in range(list_len): n = read_sint(stream) if n == 0: - raise Exception('Zero-sized 1-delta') + raise InvalidDataError('Zero-sized 1-delta') point = [0, 0] point[(i + 1) % 2] = n points.append(point) @@ -1593,7 +1594,7 @@ def read_point_list( def write_point_list( - stream: io.BufferedIOBase, + stream: IO[bytes], points: List[Sequence[int]], fast: bool = False, implicit_closed: bool = True @@ -1740,7 +1741,7 @@ class PropStringReference: return f'[{self.ref_type} : {self.ref}]' -def read_property_value(stream: io.BufferedIOBase) -> property_value_t: +def read_property_value(stream: IO[bytes]) -> property_value_t: """ Read a property value from a stream. @@ -1798,7 +1799,7 @@ def read_property_value(stream: io.BufferedIOBase) -> property_value_t: def write_property_value( - stream: io.BufferedIOBase, + stream: IO[bytes], value: property_value_t, force_real: bool = False, force_signed_int: bool = False, @@ -1850,11 +1851,11 @@ def write_property_value( size = write_uint(stream, 15) size += write_uint(stream, value.ref) else: - raise Exception(f'Invalid property type: {type(value)} ({value})') + raise InvalidDataError(f'Invalid property type: {type(value)} ({value})') return size -def read_interval(stream: io.BufferedIOBase) -> Tuple[Optional[int], Optional[int]]: +def read_interval(stream: IO[bytes]) -> Tuple[Optional[int], Optional[int]]: """ Read an interval from a stream. These are used for storing layer info. @@ -1895,7 +1896,7 @@ def read_interval(stream: io.BufferedIOBase) -> Tuple[Optional[int], Optional[in def write_interval( - stream: io.BufferedIOBase, + stream: IO[bytes], min_bound: Optional[int] = None, max_bound: Optional[int] = None, ) -> int: @@ -1962,7 +1963,7 @@ class OffsetEntry: self.offset = offset @staticmethod - def read(stream: io.BufferedIOBase) -> 'OffsetEntry': + def read(stream: IO[bytes]) -> 'OffsetEntry': """ Read an offset entry from a stream. @@ -1977,7 +1978,7 @@ class OffsetEntry: entry.offset = read_uint(stream) return entry - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write this offset entry to a stream. @@ -2063,7 +2064,7 @@ class OffsetTable: self.xnames = xnames @staticmethod - def read(stream: io.BufferedIOBase) -> 'OffsetTable': + def read(stream: IO[bytes]) -> 'OffsetTable': """ Read an offset table from a stream. See class docstring for format details. @@ -2083,7 +2084,7 @@ class OffsetTable: table.xnames = OffsetEntry.read(stream) return table - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write this offset table to a stream. See class docstring for format details. @@ -2107,7 +2108,7 @@ class OffsetTable: self.propstrings, self.layernames, self.xnames]) -def read_u32(stream: io.BufferedIOBase) -> int: +def read_u32(stream: IO[bytes]) -> int: """ Read a 32-bit unsigned integer (little endian) from a stream. @@ -2121,7 +2122,7 @@ def read_u32(stream: io.BufferedIOBase) -> int: return struct.unpack(' int: +def write_u32(stream: IO[bytes], n: int) -> int: """ Write a 32-bit unsigned integer (little endian) to a stream. @@ -2174,7 +2175,7 @@ class Validation: self.checksum = checksum @staticmethod - def read(stream: io.BufferedIOBase) -> 'Validation': + def read(stream: IO[bytes]) -> 'Validation': """ Read a validation entry from a stream. See class docstring for format details. @@ -2199,7 +2200,7 @@ class Validation: raise InvalidDataError('Invalid validation type!') return Validation(checksum_type, checksum) - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write this validation entry to a stream. See class docstring for format details. @@ -2228,7 +2229,7 @@ class Validation: return f'Validation(type: {self.checksum_type} sum: {self.checksum})' -def write_magic_bytes(stream: io.BufferedIOBase) -> int: +def write_magic_bytes(stream: IO[bytes]) -> int: """ Write the magic byte sequence to a stream. @@ -2241,7 +2242,7 @@ def write_magic_bytes(stream: io.BufferedIOBase) -> int: return stream.write(MAGIC_BYTES) -def read_magic_bytes(stream: io.BufferedIOBase): +def read_magic_bytes(stream: IO[bytes]): """ Read the magic byte sequence from a stream. Raise an `InvalidDataError` if it was not found. diff --git a/fatamorgana/main.py b/fatamorgana/main.py index a11af4e..8748d7f 100644 --- a/fatamorgana/main.py +++ b/fatamorgana/main.py @@ -3,7 +3,7 @@ This module contains data structures and functions for reading from and writing to whole OASIS layout files, and provides a few additional abstractions for the data contained inside them. """ -from typing import List, Dict, Union, Optional, Type +from typing import List, Dict, Union, Optional, Type, IO import io import logging @@ -116,7 +116,7 @@ class OasisLayout: self.layers = [] @staticmethod - def read(stream: io.BufferedIOBase) -> 'OasisLayout': + def read(stream: IO[bytes]) -> 'OasisLayout': """ Read an entire .oas file into an `OasisLayout` object. @@ -138,7 +138,7 @@ class OasisLayout: def read_record( self, - stream: io.BufferedIOBase, + stream: IO[bytes], modals: Modals, file_state: FileModals ) -> bool: @@ -343,7 +343,7 @@ class OasisLayout: raise InvalidRecordError(f'Unknown record id: {record_id}') return False - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write this object in OASIS fromat to a stream. @@ -430,7 +430,7 @@ class Cell: self.placements = [] if placements is None else placements self.geometry = [] if geometry is None else geometry - def dedup_write(self, stream: io.BufferedIOBase, modals: Modals) -> int: + def dedup_write(self, stream: IO[bytes], modals: Modals) -> int: """ Write this cell to a stream, using the provided modal variables to deduplicate any repeated data. diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 453ad03..20e9819 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -10,7 +10,7 @@ Higher-level code (e.g. monitoring for combinations of records with parse, or code for dealing with nested records in a CBlock) should live in main.py instead. """ -from typing import List, Dict, Tuple, Union, Optional, Sequence, Any, TypeVar +from typing import List, Dict, Tuple, Union, Optional, Sequence, Any, TypeVar, IO from abc import ABCMeta, abstractmethod import copy import math @@ -159,7 +159,7 @@ class Record(metaclass=ABCMeta): @staticmethod @abstractmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Record': + def read(stream: IO[bytes], record_id: int) -> 'Record': """ Read a record of this type from a stream. This function does not merge with modal variables. @@ -179,7 +179,7 @@ class Record(metaclass=ABCMeta): pass @abstractmethod - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: """ Write this record to a stream as-is. This function does not merge or deduplicate with modal variables. @@ -195,7 +195,7 @@ class Record(metaclass=ABCMeta): """ pass - def dedup_write(self, stream: io.BufferedIOBase, modals: Modals) -> int: + def dedup_write(self, stream: IO[bytes], modals: Modals) -> int: """ Run `.deduplicate_with_modals()` and then `.write()` to the stream. @@ -256,7 +256,7 @@ class GeometryMixin(metaclass=ABCMeta): def read_refname( - stream: io.BufferedIOBase, + stream: IO[bytes], is_present: Union[bool, int], is_reference: Union[bool, int] ) -> Union[None, int, NString]: @@ -281,7 +281,7 @@ def read_refname( def read_refstring( - stream: io.BufferedIOBase, + stream: IO[bytes], is_present: Union[bool, int], is_reference: Union[bool, int], ) -> Union[None, int, AString]: @@ -316,14 +316,14 @@ class Pad(Record): pass @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Pad': + def read(stream: IO[bytes], record_id: int) -> 'Pad': if record_id != 0: raise InvalidDataError(f'Invalid record id for Pad {record_id}') record = Pad() logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: return write_uint(stream, 0) @@ -355,14 +355,14 @@ class XYMode(Record): pass @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'XYMode': + def read(stream: IO[bytes], record_id: int) -> 'XYMode': if record_id not in (15, 16): raise InvalidDataError('Invalid record id for XYMode') record = XYMode(record_id == 16) logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: return write_uint(stream, 15 + self.relative) @@ -417,7 +417,7 @@ class Start(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Start': + def read(stream: IO[bytes], record_id: int) -> 'Start': if record_id != 1: raise InvalidDataError(f'Invalid record id for Start: {record_id}') version = AString.read(stream) @@ -432,7 +432,7 @@ class Start(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: size = write_uint(stream, 1) size += self.version.write(stream) size += write_real(stream, self.unit) @@ -478,7 +478,7 @@ class End(Record): @staticmethod def read( - stream: io.BufferedIOBase, + stream: IO[bytes], record_id: int, has_offset_table: bool ) -> 'End': @@ -494,7 +494,7 @@ class End(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: size = write_uint(stream, 2) if self.offset_table is not None: size += self.offset_table.write(stream) @@ -550,7 +550,7 @@ class CBlock(Record): pass @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'CBlock': + def read(stream: IO[bytes], record_id: int) -> 'CBlock': if record_id != 34: raise InvalidDataError(f'Invalid record id for CBlock: {record_id}') compression_type = read_uint(stream) @@ -560,7 +560,7 @@ class CBlock(Record): logger.debug(f'CBlock ending at 0x{stream.tell():x} was read successfully') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: size = write_uint(stream, 34) size += write_uint(stream, self.compression_type) size += write_uint(stream, self.decompressed_byte_count) @@ -662,7 +662,7 @@ class CellName(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'CellName': + def read(stream: IO[bytes], record_id: int) -> 'CellName': if record_id not in (3, 4): raise InvalidDataError(f'Invalid record id for CellName {record_id}') nstring = NString.read(stream) @@ -674,7 +674,7 @@ class CellName(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 3 + (self.reference_number is not None) size = write_uint(stream, record_id) size += self.nstring.write(stream) @@ -717,7 +717,7 @@ class PropName(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'PropName': + def read(stream: IO[bytes], record_id: int) -> 'PropName': if record_id not in (7, 8): raise InvalidDataError(f'Invalid record id for PropName {record_id}') nstring = NString.read(stream) @@ -729,7 +729,7 @@ class PropName(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 7 + (self.reference_number is not None) size = write_uint(stream, record_id) size += self.nstring.write(stream) @@ -773,7 +773,7 @@ class TextString(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'TextString': + def read(stream: IO[bytes], record_id: int) -> 'TextString': if record_id not in (5, 6): raise InvalidDataError(f'Invalid record id for TextString: {record_id}') astring = AString.read(stream) @@ -785,7 +785,7 @@ class TextString(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 5 + (self.reference_number is not None) size = write_uint(stream, record_id) size += self.astring.write(stream) @@ -829,7 +829,7 @@ class PropString(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'PropString': + def read(stream: IO[bytes], record_id: int) -> 'PropString': if record_id not in (9, 10): raise InvalidDataError(f'Invalid record id for PropString: {record_id}') astring = AString.read(stream) @@ -841,7 +841,7 @@ class PropString(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 9 + (self.reference_number is not None) size = write_uint(stream, record_id) size += self.astring.write(stream) @@ -896,7 +896,7 @@ class LayerName(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'LayerName': + def read(stream: IO[bytes], record_id: int) -> 'LayerName': if record_id not in (11, 12): raise InvalidDataError(f'Invalid record id for LayerName: {record_id}') is_textlayer = (record_id == 12) @@ -907,7 +907,7 @@ class LayerName(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 11 + self.is_textlayer size = write_uint(stream, record_id) size += self.nstring.write(stream) @@ -973,7 +973,7 @@ class Property(Record): dedup_field(self, 'is_standard', modals, 'property_is_standard') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Property': + def read(stream: IO[bytes], record_id: int) -> 'Property': if record_id not in (28, 29): raise InvalidDataError(f'Invalid record id for PropertyValue: {record_id}') if record_id == 29: @@ -1003,7 +1003,7 @@ class Property(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: if self.is_standard is None and self.values is None and self.name is None: return write_uint(stream, 29) else: @@ -1075,7 +1075,7 @@ class XName(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'XName': + def read(stream: IO[bytes], record_id: int) -> 'XName': if record_id not in (30, 31): raise InvalidDataError(f'Invalid record id for XName: {record_id}') attribute = read_uint(stream) @@ -1088,7 +1088,7 @@ class XName(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: record_id = 30 + (self.reference_number is not None) size = write_uint(stream, record_id) size += write_uint(stream, self.attribute) @@ -1133,7 +1133,7 @@ class XElement(Record): pass @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'XElement': + def read(stream: IO[bytes], record_id: int) -> 'XElement': if record_id != 32: raise InvalidDataError(f'Invalid record id for XElement: {record_id}') attribute = read_uint(stream) @@ -1142,7 +1142,7 @@ class XElement(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: size = write_uint(stream, 32) size += write_uint(stream, self.attribute) size += write_bstring(stream, self.bstring) @@ -1216,7 +1216,7 @@ class XGeometry(Record, GeometryMixin): dedup_field(self, 'datatype', modals, 'datatype') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'XGeometry': + def read(stream: IO[bytes], record_id: int) -> 'XGeometry': if record_id != 33: raise InvalidDataError(f'Invalid record id for XGeometry: {record_id}') @@ -1241,7 +1241,7 @@ class XGeometry(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: x = self.x is not None y = self.y is not None r = self.repetition is not None @@ -1288,7 +1288,7 @@ class Cell(Record): modals.reset() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Cell': + def read(stream: IO[bytes], record_id: int) -> 'Cell': name: Union[int, NString] if record_id == 13: name = read_uint(stream) @@ -1300,7 +1300,7 @@ class Cell(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: size = 0 if isinstance(self.name, int): size += write_uint(stream, 13) @@ -1391,7 +1391,7 @@ class Placement(Record): dedup_field(self, 'name', modals, 'placement_cell') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Placement': + def read(stream: IO[bytes], record_id: int) -> 'Placement': if record_id not in (17, 18): raise InvalidDataError(f'Invalid record id for Placement: {record_id}') @@ -1421,7 +1421,7 @@ class Placement(Record): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: c = self.name is not None n = c and isinstance(self.name, int) x = self.x is not None @@ -1534,7 +1534,7 @@ class Text(Record, GeometryMixin): dedup_field(self, 'datatype', modals, 'text_datatype') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Text': + def read(stream: IO[bytes], record_id: int) -> 'Text': if record_id != 19: raise InvalidDataError(f'Invalid record id for Text: {record_id}') @@ -1559,7 +1559,7 @@ class Text(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: c = self.string is not None n = c and isinstance(self.string, int) x = self.x is not None @@ -1609,14 +1609,14 @@ class Rectangle(Record, GeometryMixin): repetition (Optional[repetition_t]): Repetition, if any. properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] = None - datatype: Optional[int] = None - width: Optional[int] = None - height: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - is_square: bool = False + layer: Optional[int] + datatype: Optional[int] + width: Optional[int] + height: Optional[int] + x: Optional[int] + y: Optional[int] + repetition: Optional[repetition_t] + is_square: bool properties: List['Property'] def __init__( @@ -1674,7 +1674,7 @@ class Rectangle(Record, GeometryMixin): dedup_field(self, 'height', modals, 'geometry_h') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Rectangle': + def read(stream: IO[bytes], record_id: int) -> 'Rectangle': if record_id != 20: raise InvalidDataError(f'Invalid record id for Rectangle: {record_id}') @@ -1698,7 +1698,7 @@ class Rectangle(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: s = self.is_square w = self.width is not None h = self.height is not None @@ -1749,12 +1749,12 @@ class Polygon(Record, GeometryMixin): Default no repetition. properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] = None - datatype: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - point_list: Optional[point_list_t] = None + layer: Optional[int] + datatype: Optional[int] + x: Optional[int] + y: Optional[int] + repetition: Optional[repetition_t] + point_list: Optional[point_list_t] properties: List['Property'] def __init__( @@ -1797,7 +1797,7 @@ class Polygon(Record, GeometryMixin): dedup_field(self, 'point_list', modals, 'polygon_point_list') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Polygon': + def read(stream: IO[bytes], record_id: int) -> 'Polygon': if record_id != 21: raise InvalidDataError(f'Invalid record id for Polygon: {record_id}') @@ -1822,7 +1822,7 @@ class Polygon(Record, GeometryMixin): logger.debug('Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase, fast: bool = False) -> int: + def write(self, stream: IO[bytes], fast: bool = False) -> int: p = self.point_list is not None x = self.x is not None y = self.y is not None @@ -1941,7 +1941,7 @@ class Path(Record, GeometryMixin): dedup_field(self, 'extension_end', modals, 'path_extension_end') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Path': + def read(stream: IO[bytes], record_id: int) -> 'Path': if record_id != 22: raise InvalidDataError(f'Invalid record id for Path: {record_id}') @@ -1984,7 +1984,7 @@ class Path(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase, fast: bool = False) -> int: + def write(self, stream: IO[bytes], fast: bool = False) -> int: e = self.extension_start is not None or self.extension_end is not None w = self.half_width is not None p = self.point_list is not None @@ -2136,7 +2136,7 @@ class Trapezoid(Record, GeometryMixin): dedup_field(self, 'height', modals, 'geometry_h') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Trapezoid': + def read(stream: IO[bytes], record_id: int) -> 'Trapezoid': if record_id not in (23, 24, 25): raise InvalidDataError(f'Invalid record id for Trapezoid: {record_id}') @@ -2164,7 +2164,7 @@ class Trapezoid(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: v = self.is_vertical w = self.width is not None h = self.height is not None @@ -2358,7 +2358,7 @@ class CTrapezoid(Record, GeometryMixin): self.check_valid() @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'CTrapezoid': + def read(stream: IO[bytes], record_id: int) -> 'CTrapezoid': if record_id != 26: raise InvalidDataError(f'Invalid record id for CTrapezoid: {record_id}') @@ -2384,7 +2384,7 @@ class CTrapezoid(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: t = self.ctrapezoid_type is not None w = self.width is not None h = self.height is not None @@ -2508,7 +2508,7 @@ class Circle(Record, GeometryMixin): dedup_field(self, 'radius', modals, 'circle_radius') @staticmethod - def read(stream: io.BufferedIOBase, record_id: int) -> 'Circle': + def read(stream: IO[bytes], record_id: int) -> 'Circle': if record_id != 27: raise InvalidDataError(f'Invalid record id for Circle: {record_id}') @@ -2533,7 +2533,7 @@ class Circle(Record, GeometryMixin): logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record - def write(self, stream: io.BufferedIOBase) -> int: + def write(self, stream: IO[bytes]) -> int: s = self.radius is not None x = self.x is not None y = self.y is not None From 01b3f9ca3a29849eca36cfc84a309f55d51654dd Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Thu, 26 Jan 2023 13:36:22 -0800 Subject: [PATCH 08/40] cleanup based on flake8 output --- .flake8 | 1 + fatamorgana/basic.py | 5 +- fatamorgana/records.py | 2 +- fatamorgana/test/test_files_cblocks.py | 179 +++--- fatamorgana/test/test_files_cells.py | 7 +- fatamorgana/test/test_files_circles.py | 86 ++- fatamorgana/test/test_files_ctrapezoids.py | 143 ++--- fatamorgana/test/test_files_empty.py | 7 +- fatamorgana/test/test_files_layernames.py | 118 ++-- fatamorgana/test/test_files_modals.py | 208 +++--- fatamorgana/test/test_files_paths.py | 176 +++--- fatamorgana/test/test_files_placements.py | 564 ++++++++--------- fatamorgana/test/test_files_polygons.py | 305 ++++----- fatamorgana/test/test_files_properties.py | 698 ++++++++++----------- fatamorgana/test/test_files_rectangles.py | 160 +++-- fatamorgana/test/test_files_texts.py | 21 +- fatamorgana/test/test_files_trapezoids.py | 230 ++++--- fatamorgana/test/test_int.py | 3 - fatamorgana/test/utils.py | 10 +- 19 files changed, 1429 insertions(+), 1494 deletions(-) diff --git a/.flake8 b/.flake8 index 0042015..fb07707 100644 --- a/.flake8 +++ b/.flake8 @@ -27,3 +27,4 @@ ignore = per-file-ignores = # F401 import without use */__init__.py: F401, + __init__.py: F401, diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 2e41b6c..476e5f6 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -7,7 +7,6 @@ from fractions import Fraction from enum import Enum import math import struct -import io import warnings try: @@ -1663,13 +1662,13 @@ def write_point_list( if implicit_closed: ManhattanDelta(points[-1][0] - points[0][0], points[-1][1] - points[0][1]) list_type = 2 - except: + except InvalidDataError: try: deltas = [OctangularDelta(x, y) for x, y in points] if implicit_closed: OctangularDelta(points[-1][0] - points[0][0], points[-1][1] - points[0][1]) list_type = 3 - except: + except InvalidDataError: pass if list_type is not None: size = write_uint(stream, list_type) diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 20e9819..46beb48 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -383,7 +383,7 @@ class Start(Record): def __init__( self, unit: real_t, - version: Union[AString, str] = "1.0", + version: Union[AString, str] = "1.0", offset_table: Optional[OffsetTable] = None, ) -> None: """ diff --git a/fatamorgana/test/test_files_cblocks.py b/fatamorgana/test/test_files_cblocks.py index 93ff0ac..cf3f2ec 100644 --- a/fatamorgana/test/test_files_cblocks.py +++ b/fatamorgana/test/test_files_cblocks.py @@ -1,17 +1,11 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore -import numpy from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_bstring, write_byte from ..main import OasisLayout @@ -98,86 +92,105 @@ def test_file_1() -> None: assert geometry[1].height == 610 assert geometry[1].width == 680 - assert_equal(geometry[2].point_list, - [[-30, -360], [480, -50], [180, 430], [-630, -20]]) + assert_equal(geometry[2].point_list, [ + [-30, -360], + [480, -50], + [180, 430], + [-630, -20], + ]) - assert_equal(geometry[3].point_list, - [[-30, -400], - [450, 40], - [70, -220], - [10, 210], - [740, -20], - [0, 660], - [570, 10], - [50, 500], - [630, 20], - [10, 100], - [-810, 10], - [20, -470], - [-660, 0], - [20, -470], - [-620, 10], - [0, 610], - [610, -10], - [0, -100], - [210, 10], - [40, 820], - [-1340, 60], - [30, -1370]]) + assert_equal(geometry[3].point_list, [ + [-30, -400], + [450, 40], + [70, -220], + [10, 210], + [740, -20], + [0, 660], + [570, 10], + [50, 500], + [630, 20], + [10, 100], + [-810, 10], + [20, -470], + [-660, 0], + [20, -470], + [-620, 10], + [0, 610], + [610, -10], + [0, -100], + [210, 10], + [40, 820], + [-1340, 60], + [30, -1370], + ]) - assert_equal(geometry[4].point_list, - [[40, -760], [490, -50], [110, 800], [-640, 10]]) + assert_equal(geometry[4].point_list, [ + [40, -760], + [490, -50], + [110, 800], + [-640, 10], + ]) - assert_equal(geometry[5].point_list, - [[140, -380], - [340, -10], - [30, -100], - [-320, 20], - [130, -460], - [-480, -20], - [-210, 910], - [370, 40]]) + assert_equal(geometry[5].point_list, [ + [140, -380], + [340, -10], + [30, -100], + [-320, 20], + [130, -460], + [-480, -20], + [-210, 910], + [370, 40], + ]) - assert_equal(geometry[6].point_list, - [[720, -20], - [20, 20], - [690, 0], - [-10, 650], - [-20, 30], - [-90, -10], - [10, 70], - [470, -30], - [20, -120], - [-320, 0], - [40, -790], - [-90, -20], - [-60, 140], - [-1390, 50], - [10, 30]]) + assert_equal(geometry[6].point_list, [ + [720, -20], + [20, 20], + [690, 0], + [-10, 650], + [-20, 30], + [-90, -10], + [10, 70], + [470, -30], + [20, -120], + [-320, 0], + [40, -790], + [-90, -20], + [-60, 140], + [-1390, 50], + [10, 30], + ]) - assert_equal(geometry[7].point_list, - [[150, -830], - [-1320, 40], - [-70, 370], - [310, -30], - [10, 220], - [250, -40], - [40, -220], - [340, 10], - [-20, 290], - [-1070, 20], - [0, 230], - [1380, -60]]) + assert_equal(geometry[7].point_list, [ + [150, -830], + [-1320, 40], + [-70, 370], + [310, -30], + [10, 220], + [250, -40], + [40, -220], + [340, 10], + [-20, 290], + [-1070, 20], + [0, 230], + [1380, -60], + ]) - assert_equal(geometry[8].point_list, - [[330, 0], [-10, 480], [620, -20], [-10, 330], [-930, 60], [0, -850]]) + assert_equal(geometry[8].point_list, [ + [330, 0], + [-10, 480], + [620, -20], + [-10, 330], + [-930, 60], + [0, -850], + ]) - assert_equal(geometry[9].point_list, - [[-140, -410], - [10, -140], - [270, 0], - [130, 1030], - [-500, 50], - [10, -330], - [210, -10], - [10, -190]]) + assert_equal(geometry[9].point_list, [ + [-140, -410], + [10, -140], + [270, 0], + [130, 1030], + [-500, 50], + [10, -330], + [210, -10], + [10, -190], + ]) diff --git a/fatamorgana/test/test_files_cells.py b/fatamorgana/test/test_files_cells.py index 9239994..9fae7b8 100644 --- a/fatamorgana/test/test_files_cells.py +++ b/fatamorgana/test/test_files_cells.py @@ -1,14 +1,11 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore +import pytest from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring +from ..basic import write_uint, write_bstring from ..basic import InvalidRecordError, InvalidDataError from ..main import OasisLayout diff --git a/fatamorgana/test/test_files_circles.py b/fatamorgana/test/test_files_circles.py index 35c7a14..794c18f 100644 --- a/fatamorgana/test/test_files_circles.py +++ b/fatamorgana/test/test_files_circles.py @@ -1,17 +1,9 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct - -import pytest # type: ignore -import numpy -from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -37,52 +29,52 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0011_1011) # 00rX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 150) # radius - write_sint(buf, -100) # geometry-x (absolute) - write_sint(buf, 200) # geometry-y (absolute) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0011_1011) # 00rX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 150) # radius + write_sint(buf, -100) # geometry-x (absolute) + write_sint(buf, 200) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0000_1000) # 00rX_YRDL - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0000_1000) # 00rX_YRDL + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0010_1000) # 00rX_YRDL - write_uint(buf, 0) # radius - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0010_1000) # 00rX_YRDL + write_uint(buf, 0) # radius + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0010_1000) # 00rX_YRDL - write_uint(buf, 1) # radius - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0010_1000) # 00rX_YRDL + write_uint(buf, 1) # radius + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0010_1000) # 00rX_YRDL - write_uint(buf, 6) # radius - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0010_1000) # 00rX_YRDL + write_uint(buf, 6) # radius + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0010_1000) # 00rX_YRDL - write_uint(buf, 20) # radius - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0010_1000) # 00rX_YRDL + write_uint(buf, 20) # radius + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 27) # CIRCLE record - write_byte(buf, 0b0010_1100) # 00rX_YRDL - write_uint(buf, 100) # radius - write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 400) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 27) # CIRCLE record + write_byte(buf, 0b0010_1100) # 00rX_YRDL + write_uint(buf, 100) # radius + write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 400) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing buf.write(FOOTER) return buf diff --git a/fatamorgana/test/test_files_ctrapezoids.py b/fatamorgana/test/test_files_ctrapezoids.py index b98794a..fdcc6cf 100644 --- a/fatamorgana/test/test_files_ctrapezoids.py +++ b/fatamorgana/test/test_files_ctrapezoids.py @@ -1,17 +1,9 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct - -import pytest # type: ignore -import numpy -from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -33,29 +25,29 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b1111_1011) # TWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 24) # ctrapezoid type - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, -100) # geometry-x (absolute) - write_sint(buf, 200) # geometry-y (absolute) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b1111_1011) # TWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 24) # ctrapezoid type + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, -100) # geometry-x (absolute) + write_sint(buf, 200) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b0000_1000) # TWHX_YRDL - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b0000_1000) # TWHX_YRDL + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_0011) # SWHX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_0011) # SWHX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype h = [250, 100] v = [100, 250] @@ -66,33 +58,34 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: + [0b10] * 4 + [0b01] * 2 + [0b10] * 2 - + [0b11, 0b10]) + + [0b11, 0b10] + ) for t, (x, x_en) in enumerate(zip(wh, wh_en)): - write_uint(buf, 26) # CTRAPEZOID record + write_uint(buf, 26) # CTRAPEZOID record write_byte(buf, 0b1000_1011 | (x_en << 5)) # TWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, t) # ctrapezoid type + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, t) # ctrapezoid type if x_en & 0b10: - write_uint(buf, x[0]) # width + write_uint(buf, x[0]) # width if x_en & 0b01: - write_uint(buf, x[1]) # height - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, x[1]) # height + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_0011) # SWHX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_0011) # SWHX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b0000_1100) # TWHX_YRDL - write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 400) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b0000_1100) # TWHX_YRDL + write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 400) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing buf.write(FOOTER) return buf @@ -143,7 +136,7 @@ def test_file_1() -> None: elif ct_type in range(22, 24) or ct_type == 25: assert gg.height == [100, None][is_ctrapz], msg else: - if ct_type < 8 or 16 <= ct_type < 25 or 26 <= ct_type : + if ct_type < 8 or 16 <= ct_type < 25 or 26 <= ct_type: assert gg.width == 250, msg assert gg.height == 100, msg else: @@ -169,39 +162,39 @@ def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: write_bstring(buf, b'A') # Cell name # Shouldn't access (undefined) height modal, despite not having a height. - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b1101_1011) # TWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 16) # ctrapezoid type - write_uint(buf, 200) # width - write_sint(buf, -100) # geometry-x (absolute) - write_sint(buf, 200) # geometry-y (absolute) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b1101_1011) # TWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 16) # ctrapezoid type + write_uint(buf, 200) # width + write_sint(buf, -100) # geometry-x (absolute) + write_sint(buf, 200) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b0000_1000) # TWHX_YRDL - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b0000_1000) # TWHX_YRDL + write_sint(buf, 400) # geometry-y (relative) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'B') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'B') # Cell name # Shouldn't access (undefined) width modal, despite not having a width. - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b1011_1011) # TWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 20) # ctrapezoid type - write_uint(buf, 200) # height - write_sint(buf, -100) # geometry-x (absolute) - write_sint(buf, 200) # geometry-y (absolute) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b1011_1011) # TWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 20) # ctrapezoid type + write_uint(buf, 200) # height + write_sint(buf, -100) # geometry-x (absolute) + write_sint(buf, 200) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record - write_uint(buf, 26) # CTRAPEZOID record - write_byte(buf, 0b0000_1000) # TWHX_YRDL - write_sint(buf, 400) # geometry-y (relative) + write_uint(buf, 26) # CTRAPEZOID record + write_byte(buf, 0b0000_1000) # TWHX_YRDL + write_sint(buf, 400) # geometry-y (relative) buf.write(FOOTER) return buf diff --git a/fatamorgana/test/test_files_empty.py b/fatamorgana/test/test_files_empty.py index 1fbb63c..acf651d 100644 --- a/fatamorgana/test/test_files_empty.py +++ b/fatamorgana/test/test_files_empty.py @@ -1,14 +1,10 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase import struct -import pytest # type: ignore - from .utils import MAGIC_BYTES, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring +from ..basic import write_uint, write_bstring from ..main import OasisLayout @@ -59,7 +55,6 @@ def test_file_1() -> None: assert layout.unit == 1000 - def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: ''' File contains no records. diff --git a/fatamorgana/test/test_files_layernames.py b/fatamorgana/test/test_files_layernames.py index 56ddc23..94a2cc8 100644 --- a/fatamorgana/test/test_files_layernames.py +++ b/fatamorgana/test/test_files_layernames.py @@ -1,16 +1,10 @@ # type: ignore +from typing import Sequence -from typing import List, Tuple, Iterable, Sequence -from itertools import chain from io import BytesIO, BufferedIOBase -import pytest # type: ignore -import numpy -from numpy.testing import assert_equal - from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -37,67 +31,67 @@ def base_tests(layout: OasisLayout) -> None: def write_names_geom(buf: BufferedIOBase, short: bool = False) -> BufferedIOBase: - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'AA') # name - write_uint(buf, 0) # all layers - write_uint(buf, 0) # all datatypes + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'AA') # name + write_uint(buf, 0) # all layers + write_uint(buf, 0) # all datatypes - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'L5A') # name - write_uint(buf, 1) # layer <=5 - write_uint(buf, 5) # (...) - write_uint(buf, 0) # all datatypes + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'L5A') # name + write_uint(buf, 1) # layer <=5 + write_uint(buf, 5) # (...) + write_uint(buf, 0) # all datatypes - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'H5A') # name - write_uint(buf, 2) # layer >=5 - write_uint(buf, 5) # (...) - write_uint(buf, 0) # all datatypes + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'H5A') # name + write_uint(buf, 2) # layer >=5 + write_uint(buf, 5) # (...) + write_uint(buf, 0) # all datatypes - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'E5A') # name - write_uint(buf, 3) # layer ==5 - write_uint(buf, 5) # (...) - write_uint(buf, 0) # all datatypes + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'E5A') # name + write_uint(buf, 3) # layer ==5 + write_uint(buf, 5) # (...) + write_uint(buf, 0) # all datatypes - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'I56A') # name - write_uint(buf, 4) # layer 5 to 6 - write_uint(buf, 5) # (...) - write_uint(buf, 6) # (...) - write_uint(buf, 0) # all datatypes + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'I56A') # name + write_uint(buf, 4) # layer 5 to 6 + write_uint(buf, 5) # (...) + write_uint(buf, 6) # (...) + write_uint(buf, 0) # all datatypes if short: return buf - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'E5L4') # name - write_uint(buf, 3) # layer ==5 - write_uint(buf, 5) # (...) - write_uint(buf, 1) # datatype <=4 - write_uint(buf, 4) # (...) + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'E5L4') # name + write_uint(buf, 3) # layer ==5 + write_uint(buf, 5) # (...) + write_uint(buf, 1) # datatype <=4 + write_uint(buf, 4) # (...) - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'E5H4') # name - write_uint(buf, 3) # layer ==5 - write_uint(buf, 5) # (...) - write_uint(buf, 2) # datatype >=4 - write_uint(buf, 4) # (...) + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'E5H4') # name + write_uint(buf, 3) # layer ==5 + write_uint(buf, 5) # (...) + write_uint(buf, 2) # datatype >=4 + write_uint(buf, 4) # (...) - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'E5E4') # name - write_uint(buf, 3) # layer ==5 - write_uint(buf, 5) # (...) - write_uint(buf, 3) # datatype ==4 - write_uint(buf, 4) # (...) + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'E5E4') # name + write_uint(buf, 3) # layer ==5 + write_uint(buf, 5) # (...) + write_uint(buf, 3) # datatype ==4 + write_uint(buf, 4) # (...) - write_uint(buf, 11) # LAYERNAME record (geometry) - write_bstring(buf, b'E5I47') # name - write_uint(buf, 3) # layer ==5 - write_uint(buf, 5) # (...) - write_uint(buf, 4) # datatype 4 to 7 - write_uint(buf, 4) # (...) - write_uint(buf, 7) # (...) + write_uint(buf, 11) # LAYERNAME record (geometry) + write_bstring(buf, b'E5I47') # name + write_uint(buf, 3) # layer ==5 + write_uint(buf, 5) # (...) + write_uint(buf, 4) # datatype 4 to 7 + write_uint(buf, 4) # (...) + write_uint(buf, 7) # (...) return buf @@ -127,7 +121,7 @@ def write_names_text(buf: BufferedIOBase, prefix: bytes = b'') -> BufferedIOBase write_uint(buf, 0) # all datatypes write_uint(buf, 12) # LAYERNAME record (geometry) - write_bstring(buf, prefix + b'I56A') # name + write_bstring(buf, prefix + b'I56A') # name write_uint(buf, 4) # layer 5 to 6 write_uint(buf, 5) # (...) write_uint(buf, 6) # (...) @@ -160,7 +154,8 @@ def write_text(buf: BufferedIOBase) -> BufferedIOBase: def name_test(layers: Sequence, is_textlayer: bool) -> None: for ii, nn in enumerate(layers): - assert is_textlayer == nn.is_textlayer, f'Fail on layername {ii}' + msg = f'Fail on layername {ii}' + assert is_textlayer == nn.is_textlayer, msg assert nn.nstring.string == ['AA', 'L5A', 'H5A', 'E5A', 'I56A', 'E5L4', 'E5H4', 'E5E4', 'E5I47'][ii], msg @@ -172,7 +167,8 @@ def name_test(layers: Sequence, is_textlayer: bool) -> None: def name_test_text(layers: Sequence) -> None: for ii, nn in enumerate(layers): - assert nn.is_textlayer, f'Fail on layername {ii}' + msg = f'Fail on layername {ii}' + assert nn.is_textlayer, msg assert nn.nstring.string == ['TAA', 'TL5A', 'TH5A', 'TE5A', 'TI56A'][ii], msg assert nn.layer_interval[0] == [None, None, 5, 5, 5][ii], msg diff --git a/fatamorgana/test/test_files_modals.py b/fatamorgana/test/test_files_modals.py index 0021bf1..d2417f2 100644 --- a/fatamorgana/test/test_files_modals.py +++ b/fatamorgana/test/test_files_modals.py @@ -1,17 +1,9 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct - -import pytest # type: ignore -import numpy -from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -33,151 +25,151 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0110_0011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 10) # width - write_uint(buf, 20) # height + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0110_0011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 10) # width + write_uint(buf, 20) # height # TEXT 1 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0100_0011) # 0CNX_YRTL - write_bstring(buf, b'A') # text string - write_uint(buf, 2) # layer - write_uint(buf, 1) # datatype + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0100_0011) # 0CNX_YRTL + write_bstring(buf, b'A') # text string + write_uint(buf, 2) # layer + write_uint(buf, 1) # datatype # RECTANGLE 2 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 100) # geometry-x (absolute) - write_sint(buf, -100) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 100) # geometry-x (absolute) + write_sint(buf, -100) # geometry-y (absolute) # TEXT 3 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 100) # text-x (absolute) - write_sint(buf, -100) # text-y (absolute) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 100) # text-x (absolute) + write_sint(buf, -100) # text-y (absolute) # RECTANGLE 4 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 200) # geometry-x (absolute) - write_sint(buf, -200) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 200) # geometry-x (absolute) + write_sint(buf, -200) # geometry-y (absolute) # TEXT 5 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 200) # text-x (absolute) - write_sint(buf, -200) # text-y (absolute) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 200) # text-x (absolute) + write_sint(buf, -200) # text-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # RECTANGLE 6 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 100) # geometry-x (relative) - write_sint(buf, -100) # geometry-y (relative) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 100) # geometry-x (relative) + write_sint(buf, -100) # geometry-y (relative) # TEXT 7 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 100) # text-x (relative) - write_sint(buf, -100) # text-y (relative) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 100) # text-x (relative) + write_sint(buf, -100) # text-y (relative) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'B') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'B') # Cell name # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0110_0011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 20) # width - write_uint(buf, 10) # height + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0110_0011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 20) # width + write_uint(buf, 10) # height # TEXT 1 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0100_0011) # 0CNX_YRTL - write_bstring(buf, b'B') # text string - write_uint(buf, 2) # layer - write_uint(buf, 1) # datatype + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0100_0011) # 0CNX_YRTL + write_bstring(buf, b'B') # text string + write_uint(buf, 2) # layer + write_uint(buf, 1) # datatype # RECTANGLE 2 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 100) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 100) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) # TEXT 3 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 100) # text-x (absolute) - write_sint(buf, 100) # text-y (absolute) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 100) # text-x (absolute) + write_sint(buf, 100) # text-y (absolute) # RECTANGLE 4 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 200) # geometry-x (absolute) - write_sint(buf, 200) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 200) # geometry-x (absolute) + write_sint(buf, 200) # geometry-y (absolute) # TEXT 5 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 200) # text-x (absolute) - write_sint(buf, 200) # text-y (absolute) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 200) # text-x (absolute) + write_sint(buf, 200) # text-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # RECTANGLE 6 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0001_1000) # SWHX_YRDL - write_sint(buf, 100) # geometry-x (relative) - write_sint(buf, 100) # geometry-y (relative) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0001_1000) # SWHX_YRDL + write_sint(buf, 100) # geometry-x (relative) + write_sint(buf, 100) # geometry-y (relative) # TEXT 7 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0001_1000) # 0CNX_YRTL - write_sint(buf, 100) # text-x (relative) - write_sint(buf, 100) # text-y (relative) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0001_1000) # 0CNX_YRTL + write_sint(buf, 100) # text-x (relative) + write_sint(buf, 100) # text-y (relative) # PLACEMENT 0 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b1000_0000) # CNXY_RAAF - write_bstring(buf, b'A') # Cell reference + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b1000_0000) # CNXY_RAAF + write_bstring(buf, b'A') # Cell reference # PLACEMENT 1 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_0000) # CNXY_RAAF - write_sint(buf, 50) # placement-x (relative) - write_sint(buf, 50) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_0000) # CNXY_RAAF + write_sint(buf, 50) # placement-x (relative) + write_sint(buf, 50) # placement-y (relative) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'TOP') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'TOP') # Cell name # PLACEMENT 0 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b1000_0000) # CNXY_RAAF - write_bstring(buf, b'B') # Cell reference + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b1000_0000) # CNXY_RAAF + write_bstring(buf, b'B') # Cell reference # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0110_0011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 50) # width - write_uint(buf, 5) # height + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0110_0011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 50) # width + write_uint(buf, 5) # height # TEXT 1 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0100_0011) # 0CNX_YRTL - write_bstring(buf, b'TOP') # text string - write_uint(buf, 2) # layer - write_uint(buf, 1) # datatype + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0100_0011) # 0CNX_YRTL + write_bstring(buf, b'TOP') # text string + write_uint(buf, 2) # layer + write_uint(buf, 1) # datatype buf.write(FOOTER) return buf diff --git a/fatamorgana/test/test_files_paths.py b/fatamorgana/test/test_files_paths.py index a359817..8fb2cc0 100644 --- a/fatamorgana/test/test_files_paths.py +++ b/fatamorgana/test/test_files_paths.py @@ -1,17 +1,11 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore -import numpy from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte, PathExtensionScheme from ..main import OasisLayout @@ -37,108 +31,108 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'ABC') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'ABC') # Cell name # PATH 0 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b1111_1011) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 10) # half-width - write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE - write_sint(buf, 5) # (extension-scheme) start - write_sint(buf, -5) # (extension-scheme) end - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 0) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b1111_1011) # EWPX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 10) # half-width + write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE + write_sint(buf, 5) # (extension-scheme) start + write_sint(buf, -5) # (extension-scheme) end + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 0) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PATH 1 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b1110_1011) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 10) # half-width - write_byte(buf, 0b0000_0000) # extension-scheme 0000_SSEE - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b1110_1011) # EWPX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 10) # half-width + write_byte(buf, 0b0000_0000) # extension-scheme 0000_SSEE + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 200) # geometry-y (relative) # PATH 2 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b1110_1001) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 10) # half-width - write_byte(buf, 0b0000_0100) # extension-scheme 0000_SSEE - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b1110_1001) # EWPX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 10) # half-width + write_byte(buf, 0b0000_0100) # extension-scheme 0000_SSEE + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 200) # geometry-y (relative) # PATH 3 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b1110_1010) # EWPX_YRDL - write_uint(buf, 2) # datatype - write_uint(buf, 12) # half-width - write_byte(buf, 0b0000_0101) # extension-scheme 0000_SSEE - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b1110_1010) # EWPX_YRDL + write_uint(buf, 2) # datatype + write_uint(buf, 12) # half-width + write_byte(buf, 0b0000_0101) # extension-scheme 0000_SSEE + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 200) # geometry-y (relative) # PATH 4 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b1010_1011) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_byte(buf, 0b0000_1010) # extension-scheme 0000_SSEE - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b1010_1011) # EWPX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_byte(buf, 0b0000_1010) # extension-scheme 0000_SSEE + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 200) # geometry-y (relative) # PATH 5 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b0000_1011) # EWPX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b0000_1011) # EWPX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_sint(buf, 200) # geometry-y (relative) # PATH 6 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b0000_1111) # EWPX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_sint(buf, 200) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 22) # PATH record + write_byte(buf, 0b0000_1111) # EWPX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_sint(buf, 200) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PATH 7 - write_uint(buf, 22) # PATH record - write_byte(buf, 0b0001_0101) # EWPX_YRDL - write_uint(buf, 1) # layer - write_sint(buf, 1000) # geometry-x (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 22) # PATH record + write_byte(buf, 0b0001_0101) # EWPX_YRDL + write_uint(buf, 1) # layer + write_sint(buf, 1000) # geometry-x (relative) + write_uint(buf, 0) # repetition (reuse) buf.write(FOOTER) return buf diff --git a/fatamorgana/test/test_files_placements.py b/fatamorgana/test/test_files_placements.py index 5059be9..390876e 100644 --- a/fatamorgana/test/test_files_placements.py +++ b/fatamorgana/test/test_files_placements.py @@ -1,17 +1,11 @@ # type: ignore - -from typing import List, Tuple, Iterable -from itertools import chain +from typing import Tuple from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore -import numpy from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError, write_float32, write_float64 +from ..basic import write_uint, write_sint, write_bstring, write_byte, write_float32, write_float64 from ..main import OasisLayout @@ -28,14 +22,14 @@ def base_tests(layout: OasisLayout) -> None: def write_rectangle(buf: BufferedIOBase, pos: Tuple[int, int] = (300, -400)) -> None: - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, pos[0]) # geometry-x (absolute) - write_sint(buf, pos[1]) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, pos[0]) # geometry-x (absolute) + write_sint(buf, pos[1]) # geometry-y (absolute) def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: @@ -43,120 +37,120 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name write_rectangle(buf) - write_uint(buf, 14) # CELL record (explicit) + write_uint(buf, 14) # CELL record (explicit) write_bstring(buf, b'TOP') # Cell name - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 0 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b1011_0000) # CNXY_RAAF - write_bstring(buf, b'A') # cell reference - write_sint(buf, -300) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b1011_0000) # CNXY_RAAF + write_bstring(buf, b'A') # cell reference + write_sint(buf, -300) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 1 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_0000) # CNXY_RAAF - write_sint(buf, 0) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_0000) # CNXY_RAAF + write_sint(buf, 0) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 2 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0000) # CNXY_RAAF - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0000) # CNXY_RAAF + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 3 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0010_0000) # CNXY_RAAF - write_sint(buf, 300) # placement-x (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0010_0000) # CNXY_RAAF + write_sint(buf, 300) # placement-x (relative) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 4 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_0001) # CNXY_RAAF - write_sint(buf, 700) # placement-x (absolute) - write_sint(buf, 400) # placement-y (absolute) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_0001) # CNXY_RAAF + write_sint(buf, 700) # placement-x (absolute) + write_sint(buf, 400) # placement-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 5 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0010) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0010) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) # PLACEMENT 6 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0011) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0011) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 7 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (absolute) - write_sint(buf, 0) # placement-y (absolute) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 300) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (absolute) + write_sint(buf, 0) # placement-y (absolute) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 300) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 8 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 0) # repetition (reuse) # PLACEMENT 9 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 2) # repetition (3 cols.) - write_uint(buf, 1) # (repetition) count - write_uint(buf, 320) # (repetition) spacing + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 2) # repetition (3 cols.) + write_uint(buf, 1) # (repetition) count + write_uint(buf, 320) # (repetition) spacing # PLACEMENT 10 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 3) # repetition (4 rows) - write_uint(buf, 2) # (repetition) count - write_uint(buf, 310) # (repetition) spacing + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 3) # repetition (4 rows) + write_uint(buf, 2) # (repetition) count + write_uint(buf, 310) # (repetition) spacing # PLACEMENT 11 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 4) # repetition (4 arbitrary cols.) - write_uint(buf, 2) # (repetition) dimension - write_uint(buf, 320) # (repetition) spacing - write_uint(buf, 330) # (repetition) spacing - write_uint(buf, 340) # (repetition) spacing + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 4) # repetition (4 arbitrary cols.) + write_uint(buf, 2) # (repetition) dimension + write_uint(buf, 320) # (repetition) spacing + write_uint(buf, 330) # (repetition) spacing + write_uint(buf, 340) # (repetition) spacing # PLACEMENT 12 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 8) # repetition (3x4 matrix, arbitrary vectors) - write_uint(buf, 1) # (repetition) n-dimension - write_uint(buf, 2) # (repetition) m-dimension - write_uint(buf, 310 << 2 | 0b01) # (repetition) n-displacement g-delta: (310, 320) - write_sint(buf, 320) # (repetition g-delta) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 8) # repetition (3x4 matrix, arbitrary vectors) + write_uint(buf, 1) # (repetition) n-dimension + write_uint(buf, 2) # (repetition) m-dimension + write_uint(buf, 310 << 2 | 0b01) # (repetition) n-displacement g-delta: (310, 320) + write_sint(buf, 320) # (repetition g-delta) write_uint(buf, 330 << 4 | 0b1010) # (repetition) m-displacement g-delta: 330-northwest (-330, 330) buf.write(FOOTER) @@ -211,9 +205,9 @@ def test_file_1() -> None: assert pp.y == 0, msg if ii < 4 or ii == 5: - assert pp.flip == False, msg + assert not bool(pp.flip), msg else: - assert pp.flip == True, msg + assert bool(pp.flip), msg if ii < 5: assert pp.angle == 0, msg @@ -286,49 +280,49 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: # PLACEMENT 0 write_uint(buf, 17) # PLACEMENT (simple) if variant == 2: - write_byte(buf, 0b1011_0000) # CNXY_RAAF - write_bstring(buf, b'A') # cell reference + write_byte(buf, 0b1011_0000) # CNXY_RAAF + write_bstring(buf, b'A') # cell reference else: - write_byte(buf, 0b1111_0000) # CNXY_RAAF - write_uint(buf, 0) # cell reference - write_sint(buf, -300) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) + write_byte(buf, 0b1111_0000) # CNXY_RAAF + write_uint(buf, 0) # cell reference + write_sint(buf, -300) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 1 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_0000) # CNXY_RAAF - write_sint(buf, 0) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_0000) # CNXY_RAAF + write_sint(buf, 0) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 2 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0000) # CNXY_RAAF - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0000) # CNXY_RAAF + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 3 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0010_0000) # CNXY_RAAF - write_sint(buf, 300) # placement-x (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0010_0000) # CNXY_RAAF + write_sint(buf, 300) # placement-x (relative) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 4 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_0001) # CNXY_RAAF - write_sint(buf, 700) # placement-x (absolute) - write_sint(buf, 400) # placement-y (absolute) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_0001) # CNXY_RAAF + write_sint(buf, 700) # placement-x (absolute) + write_sint(buf, 400) # placement-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 5 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0010) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0010) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) # PLACEMENT 6 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_0011) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_0011) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) if variant == 2: write_uint(buf, 14) # CELL record (explicit) @@ -502,9 +496,9 @@ def common_tests(layout: OasisLayout, variant: int) -> None: assert pp.y == 400 * (ii + 1), msg if ii in (4, 6): - assert pp.flip == True, msg + assert bool(pp.flip), msg else: - assert pp.flip == False, msg + assert not bool(pp.flip), msg if ii in (5, 6): assert pp.angle == 90, msg @@ -525,73 +519,73 @@ def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 3) # CELLNAME record (implicit id 0) + write_uint(buf, 3) # CELLNAME record (implicit id 0) write_bstring(buf, b'A') - write_uint(buf, 3) # CELLNAME record (implicit id 1) + write_uint(buf, 3) # CELLNAME record (implicit id 1) write_bstring(buf, b'TOP') - write_uint(buf, 13) # CELL record (name ref.) - write_uint(buf, 1) # Cell name 1 (TOP) + write_uint(buf, 13) # CELL record (name ref.) + write_uint(buf, 1) # Cell name 1 (TOP) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 0 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b1111_1000) # CNXY_RAAF - write_uint(buf, 0) # cell reference - write_sint(buf, -300) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 20) # (repetition) x-spacing - write_uint(buf, 30) # (repetition) y-spacing + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b1111_1000) # CNXY_RAAF + write_uint(buf, 0) # cell reference + write_sint(buf, -300) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 20) # (repetition) x-spacing + write_uint(buf, 30) # (repetition) y-spacing # PLACEMENT 1 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1000) # CNXY_RAAF - write_sint(buf, 0) # placement-x (relative) - write_sint(buf, 400) # placement-y (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1000) # CNXY_RAAF + write_sint(buf, 0) # placement-x (relative) + write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 0) # repetition (reuse) # PLACEMENT 2 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_1000) # CNXY_RAAF - write_sint(buf, 400) # placement-y (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_1000) # CNXY_RAAF + write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 0) # repetition (reuse) # PLACEMENT 3 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0010_1000) # CNXY_RAAF - write_sint(buf, 300) # placement-x (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0010_1000) # CNXY_RAAF + write_sint(buf, 300) # placement-x (relative) + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 4 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0011_1001) # CNXY_RAAF - write_sint(buf, 700) # placement-x (absolute) - write_sint(buf, 400) # placement-y (absolute) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0011_1001) # CNXY_RAAF + write_sint(buf, 700) # placement-x (absolute) + write_sint(buf, 400) # placement-y (absolute) + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 5 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_1010) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_1010) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 0) # repetition (reuse) # PLACEMENT 6 - write_uint(buf, 17) # PLACEMENT (simple) - write_byte(buf, 0b0001_1011) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT (simple) + write_byte(buf, 0b0001_1011) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 13) # CELL record (name ref.) - write_uint(buf, 0) # Cell name 0 (A) + write_uint(buf, 13) # CELL record (name ref.) + write_uint(buf, 0) # Cell name 0 (A) write_rectangle(buf) @@ -604,84 +598,84 @@ def write_file_6(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'TOPTOP') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'TOPTOP') # Cell name - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record - write_uint(buf, 18) # PLACEMENT (mag 0.5, manhattan) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'TOP') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 0.5) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 90.0) # (angle) - write_sint(buf, 100) # placement-x (relative) - write_sint(buf, 0) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (mag 0.5, manhattan) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'TOP') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 0.5) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 90.0) # (angle) + write_sint(buf, 100) # placement-x (relative) + write_sint(buf, 0) # placement-y (relative) - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0011_0000) # CNXY_RMAF - write_sint(buf, 100) # placement-x (relative) - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0011_0000) # CNXY_RMAF + write_sint(buf, 100) # placement-x (relative) + write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'TOP') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'TOP') # Cell name - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 0 - write_uint(buf, 18) # PLACEMENT (mag 0.5, manhattan) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'A') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 0.5) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 0.0) # (angle) - write_sint(buf, -150) # placement-x (relative) - write_sint(buf, 200) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (mag 0.5, manhattan) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'A') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 0.5) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 0.0) # (angle) + write_sint(buf, -150) # placement-x (relative) + write_sint(buf, 200) # placement-y (relative) # PLACEMENT 1 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0011_0000) # CNXY_RMAF - write_sint(buf, -150) # placement-x (relative) - write_sint(buf, 600) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0011_0000) # CNXY_RMAF + write_sint(buf, -150) # placement-x (relative) + write_sint(buf, 600) # placement-y (relative) # PLACEMENT 2 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0001_0000) # CNXY_RMAF - write_sint(buf, 400) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0001_0000) # CNXY_RMAF + write_sint(buf, 400) # placement-y (relative) # PLACEMENT 3 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0010_0000) # CNXY_RMAF - write_sint(buf, 300) # placement-x (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0010_0000) # CNXY_RMAF + write_sint(buf, 300) # placement-x (relative) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 4 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0011_0001) # CNXY_RMAF - write_sint(buf, 700) # placement-x (absolute) - write_sint(buf, 400) # placement-y (absolute) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0011_0001) # CNXY_RMAF + write_sint(buf, 700) # placement-x (absolute) + write_sint(buf, 400) # placement-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 5 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0001_0010) # CNXY_RMAF - write_uint(buf, 0) # angle (uint, positive) - write_uint(buf, 90) # (angle) - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0001_0010) # CNXY_RMAF + write_uint(buf, 0) # angle (uint, positive) + write_uint(buf, 90) # (angle) + write_sint(buf, 1000) # placement-y (relative) # PLACEMENT 6 - write_uint(buf, 18) # PLACEMENT (no mag, manhattan) - write_byte(buf, 0b0001_0011) # CNXY_RMAF - write_uint(buf, 1) # angle (uint, negative) - write_uint(buf, 90) # (angle) - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 18) # PLACEMENT (no mag, manhattan) + write_byte(buf, 0b0001_0011) # CNXY_RMAF + write_uint(buf, 1) # angle (uint, negative) + write_uint(buf, 90) # (angle) + write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name write_rectangle(buf) @@ -757,71 +751,71 @@ def write_file_8(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'TOPTOP') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'TOPTOP') # Cell name - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record - write_uint(buf, 18) # PLACEMENT (mag 0.5, arbitrary angle) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'TOP') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 0.5) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 22.5) # (angle) - write_sint(buf, 100) # placement-x (absolute) - write_sint(buf, 0) # placement-y (absolute) + write_uint(buf, 18) # PLACEMENT (mag 0.5, arbitrary angle) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'TOP') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 0.5) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 22.5) # (angle) + write_sint(buf, 100) # placement-x (absolute) + write_sint(buf, 0) # placement-y (absolute) - write_uint(buf, 18) # PLACEMENT (mag 1.0, manhattan) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'TOP') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 1.0) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 0.0) # (angle) - write_sint(buf, 1100) # placement-x (absolute) - write_sint(buf, 0) # placement-y (absolute) + write_uint(buf, 18) # PLACEMENT (mag 1.0, manhattan) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'TOP') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 1.0) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 0.0) # (angle) + write_sint(buf, 1100) # placement-x (absolute) + write_sint(buf, 0) # placement-y (absolute) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'TOP') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'TOP') # Cell name - write_uint(buf, 18) # PLACEMENT (mag 2.0, manhattan) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'A') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 2.0) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 0.0) # (angle) - write_sint(buf, -100) # placement-x (absolute) - write_sint(buf, 100) # placement-y (absolute) + write_uint(buf, 18) # PLACEMENT (mag 2.0, manhattan) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'A') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 2.0) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 0.0) # (angle) + write_sint(buf, -100) # placement-x (absolute) + write_sint(buf, 100) # placement-y (absolute) - write_uint(buf, 18) # PLACEMENT (mag 1.0, arbitrary angle) - write_byte(buf, 0b1011_0110) # CNXY_RMAF - write_bstring(buf, b'A') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 1.0) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 45.0) # (angle) - write_sint(buf, -150) # placement-x (absolute) - write_sint(buf, 1100) # placement-y (absolute) + write_uint(buf, 18) # PLACEMENT (mag 1.0, arbitrary angle) + write_byte(buf, 0b1011_0110) # CNXY_RMAF + write_bstring(buf, b'A') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 1.0) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 45.0) # (angle) + write_sint(buf, -150) # placement-x (absolute) + write_sint(buf, 1100) # placement-y (absolute) - write_uint(buf, 18) # PLACEMENT (mag 0.5, arbitrary angle) - write_byte(buf, 0b1011_1111) # CNXY_RMAF - write_bstring(buf, b'A') # Cell reference - write_uint(buf, 6) # magnitude, float32 - write_float32(buf, 0.5) # (magnitude) - write_uint(buf, 7) # angle, float64 - write_float64(buf, 135.0) # (angle) - write_sint(buf, -200) # placement-x (absolute) - write_sint(buf, 2100) # placement-y (absolute) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 18) # PLACEMENT (mag 0.5, arbitrary angle) + write_byte(buf, 0b1011_1111) # CNXY_RMAF + write_bstring(buf, b'A') # Cell reference + write_uint(buf, 6) # magnitude, float32 + write_float32(buf, 0.5) # (magnitude) + write_uint(buf, 7) # angle, float64 + write_float64(buf, 135.0) # (angle) + write_sint(buf, -200) # placement-x (absolute) + write_sint(buf, 2100) # placement-y (absolute) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'A') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'A') # Cell name write_rectangle(buf, pos=(30, -40)) diff --git a/fatamorgana/test/test_files_polygons.py b/fatamorgana/test/test_files_polygons.py index fc5d0c2..2deb808 100644 --- a/fatamorgana/test/test_files_polygons.py +++ b/fatamorgana/test/test_files_polygons.py @@ -1,17 +1,12 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore import numpy from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -85,8 +80,11 @@ def common_tests(layout: OasisLayout) -> None: for ii in range(4): msg = f'Fail on poly {ii}' assert len(geometry[0].point_list) == 6, msg - assert_equal(geometry[0].point_list, [[150, 0], [0, 50], [-50, 0], [0, 50], - [-100, 0], [0, -100]], err_msg=msg) + assert_equal( + geometry[0].point_list, + [[150, 0], [0, 50], [-50, 0], [0, 50], [-100, 0], [0, -100]], + err_msg=msg, + ) assert len(geometry[4].point_list) == 6 assert_equal(geometry[4].point_list, [[0, 150], [50, 0], [0, -50], [50, 0], [0, -100], [-100, 0]]) @@ -97,8 +95,10 @@ def common_tests(layout: OasisLayout) -> None: assert len(geometry[7].point_list) == 9 assert_equal(geometry[7].point_list, [[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25], [40, 0]]) assert len(geometry[8].point_list) == 9 - assert_equal(geometry[8].point_list, - numpy.cumsum([[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25], [45, -575]], axis=0)) + assert_equal( + geometry[8].point_list, + numpy.cumsum([[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25], [45, -575]], axis=0), + ) for ii in range(9, 12): msg = f'Fail on poly {ii}' @@ -114,49 +114,49 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: buf.write(HEADER) if variant == 3: - write_uint(buf, 7) # PROPNAME record (implict id 0) - write_bstring(buf, b'PROP0') # property name + write_uint(buf, 7) # PROPNAME record (implict id 0) + write_bstring(buf, b'PROP0') # property name - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'ABC') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'ABC') # Cell name # POLYGON 0 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_1011) # 00PX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 0) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_1011) # 00PX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 0) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) if variant == 3: # PROPERTY 0 - write_uint(buf, 28) # PROPERTY record (explicit) - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 2) # property value (real: positive reciprocal) - write_uint(buf, 5) # (real) 1/5 + write_uint(buf, 28) # PROPERTY record (explicit) + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 2) # property value (real: positive reciprocal) + write_uint(buf, 5) # (real) 1/5 write_uint(buf, 16) # XYRELATIVE record # Polygon 1 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_1011) # 00PX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -200) # geometry-x (relative) - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_1011) # 00PX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -200) # geometry-x (relative) + write_sint(buf, 300) # geometry-y (relative) if variant == 3: # PROPERTY 1 @@ -165,55 +165,55 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 15) # XYABSOLUTE record # Polygon 2 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 0) # geometry-x (absolute) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 0) # geometry-x (absolute) if variant == 3: # PROPERTY 2 write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 3 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0000_1000) # 00PX_YRDL - write_sint(buf, 1000) # geometry-y (absolute) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0000_1000) # 00PX_YRDL + write_sint(buf, 1000) # geometry-y (absolute) if variant == 3: # PROPERTY 3 write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 4 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 1) # pointlist: 1-delta, vert-fisrt - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 200) # geometry-x (absolute) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 1) # pointlist: 1-delta, vert-fisrt + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 200) # geometry-x (absolute) if variant == 3: # PROPERTY 4 write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 5 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 2) # pointlist: 2-delta - write_uint(buf, 7) # (pointlist) dimension + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 2) # pointlist: 2-delta + write_uint(buf, 7) # (pointlist) dimension write_uint(buf, 150 << 2 | 0b00) # (pointlist) write_uint(buf, 50 << 2 | 0b01) # (pointlist) write_uint(buf, 50 << 2 | 0b10) # (pointlist) @@ -228,12 +228,12 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 6 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 3) # pointlist: 3-delta - write_uint(buf, 8) # (pointlist) dimension + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 3) # pointlist: 3-delta + write_uint(buf, 8) # (pointlist) dimension write_uint(buf, 25 << 3 | 0b000) # (pointlist) write_uint(buf, 50 << 3 | 0b100) # (pointlist) write_uint(buf, 50 << 3 | 0b001) # (pointlist) @@ -249,12 +249,12 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 7 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 4) # pointlist: g-delta - write_uint(buf, 8) # (pointlist) dimension + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 4) # pointlist: g-delta + write_uint(buf, 8) # (pointlist) dimension write_uint(buf, 25 << 4 | 0b0000) # (pointlist) write_uint(buf, 50 << 4 | 0b1000) # (pointlist) write_uint(buf, 50 << 4 | 0b0010) # (pointlist) @@ -263,7 +263,7 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 50 << 4 | 0b0100) # (pointlist) write_uint(buf, 50 << 4 | 0b1100) # (pointlist) write_uint(buf, 10 << 2 | 0b01) # (pointlist) - write_sint(buf, -75 ) + write_sint(buf, -75) write_uint(buf, 25 << 4 | 0b1110) # (pointlist) write_sint(buf, 900) # geometry-x (absolute) @@ -272,12 +272,12 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 8 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 5) # pointlist: double g-delta - write_uint(buf, 8) # (pointlist) dimension + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 5) # pointlist: double g-delta + write_uint(buf, 8) # (pointlist) dimension write_uint(buf, 25 << 4 | 0b0000) # (pointlist) write_uint(buf, 50 << 4 | 0b1000) # (pointlist) write_uint(buf, 50 << 4 | 0b0010) # (pointlist) @@ -286,7 +286,7 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 50 << 4 | 0b0100) # (pointlist) write_uint(buf, 50 << 4 | 0b1100) # (pointlist) write_uint(buf, 10 << 2 | 0b01) # (pointlist) - write_sint(buf, -75 ) + write_sint(buf, -75) write_uint(buf, 25 << 4 | 0b1110) # (pointlist) write_sint(buf, 1100) # geometry-x (absolute) @@ -295,62 +295,62 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 9 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_1111) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 1) # pointlist: 1-delta (vert. first) - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 0) # geometry-x (absolute) - write_sint(buf, 2000) # geometry-y (absolute) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_1111) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 1) # pointlist: 1-delta (vert. first) + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 0) # geometry-x (absolute) + write_sint(buf, 2000) # geometry-y (absolute) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing if variant == 3: # PROPERTY 9 write_uint(buf, 29) # PROPERTY record (repeat) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # Polygon 10 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0110) # 00PX_YRDL - write_uint(buf, 1) # datatype - write_uint(buf, 1) # pointlist: 1-delta (vert. first) - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 1000) # geometry-x (relative) - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0110) # 00PX_YRDL + write_uint(buf, 1) # datatype + write_uint(buf, 1) # pointlist: 1-delta (vert. first) + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 1000) # geometry-x (relative) + write_uint(buf, 0) # repetition (reuse) if variant == 3: # PROPERTY 10 write_uint(buf, 29) # PROPERTY record (repeat) # Polygon 11 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0110) # 00PX_YRDL - write_uint(buf, 1) # datatype - write_uint(buf, 1) # pointlist: 1-delta (vert. first) - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 1000) # geometry-x (relative) - write_uint(buf, 6) # repetition (3 rows) - write_uint(buf, 1) # (repetition) dimension - write_uint(buf, 200) # (repetition) y-delta - write_uint(buf, 300) # (repetition) y-delta + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0110) # 00PX_YRDL + write_uint(buf, 1) # datatype + write_uint(buf, 1) # pointlist: 1-delta (vert. first) + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 1000) # geometry-x (relative) + write_uint(buf, 6) # repetition (3 rows) + write_uint(buf, 1) # (repetition) dimension + write_uint(buf, 200) # (repetition) y-delta + write_uint(buf, 300) # (repetition) y-delta if variant == 3: # PROPERTY 11 @@ -386,21 +386,21 @@ def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: write_uint(buf, 15) # XYRELATIVE record # POLYGON 0 - write_uint(buf, 21) # POLYGON record - write_byte(buf, 0b0011_0011) # 00PX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 4) # pointlist: g-delta - write_uint(buf, 8002) # (pointlist) dimension - write_uint(buf, 1000 << 2 | 0b11) # (pointlist) - write_sint(buf, 0) # (pointlist) + write_uint(buf, 21) # POLYGON record + write_byte(buf, 0b0011_0011) # 00PX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 4) # pointlist: g-delta + write_uint(buf, 8002) # (pointlist) dimension + write_uint(buf, 1000 << 2 | 0b11) # (pointlist) + write_sint(buf, 0) # (pointlist) for _ in range(4000): - write_uint(buf, 10 << 2 | 0b01) # (pointlist) - write_sint(buf, 20) # (pointlist) - write_uint(buf, 10 << 2 | 0b11) # (pointlist) - write_sint(buf, 20) # (pointlist) - write_uint(buf, 1000 << 2 | 0b01) # (pointlist) - write_sint(buf, 0) # (pointlist) + write_uint(buf, 10 << 2 | 0b01) # (pointlist) + write_sint(buf, 20) # (pointlist) + write_uint(buf, 10 << 2 | 0b11) # (pointlist) + write_sint(buf, 20) # (pointlist) + write_uint(buf, 1000 << 2 | 0b01) # (pointlist) + write_sint(buf, 0) # (pointlist) write_sint(buf, 0) # geometry-x (absolute) buf.write(FOOTER) @@ -425,7 +425,8 @@ def test_file_2() -> None: assert_equal(poly.point_list, ([[-1000, 0]] + [[(-1) ** nn * 10, 20] for nn in range(8000)] - + [[1000, 0], [0, -20 * 8000]])) + + [[1000, 0], [0, -20 * 8000]]), + ) def test_file_3() -> None: diff --git a/fatamorgana/test/test_files_properties.py b/fatamorgana/test/test_files_properties.py index a49d7e1..107b64a 100644 --- a/fatamorgana/test/test_files_properties.py +++ b/fatamorgana/test/test_files_properties.py @@ -1,17 +1,13 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore -import numpy +import pytest from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte +from ..basic import InvalidDataError from ..main import OasisLayout @@ -54,7 +50,6 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 7) # PROPNAME record (implicit id 1) write_bstring(buf, b'PROP1') - write_uint(buf, 14) # CELL record (explicit) write_bstring(buf, b'A') # Cell name @@ -74,11 +69,29 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 300) # (repetition) x-spacing write_uint(buf, 320) # (repetition) y-spacing - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_0100) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_0100) # UUUU_VCNS write_bstring(buf, b'PROPX') # RECTANGLE 1 + write_uint(buf, 20) # RECTANGLE record + var_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) + if include_repetitions: + write_uint(buf, 0) # repetition (reuse) + + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 1) # property value 0 (real type 1, negative int) + write_uint(buf, 5) # (real 1) + + # RECTANGLE 2 write_uint(buf, 20) # RECTANGLE record var_byte(buf, 0b0111_1011) # SWHX_YRDL write_uint(buf, 1) # layer @@ -90,60 +103,20 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: if include_repetitions: write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 1) # property value 0 (real type 1, negative int) - write_uint(buf, 5) # (real 1) - - # RECTANGLE 2 - write_uint(buf, 20) # RECTANGLE record - var_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) - if include_repetitions: - write_uint(buf, 0) # repetition (reuse) - - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0100_0110) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 8) # prop value 0 (unsigned int) - write_uint(buf, 25) # (prop value) - write_uint(buf, 9) # prop value 1 (signed int) - write_sint(buf, -124) # (prop value) - write_uint(buf, 10) # prop value 2 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0100_0110) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 8) # prop value 0 (unsigned int) + write_uint(buf, 25) # (prop value) + write_uint(buf, 9) # prop value 1 (signed int) + write_sint(buf, -124) # (prop value) + write_uint(buf, 10) # prop value 2 (a-string) write_bstring(buf, b'PROP_VALUE2') - write_uint(buf, 13) # prop value 3 (propstring ref.) + write_uint(buf, 13) # prop value 3 (propstring ref.) write_uint(buf, 12) # RECTANGLE 3 write_uint(buf, 20) # RECTANGLE record - var_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) - if include_repetitions: - write_uint(buf, 0) # repetition (reuse) - - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b1111_0000) # UUUU_VCNS - write_uint(buf, 3) # number of values - write_uint(buf, 0) # prop value 0 (unsigned int) - write_uint(buf, 25) # (prop value) - write_uint(buf, 9) # prop value 1 (signed int) - write_sint(buf, -124) # (prop value) - write_uint(buf, 14) # prop value 2 (propstring ref.) - write_uint(buf, 13) - - # RECTANGLE 4 - write_uint(buf, 20) # RECTANGLE record var_byte(buf, 0b0111_1011) # SWHX_YRDL write_uint(buf, 1) # layer write_uint(buf, 2) # datatype @@ -154,14 +127,36 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: if include_repetitions: write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_1000) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b1111_0000) # UUUU_VCNS + write_uint(buf, 3) # number of values + write_uint(buf, 0) # prop value 0 (unsigned int) + write_uint(buf, 25) # (prop value) + write_uint(buf, 9) # prop value 1 (signed int) + write_sint(buf, -124) # (prop value) + write_uint(buf, 14) # prop value 2 (propstring ref.) + write_uint(buf, 13) - write_uint(buf, 15) # XYABSOLUTE record + # RECTANGLE 4 + write_uint(buf, 20) # RECTANGLE record + var_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) + if include_repetitions: + write_uint(buf, 0) # repetition (reuse) + + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_1000) # UUUU_VCNS + + write_uint(buf, 15) # XYABSOLUTE record # TEXT 5 write_uint(buf, 19) # TEXT record - var_byte(buf, 0b0101_1011) # 0CNX_YRTL + var_byte(buf, 0b0101_1011) # 0CNX_YRTL write_bstring(buf, b'A') # text-string write_uint(buf, 2) # text-layer write_uint(buf, 1) # text-datatype @@ -173,47 +168,47 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 29) # PROPERTY (reuse) # PATH 6 - write_uint(buf, 22) # PATH record - var_byte(buf, 0b1111_1011) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 10) # half-width - write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE - write_sint(buf, 5) # (extension-scheme) - write_sint(buf, -5) # (extension-scheme) - write_uint(buf, 0) # pointlist (1-delta, horiz. first) - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 2000) # geometry-x (absolute) - write_sint(buf, 0) # geometry-y (absolute) + write_uint(buf, 22) # PATH record + var_byte(buf, 0b1111_1011) # EWPX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 10) # half-width + write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE + write_sint(buf, 5) # (extension-scheme) + write_sint(buf, -5) # (extension-scheme) + write_uint(buf, 0) # pointlist (1-delta, horiz. first) + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 2000) # geometry-x (absolute) + write_sint(buf, 0) # geometry-y (absolute) if include_repetitions: - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # POLYGON 7 - write_uint(buf, 21) # POLYGON record - var_byte(buf, 0b0011_1011) # 00PX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 0) # pointlist (1-delta, horiz. first) - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 3000) # geometry-x (absolute) - write_sint(buf, 0) # geometry-y (absolute) + write_uint(buf, 21) # POLYGON record + var_byte(buf, 0b0011_1011) # 00PX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 0) # pointlist (1-delta, horiz. first) + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 3000) # geometry-x (absolute) + write_sint(buf, 0) # geometry-y (absolute) if include_repetitions: - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_0110) # UUUU_VCNS - write_uint(buf, 1) # propname id + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_0110) # UUUU_VCNS + write_uint(buf, 1) # propname id if variant == 5: write_uint(buf, 10) # PROPSTRING (explicit id) @@ -375,141 +370,141 @@ def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: write_uint(buf, 7) # PROPNAME record (implicit id 0) write_bstring(buf, b'S_GDS_PROPERTY') - + # ** CELL ** write_uint(buf, 14) # CELL record (explicit) write_bstring(buf, b'A') # Cell name write_uint(buf, 16) # XYRELATIVE record # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0010_0111) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 8) # property value 0 (unsigned int) - write_uint(buf, 25) # (...) - write_uint(buf, 10) # property value 1 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0010_0111) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 8) # property value 0 (unsigned int) + write_uint(buf, 25) # (...) + write_uint(buf, 10) # property value 1 (a-string) write_bstring(buf, b'PROP_VALUE2') # RECTANGLE 1 - write_uint(buf, 20) # RECTANGLE record + write_uint(buf, 20) # RECTANGLE record write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b1111_0001) # UUUU_VCNS - write_uint(buf, 2) # number of values - write_uint(buf, 8) # property value 0 (unsigned int) - write_uint(buf, 10) # (...) - write_uint(buf, 14) # property value 1 (prop-string ref.) - write_uint(buf, 13) # (...) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b1111_0001) # UUUU_VCNS + write_uint(buf, 2) # number of values + write_uint(buf, 8) # property value 0 (unsigned int) + write_uint(buf, 10) # (...) + write_uint(buf, 14) # property value 1 (prop-string ref.) + write_uint(buf, 13) # (...) # RECTANGLE 2 - write_uint(buf, 20) # RECTANGLE record + write_uint(buf, 20) # RECTANGLE record write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_1001) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_1001) # UUUU_VCNS # RECTANGLE 3 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # RECTANGLE 4 - write_uint(buf, 20) # RECTANGLE record + write_uint(buf, 20) # RECTANGLE record write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 0) # geometry-x (relative) - write_sint(buf, 1000) # geometry-y (relative) + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 0) # geometry-x (relative) + write_sint(buf, 1000) # geometry-y (relative) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_1001) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_1001) # UUUU_VCNS - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0010_0111) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 8) # prop value 0 (unsigned int) - write_uint(buf, 25) # (...) - write_uint(buf, 10) # prop-value 1 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0010_0111) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 8) # prop value 0 (unsigned int) + write_uint(buf, 25) # (...) + write_uint(buf, 10) # prop-value 1 (a-string) write_bstring(buf, b'PROP_VALUE2') # (...) write_uint(buf, 15) # XYABSOLUTE record # TEXT 5 - write_uint(buf, 19) # TEXT record - write_byte(buf, 0b0101_1011) # 0CNX_YRTL - write_bstring(buf, b'A') # text-string - write_uint(buf, 2) # text-layer - write_uint(buf, 1) # text-datatype - write_sint(buf, 1000) # geometry-x (absolute) - write_sint(buf, 0) # geometry-y (absolute) + write_uint(buf, 19) # TEXT record + write_byte(buf, 0b0101_1011) # 0CNX_YRTL + write_bstring(buf, b'A') # text-string + write_uint(buf, 2) # text-layer + write_uint(buf, 1) # text-datatype + write_sint(buf, 1000) # geometry-x (absolute) + write_sint(buf, 0) # geometry-y (absolute) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # PATH 6 - write_uint(buf, 22) # PATH record + write_uint(buf, 22) # PATH record write_byte(buf, 0b1111_1011) # EWPX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 10) # half-width - write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE - write_sint(buf, 5) # (extension-scheme) - write_sint(buf, -5) # (extension-scheme) - write_uint(buf, 0) # pointlist (1-delta, horiz. first) - write_uint(buf, 3) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 2000) # geometry-x (absolute) - write_sint(buf, 0) # geometry-y (absolute) + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 10) # half-width + write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE + write_sint(buf, 5) # (extension-scheme) + write_sint(buf, -5) # (extension-scheme) + write_uint(buf, 0) # pointlist (1-delta, horiz. first) + write_uint(buf, 3) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 2000) # geometry-x (absolute) + write_sint(buf, 0) # geometry-y (absolute) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # POLYGON 7 - write_uint(buf, 21) # POLYGON record + write_uint(buf, 21) # POLYGON record write_byte(buf, 0b0011_1011) # 00PX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 0) # pointlist (1-delta, horiz. first) - write_uint(buf, 4) # (pointlist) dimension - write_sint(buf, 150) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, -50) # (pointlist) - write_sint(buf, 50) # (pointlist) - write_sint(buf, 3000) # geometry-x (absolute) - write_sint(buf, 0) # geometry-y (absolute) + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 0) # pointlist (1-delta, horiz. first) + write_uint(buf, 4) # (pointlist) dimension + write_sint(buf, 150) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, -50) # (pointlist) + write_sint(buf, 50) # (pointlist) + write_sint(buf, 3000) # geometry-x (absolute) + write_sint(buf, 0) # geometry-y (absolute) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) buf.write(FOOTER) return buf @@ -605,180 +600,180 @@ def write_file_4_6(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_bstring(buf, b'A') # Cell name # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 300) # geometry-x (relative) - write_sint(buf, -400) # geometry-y (relative) - + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 300) # geometry-x (relative) + write_sint(buf, -400) # geometry-y (relative) + # ** CELL ** write_uint(buf, 14) # CELL record (explicit) write_bstring(buf, b'TOP') # Cell name # PLACEMENT 0 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b1011_0000) # CNXY_RAAF - write_bstring(buf, b'A') # cell name - write_sint(buf, -300) # placement-x - write_sint(buf, 400) # placement-y + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b1011_0000) # CNXY_RAAF + write_bstring(buf, b'A') # cell name + write_sint(buf, -300) # placement-x + write_sint(buf, 400) # placement-y - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0010_0111) # UUUU_VCNS - write_uint(buf, 0) # propname-id - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 25) # (...) - write_uint(buf, 10) # prop-value 1 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0010_0111) # UUUU_VCNS + write_uint(buf, 0) # propname-id + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 25) # (...) + write_uint(buf, 10) # prop-value 1 (a-string) write_bstring(buf, b'PROP_VALUE2') if variant == 6: - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0010_0111) # UUUU_VCNS - write_uint(buf, 0) # propname-id - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 26) # (...) - write_uint(buf, 10) # prop-value 1 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0010_0111) # UUUU_VCNS + write_uint(buf, 0) # propname-id + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 26) # (...) + write_uint(buf, 10) # prop-value 1 (a-string) write_bstring(buf, b'PROP_VALUE26') # PLACEMENT 1 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_0000) # CNXY_RAAF - write_sint(buf, 0) # placement-x + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_0000) # CNXY_RAAF + write_sint(buf, 0) # placement-x if variant == 4: write_sint(buf, 200) # placement-y else: write_sint(buf, 400) # placement-y - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b1111_0001) # UUUU_VCNS - write_uint(buf, 2) # number of values - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 10) # (...) - write_uint(buf, 14) # prop-value 1 (prop-string ref.) - write_uint(buf, 13) # (...) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b1111_0001) # UUUU_VCNS + write_uint(buf, 2) # number of values + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 10) # (...) + write_uint(buf, 14) # prop-value 1 (prop-string ref.) + write_uint(buf, 13) # (...) # PLACEMENT 2 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0001_0000) # CNXY_RAAF - write_sint(buf, 400) # placement-y + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0001_0000) # CNXY_RAAF + write_sint(buf, 400) # placement-y - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_1001) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_1001) # UUUU_VCNS # PLACEMENT 3 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0010_0000) # CNXY_RAAF - write_sint(buf, 300) # placement-x + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0010_0000) # CNXY_RAAF + write_sint(buf, 300) # placement-x - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 4 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_0001) # CNXY_RAAF - write_sint(buf, 700) # placement-x (absolute) - write_sint(buf, 400) # placement-y (absolute) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_0001) # CNXY_RAAF + write_sint(buf, 700) # placement-x (absolute) + write_sint(buf, 400) # placement-y (absolute) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0000_1001) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0000_1001) # UUUU_VCNS - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 5 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0001_0010) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0001_0010) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0010_0111) # UUUU_VCNS - write_uint(buf, 0) # propname-id - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 25) # (...) - write_uint(buf, 10) # prop-value 1 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0010_0111) # UUUU_VCNS + write_uint(buf, 0) # propname-id + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 25) # (...) + write_uint(buf, 10) # prop-value 1 (a-string) write_bstring(buf, b'PROP_VALUE2') # PLACEMENT 6 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0001_0011) # CNXY_RAAF - write_sint(buf, 1000) # placement-y (relative) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0001_0011) # CNXY_RAAF + write_sint(buf, 1000) # placement-y (relative) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # PLACEMENT 7 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x (absolute) - write_sint(buf, 0) # placement-y (absolute) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 300) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x (absolute) + write_sint(buf, 0) # placement-y (absolute) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 300) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # PLACEMENT 8 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x - write_sint(buf, 0) # placement-y - write_uint(buf, 0) # repetition (reuse) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x + write_sint(buf, 0) # placement-y + write_uint(buf, 0) # repetition (reuse) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # PLACEMENT 9 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x - write_sint(buf, 0) # placement-y - write_uint(buf, 2) # repetition (3 cols.) - write_uint(buf, 1) # (repetition) dimension - write_uint(buf, 320) # (repetition) offset + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x + write_sint(buf, 0) # placement-y + write_uint(buf, 2) # repetition (3 cols.) + write_uint(buf, 1) # (repetition) dimension + write_uint(buf, 320) # (repetition) offset - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # PLACEMENT 10 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x - write_sint(buf, 0) # placement-y - write_uint(buf, 3) # repetition (4 rows) - write_uint(buf, 2) # (repetition) dimension - write_uint(buf, 310) # (repetition) offset + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x + write_sint(buf, 0) # placement-y + write_uint(buf, 3) # repetition (4 rows) + write_uint(buf, 2) # (repetition) dimension + write_uint(buf, 310) # (repetition) offset - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # PLACEMENT 11 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x - write_sint(buf, 0) # placement-y - write_uint(buf, 4) # repetition (4 arbitrary cols.) - write_uint(buf, 2) # (repetition) dimension - write_uint(buf, 320) # (repetition) - write_uint(buf, 330) # (repetition) - write_uint(buf, 340) # (repetition) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x + write_sint(buf, 0) # placement-y + write_uint(buf, 4) # repetition (4 arbitrary cols.) + write_uint(buf, 2) # (repetition) dimension + write_uint(buf, 320) # (repetition) + write_uint(buf, 330) # (repetition) + write_uint(buf, 340) # (repetition) - write_uint(buf, 29) # PROPERTY (reuse) + write_uint(buf, 29) # PROPERTY (reuse) # PLACEMENT 12 - write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) - write_byte(buf, 0b0011_1111) # CNXY_RAAF - write_sint(buf, 2000) # placement-x - write_sint(buf, 0) # placement-y - write_uint(buf, 8) # repetition (3x4 matrix, arbitrary vectors) - write_uint(buf, 1) # (repetition) n-dimension - write_uint(buf, 2) # (repetition) m-dimension - write_uint(buf, 310 << 2 | 0b01) # (repetition) n-displacement g-delta (310, 320) + write_uint(buf, 17) # PLACEMENT record (no mag, manhattan) + write_byte(buf, 0b0011_1111) # CNXY_RAAF + write_sint(buf, 2000) # placement-x + write_sint(buf, 0) # placement-y + write_uint(buf, 8) # repetition (3x4 matrix, arbitrary vectors) + write_uint(buf, 1) # (repetition) n-dimension + write_uint(buf, 2) # (repetition) m-dimension + write_uint(buf, 310 << 2 | 0b01) # (repetition) n-displacement g-delta (310, 320) write_sint(buf, 320) - write_uint(buf, 330 << 4 | 0b1010) # (repetition) m-dispalcement g-delta 330/northwest = (-330, 330) + write_uint(buf, 330 << 4 | 0b1010) # (repetition) m-dispalcement g-delta 330/northwest = (-330, 330) write_uint(buf, 29) # PROPERTY (reuse) @@ -937,16 +932,16 @@ def write_file_7_8_9(buf: BufferedIOBase, variant: int) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_0100) # UUUU_VCNS + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_0100) # UUUU_VCNS write_bstring(buf, b'FileProp1') # property name - write_uint(buf, 10) # prop-value 0 (a-string) + write_uint(buf, 10) # prop-value 0 (a-string) write_bstring(buf, b'FileProp1Value') - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 13) # prop-name reference - write_uint(buf, 10) # prop-value 0 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 13) # prop-name reference + write_uint(buf, 10) # prop-value 0 (a-string) write_bstring(buf, b'FileProp1Value') write_uint(buf, 8) # PROPNAME record (explicit id) @@ -957,70 +952,69 @@ def write_file_7_8_9(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 28) # PROPERTY record if variant == 8: # Will give an error since the value modal variable is reset by PROPNAME_ID - write_byte(buf, 0b0001_1110) # UUUU_VCNS + write_byte(buf, 0b0001_1110) # UUUU_VCNS else: - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 13) # prop-name reference + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 13) # prop-name reference if variant != 8: - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 17) # (...) + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 17) # (...) write_uint(buf, 10) # PROPSTRING (explicit id) write_bstring(buf, b'FileProp2Value') write_uint(buf, 12) # id # associated with PROPSTRING? - write_uint(buf, 28) # PROPERTY record + write_uint(buf, 28) # PROPERTY record if variant == 9: # Will give an error since the value modal variable is unset - write_byte(buf, 0b0001_1110) # UUUU_VCNS + write_byte(buf, 0b0001_1110) # UUUU_VCNS else: - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 13) # prop-name reference + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 13) # prop-name reference if variant != 9: - write_uint(buf, 8) # prop-value 0 (unsigned int) - write_uint(buf, 42) # (...) + write_uint(buf, 8) # prop-value 0 (unsigned int) + write_uint(buf, 42) # (...) write_uint(buf, 3) # CELLNAME record (implicit id 0) write_bstring(buf, b'A') # associated with cell A, through CELLNAME # TODO - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_0100) # UUUU_VCNS - write_bstring(buf, b'CellProp0') # prop name - write_uint(buf, 10) # prop-value 0 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_0100) # UUUU_VCNS + write_bstring(buf, b'CellProp0') # prop name + write_uint(buf, 10) # prop-value 0 (a-string) write_bstring(buf, b'CPValue0') - + # ** CELL ** write_uint(buf, 13) # CELL record (name ref.) write_uint(buf, 0) # Cell name 0 (XYZ) # associated with cell A - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_0100) # UUUU_VCNS - write_bstring(buf, b'CellProp1') # prop name - write_uint(buf, 10) # prop-value 0 (a-string) + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_0100) # UUUU_VCNS + write_bstring(buf, b'CellProp1') # prop name + write_uint(buf, 10) # prop-value 0 (a-string) write_bstring(buf, b'CPValue') - write_uint(buf, 28) # PROPERTY record - write_byte(buf, 0b0001_1100) # UUUU_VCNS - write_bstring(buf, b'CellProp2') # prop name + write_uint(buf, 28) # PROPERTY record + write_byte(buf, 0b0001_1100) # UUUU_VCNS + write_bstring(buf, b'CellProp2') # prop name # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 300) # geometry-x - write_sint(buf, -400) # geometry-y + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 300) # geometry-x + write_sint(buf, -400) # geometry-y buf.write(FOOTER) return buf - def test_file_7() -> None: buf = write_file_7_8_9(BytesIO(), 7) diff --git a/fatamorgana/test/test_files_rectangles.py b/fatamorgana/test/test_files_rectangles.py index f47503f..e9f0b99 100644 --- a/fatamorgana/test/test_files_rectangles.py +++ b/fatamorgana/test/test_files_rectangles.py @@ -1,15 +1,9 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct - -import pytest # type: ignore from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -88,149 +82,149 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: buf.write(HEADER) if variant == 2: - write_uint(buf, 7) # PROPNAME record (implict id 0) - write_bstring(buf, b'PROP0') # property name + write_uint(buf, 7) # PROPNAME record (implict id 0) + write_bstring(buf, b'PROP0') # property name write_uint(buf, 14) # CELL record (explicit) write_bstring(buf, b'ABC') # Cell name # RECTANGLE 0 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 300) # geometry-x (absolute) - write_sint(buf, -400) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 300) # geometry-x (absolute) + write_sint(buf, -400) # geometry-y (absolute) if variant == 2: # PROPERTY 0 - write_uint(buf, 28) # PROPERTY record (explicit) - write_byte(buf, 0b0001_0110) # UUUU_VCNS - write_uint(buf, 0) # propname id - write_uint(buf, 2) # property value (real: positive reciprocal) - write_uint(buf, 5) # (real) 1/5 + write_uint(buf, 28) # PROPERTY record (explicit) + write_byte(buf, 0b0001_0110) # UUUU_VCNS + write_uint(buf, 0) # propname id + write_uint(buf, 2) # property value (real: positive reciprocal) + write_uint(buf, 5) # (real) 1/5 write_uint(buf, 16) # XYRELATIVE record # RECTANGLE 1 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 100) # geometry-x (relative) - write_sint(buf, -100) # geometry-y (relative) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 100) # geometry-x (relative) + write_sint(buf, -100) # geometry-y (relative) if variant == 2: # PROPERTY 1 write_uint(buf, 29) # PROPERTY record (repeat) - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # RECTANGLE 2 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_1011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 600) # geometry-x (absolute) - write_sint(buf, -300) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_1011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 600) # geometry-x (absolute) + write_sint(buf, -300) # geometry-y (absolute) if variant == 2: # PROPERTY 2 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 3 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0111_0011) # SWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, 800) # geometry-x (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0111_0011) # SWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, 800) # geometry-x (absolute) if variant == 2: # PROPERTY 3 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 4 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0110_1011) # SWHX_YRDL - write_uint(buf, 2) # layer - write_uint(buf, 3) # datatype - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, -600) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0110_1011) # SWHX_YRDL + write_uint(buf, 2) # layer + write_uint(buf, 3) # datatype + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, -600) # geometry-y (absolute) if variant == 2: # PROPERTY 4 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 5 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0110_1000) # SWHX_YRDL - write_uint(buf, 100) # width - write_uint(buf, 200) # height - write_sint(buf, -900) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0110_1000) # SWHX_YRDL + write_uint(buf, 100) # width + write_uint(buf, 200) # height + write_sint(buf, -900) # geometry-y (absolute) if variant == 2: # PROPERTY 5 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 6 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_1000) # SWHX_YRDL - write_sint(buf, -1200) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_1000) # SWHX_YRDL + write_sint(buf, -1200) # geometry-y (absolute) if variant == 2: # PROPERTY 6 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 7 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b1100_1000) # SWHX_YRDL - write_uint(buf, 150) # width - write_sint(buf, -1500) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b1100_1000) # SWHX_YRDL + write_uint(buf, 150) # width + write_sint(buf, -1500) # geometry-y (absolute) if variant == 2: # PROPERTY 7 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 8 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_1000) # SWHX_YRDL - write_sint(buf, -1800) # geometry-y (absolute) + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_1000) # SWHX_YRDL + write_sint(buf, -1800) # geometry-y (absolute) if variant == 2: # PROPERTY 8 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 9 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_1100) # SWHX_YRDL - write_sint(buf, 500) # geometry-y (absolute) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_1100) # SWHX_YRDL + write_sint(buf, 500) # geometry-y (absolute) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing if variant == 2: # PROPERTY 9 write_uint(buf, 29) # PROPERTY record (repeat) # RECTANGLE 10 - write_uint(buf, 20) # RECTANGLE record - write_byte(buf, 0b0000_1100) # SWHX_YRDL - write_sint(buf, 2000) # geometry-y (absolute) - write_uint(buf, 4) # repetition (3 arbitrary cols.) - write_uint(buf, 1) # (repetition) dimension - write_uint(buf, 200) # (repetition) x-delta - write_uint(buf, 300) # (repetition) x-delta + write_uint(buf, 20) # RECTANGLE record + write_byte(buf, 0b0000_1100) # SWHX_YRDL + write_sint(buf, 2000) # geometry-y (absolute) + write_uint(buf, 4) # repetition (3 arbitrary cols.) + write_uint(buf, 1) # (repetition) dimension + write_uint(buf, 200) # (repetition) x-delta + write_uint(buf, 300) # (repetition) x-delta if variant == 2: # PROPERTY 10 diff --git a/fatamorgana/test/test_files_texts.py b/fatamorgana/test/test_files_texts.py index c23877c..0ee22a0 100644 --- a/fatamorgana/test/test_files_texts.py +++ b/fatamorgana/test/test_files_texts.py @@ -1,14 +1,11 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct -import pytest # type: ignore +import pytest from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..basic import InvalidRecordError, InvalidDataError from ..basic import GridRepetition, ArbitraryRepetition from ..main import OasisLayout @@ -86,12 +83,12 @@ def common_tests(layout: OasisLayout) -> None: assert geometry[13].repetition.b_vector == [-10, 10] assert geometry[14].repetition.a_count == 3 - assert geometry[14].repetition.b_count == None + assert geometry[14].repetition.b_count is None assert geometry[14].repetition.a_vector == [11, 12] assert geometry[14].repetition.b_vector is None assert geometry[15].repetition.a_count == 4 - assert geometry[15].repetition.b_count == None + assert geometry[15].repetition.b_count is None assert geometry[15].repetition.a_vector == [-10, 10] assert geometry[15].repetition.b_vector is None @@ -256,9 +253,9 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 8) # repetition (3x4 matrix w/arb. vectors) write_uint(buf, 1) # (repetition) n-dimension write_uint(buf, 2) # (repetition) m-dimension - write_uint(buf, (10 << 4) | 0b0000) # (repetition) n-displacement g-delta: 10/east = (10, 0) - write_uint(buf, (11 << 2) | 0b11) # (repetition) m-displacement g-delta: (-11, -12) - write_sint(buf, -12) # (repetition g-delta) + write_uint(buf, (10 << 4) | 0b0000) # (repetition) n-displacement g-delta: 10/east = (10, 0) + write_uint(buf, (11 << 2) | 0b11) # (repetition) m-displacement g-delta: (-11, -12) + write_sint(buf, -12) # (repetition g-delta) # TEXT 13 write_uint(buf, 19) # TEXT record @@ -267,9 +264,9 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: write_uint(buf, 8) # repetition (3x4 matrix w/arb. vectors) write_uint(buf, 1) # (repetition) n-dimension write_uint(buf, 2) # (repetition) m-dimension - write_uint(buf, (11 << 2) | 0b01) # (repetition) n-displacement g-delta: (11, 12) + write_uint(buf, (11 << 2) | 0b01) # (repetition) n-displacement g-delta: (11, 12) write_sint(buf, 12) - write_uint(buf, (10 << 4) | 0b1010) # (repetition) n-displacement g-delta: 10/northwest = (-10, 10) + write_uint(buf, (10 << 4) | 0b1010) # (repetition) n-displacement g-delta: 10/northwest = (-10, 10) # TEXT 14 write_uint(buf, 19) # TEXT record diff --git a/fatamorgana/test/test_files_trapezoids.py b/fatamorgana/test/test_files_trapezoids.py index 1bd67e1..574054d 100644 --- a/fatamorgana/test/test_files_trapezoids.py +++ b/fatamorgana/test/test_files_trapezoids.py @@ -1,17 +1,9 @@ # type: ignore -from typing import List, Tuple, Iterable -from itertools import chain from io import BytesIO, BufferedIOBase -import struct - -import pytest # type: ignore -import numpy -from numpy.testing import assert_equal from .utils import HEADER, FOOTER -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme -from ..basic import InvalidRecordError, InvalidDataError +from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout @@ -37,145 +29,145 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: ''' buf.write(HEADER) - write_uint(buf, 14) # CELL record (explicit) - write_bstring(buf, b'ABC') # Cell name + write_uint(buf, 14) # CELL record (explicit) + write_bstring(buf, b'ABC') # Cell name # Trapezoid 0 - write_uint(buf, 23) # TRAPEZOID record - write_byte(buf, 0b0111_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 50) # height - write_sint(buf, -20) # delta-a - write_sint(buf, 40) # delta-b - write_sint(buf, 0) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 23) # TRAPEZOID record + write_byte(buf, 0b0111_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 50) # height + write_sint(buf, -20) # delta-a + write_sint(buf, 40) # delta-b + write_sint(buf, 0) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # Trapezoid 1 - write_uint(buf, 23) # TRAPEZOID record - write_byte(buf, 0b1010_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 50) # height - write_sint(buf, 20) # delta-a - write_sint(buf, 40) # delta-b - write_sint(buf, 300) # geometry-y (absolute) + write_uint(buf, 23) # TRAPEZOID record + write_byte(buf, 0b1010_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 50) # height + write_sint(buf, 20) # delta-a + write_sint(buf, 40) # delta-b + write_sint(buf, 300) # geometry-y (absolute) # Trapezoid 2 - write_uint(buf, 23) # TRAPEZOID record - write_byte(buf, 0b1100_1001) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, 20) # delta-a - write_sint(buf, -20) # delta-b - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 23) # TRAPEZOID record + write_byte(buf, 0b1100_1001) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, 20) # delta-a + write_sint(buf, -20) # delta-b + write_sint(buf, 300) # geometry-y (relative) # Trapezoid 3 - write_uint(buf, 23) # TRAPEZOID record - write_byte(buf, 0b0100_1101) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, 20) # delta-a - write_sint(buf, -20) # delta-b - write_sint(buf, 300) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 23) # TRAPEZOID record + write_byte(buf, 0b0100_1101) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, 20) # delta-a + write_sint(buf, -20) # delta-b + write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # Trapezoid 4 - write_uint(buf, 24) # TRAPEZOID record - write_byte(buf, 0b0111_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 50) # height - write_sint(buf, -20) # delta-a - write_sint(buf, 1000) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 24) # TRAPEZOID record + write_byte(buf, 0b0111_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 50) # height + write_sint(buf, -20) # delta-a + write_sint(buf, 1000) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # Trapezoid 5 - write_uint(buf, 24) # TRAPEZOID record - write_byte(buf, 0b1010_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 50) # height - write_sint(buf, 20) # delta-a - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 24) # TRAPEZOID record + write_byte(buf, 0b1010_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 50) # height + write_sint(buf, 20) # delta-a + write_sint(buf, 300) # geometry-y (relative) # Trapezoid 6 - write_uint(buf, 24) # TRAPEZOID record - write_byte(buf, 0b1100_1001) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, 20) # delta-a - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 24) # TRAPEZOID record + write_byte(buf, 0b1100_1001) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, 20) # delta-a + write_sint(buf, 300) # geometry-y (relative) # Trapezoid 7 - write_uint(buf, 24) # TRAPEZOID record - write_byte(buf, 0b0100_1101) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, 20) # delta-a - write_sint(buf, 300) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 24) # TRAPEZOID record + write_byte(buf, 0b0100_1101) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, 20) # delta-a + write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing - write_uint(buf, 15) # XYABSOLUTE record + write_uint(buf, 15) # XYABSOLUTE record # Trapezoid 8 - write_uint(buf, 25) # TRAPEZOID record - write_byte(buf, 0b0111_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 100) # width - write_uint(buf, 50) # height - write_sint(buf, 40) # delta-b - write_sint(buf, 2000) # geometry-x (absolute) - write_sint(buf, 100) # geometry-y (absolute) + write_uint(buf, 25) # TRAPEZOID record + write_byte(buf, 0b0111_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 100) # width + write_uint(buf, 50) # height + write_sint(buf, 40) # delta-b + write_sint(buf, 2000) # geometry-x (absolute) + write_sint(buf, 100) # geometry-y (absolute) - write_uint(buf, 16) # XYRELATIVE record + write_uint(buf, 16) # XYRELATIVE record # Trapezoid 9 - write_uint(buf, 25) # TRAPEZOID record - write_byte(buf, 0b1010_1011) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 2) # datatype - write_uint(buf, 50) # height - write_sint(buf, 40) # delta-b - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 25) # TRAPEZOID record + write_byte(buf, 0b1010_1011) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 2) # datatype + write_uint(buf, 50) # height + write_sint(buf, 40) # delta-b + write_sint(buf, 300) # geometry-y (relative) # Trapezoid 10 - write_uint(buf, 25) # TRAPEZOID record - write_byte(buf, 0b1100_1001) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, -20) # delta-b - write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 25) # TRAPEZOID record + write_byte(buf, 0b1100_1001) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, -20) # delta-b + write_sint(buf, 300) # geometry-y (relative) # Trapezoid 11 - write_uint(buf, 25) # TRAPEZOID record - write_byte(buf, 0b0100_1101) # OWHX_YRDL - write_uint(buf, 1) # layer - write_uint(buf, 150) # width - write_sint(buf, -20) # delta-b - write_sint(buf, 300) # geometry-y (relative) - write_uint(buf, 1) # repetition (3x4 matrix) - write_uint(buf, 1) # (repetition) x-dimension - write_uint(buf, 2) # (repetition) y-dimension - write_uint(buf, 200) # (repetition) x-spacing - write_uint(buf, 300) # (repetition) y-spacing + write_uint(buf, 25) # TRAPEZOID record + write_byte(buf, 0b0100_1101) # OWHX_YRDL + write_uint(buf, 1) # layer + write_uint(buf, 150) # width + write_sint(buf, -20) # delta-b + write_sint(buf, 300) # geometry-y (relative) + write_uint(buf, 1) # repetition (3x4 matrix) + write_uint(buf, 1) # (repetition) x-dimension + write_uint(buf, 2) # (repetition) y-dimension + write_uint(buf, 200) # (repetition) x-spacing + write_uint(buf, 300) # (repetition) y-spacing buf.write(FOOTER) return buf diff --git a/fatamorgana/test/test_int.py b/fatamorgana/test/test_int.py index 5f44053..c974535 100644 --- a/fatamorgana/test/test_int.py +++ b/fatamorgana/test/test_int.py @@ -1,9 +1,6 @@ -from typing import List, Tuple, Iterable from itertools import chain from io import BytesIO -import pytest # type: ignore - from ..basic import read_uint, read_sint, write_uint, write_sint diff --git a/fatamorgana/test/utils.py b/fatamorgana/test/utils.py index 0f60e7c..7985908 100644 --- a/fatamorgana/test/utils.py +++ b/fatamorgana/test/utils.py @@ -1,12 +1,6 @@ -from typing import List, Tuple, Iterable -from itertools import chain -from io import BytesIO, BufferedIOBase -import struct +from io import BytesIO -import pytest # type: ignore - -from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte -from ..main import OasisLayout +from ..basic import write_uint, write_bstring, write_byte MAGIC_BYTES = b'%SEMI-OASIS\r\n' From d61bbc530f9326c3d7491f1a4e8ac195e4bee741 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Thu, 26 Jan 2023 13:48:20 -0800 Subject: [PATCH 09/40] Use IO[bytes] everywhere --- fatamorgana/test/build_testfiles.py | 6 ++--- fatamorgana/test/test_files_cblocks.py | 6 ++--- fatamorgana/test/test_files_cells.py | 18 ++++++------- fatamorgana/test/test_files_circles.py | 6 ++--- fatamorgana/test/test_files_ctrapezoids.py | 8 +++--- fatamorgana/test/test_files_empty.py | 14 +++++----- fatamorgana/test/test_files_layernames.py | 31 +++++++++++----------- fatamorgana/test/test_files_modals.py | 6 ++--- fatamorgana/test/test_files_paths.py | 6 ++--- fatamorgana/test/test_files_placements.py | 21 ++++++++------- fatamorgana/test/test_files_polygons.py | 8 +++--- fatamorgana/test/test_files_properties.py | 12 ++++----- fatamorgana/test/test_files_rectangles.py | 6 ++--- fatamorgana/test/test_files_texts.py | 22 +++++++-------- fatamorgana/test/test_files_trapezoids.py | 6 ++--- 15 files changed, 88 insertions(+), 88 deletions(-) diff --git a/fatamorgana/test/build_testfiles.py b/fatamorgana/test/build_testfiles.py index e776c61..5bb7525 100644 --- a/fatamorgana/test/build_testfiles.py +++ b/fatamorgana/test/build_testfiles.py @@ -1,10 +1,8 @@ ''' Build files equivalent to the test cases used by KLayout. ''' -# type: ignore -from typing import Callable -from io import BufferedIOBase +from typing import Callable, IO from . import ( @@ -16,7 +14,7 @@ from . import ( ) -def build_file(num: str, func: Callable[[BufferedIOBase], BufferedIOBase]) -> None: +def build_file(num: str, func: Callable[[IO[bytes]], IO[bytes]]) -> None: with open('t' + num + '.oas', 'wb') as f: func(f) diff --git a/fatamorgana/test/test_files_cblocks.py b/fatamorgana/test/test_files_cblocks.py index cf3f2ec..3f02e93 100644 --- a/fatamorgana/test/test_files_cblocks.py +++ b/fatamorgana/test/test_files_cblocks.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from numpy.testing import assert_equal @@ -26,7 +26,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cells[0].properties -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_cells.py b/fatamorgana/test/test_files_cells.py index 9fae7b8..59bc6d4 100644 --- a/fatamorgana/test/test_files_cells.py +++ b/fatamorgana/test/test_files_cells.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO import pytest @@ -23,7 +23,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' Single cell with explicit name 'XYZ' ''' @@ -48,7 +48,7 @@ def test_file_1() -> None: assert not layout.cellnames -def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_2(buf: IO[bytes]) -> IO[bytes]: ''' Two cellnames ('XYZ', 'ABC') and two cells with name references. ''' @@ -85,7 +85,7 @@ def test_file_2() -> None: assert layout.cells[1].name == 1 -def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_3(buf: IO[bytes]) -> IO[bytes]: ''' Invalid file, contains a mix of explicit and implicit cellnames ''' @@ -116,7 +116,7 @@ def test_file_3() -> None: layout = OasisLayout.read(buf) -def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_4(buf: IO[bytes]) -> IO[bytes]: ''' Two cells referencing two names with explicit ids (unsorted) ''' @@ -155,7 +155,7 @@ def test_file_4() -> None: assert layout.cells[1].name == 1 -def write_file_5(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_5(buf: IO[bytes]) -> IO[bytes]: ''' Reference to non-existent cell name. ''' @@ -196,7 +196,7 @@ def test_file_5() -> None: #TODO add optional error checking for this case -def write_file_6(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_6(buf: IO[bytes]) -> IO[bytes]: ''' Cellname with invalid n-string. ''' @@ -237,7 +237,7 @@ def test_file_6() -> None: #assert layout.cells[1].name == 1 -def write_file_7(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_7(buf: IO[bytes]) -> IO[bytes]: ''' Unused cellname. ''' diff --git a/fatamorgana/test/test_files_circles.py b/fatamorgana/test/test_files_circles.py index 794c18f..f29b18f 100644 --- a/fatamorgana/test/test_files_circles.py +++ b/fatamorgana/test/test_files_circles.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte @@ -24,7 +24,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cells[0].properties -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_ctrapezoids.py b/fatamorgana/test/test_files_ctrapezoids.py index fdcc6cf..095909f 100644 --- a/fatamorgana/test/test_files_ctrapezoids.py +++ b/fatamorgana/test/test_files_ctrapezoids.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte @@ -20,7 +20,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -153,7 +153,7 @@ def test_file_1() -> None: assert geometry[55].repetition.b_vector == [0, 300] -def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_2(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_empty.py b/fatamorgana/test/test_files_empty.py index acf651d..8554c28 100644 --- a/fatamorgana/test/test_files_empty.py +++ b/fatamorgana/test/test_files_empty.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO import struct from .utils import MAGIC_BYTES, FOOTER @@ -22,7 +22,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' File contains one PAD record. 1000 units/micron @@ -55,7 +55,7 @@ def test_file_1() -> None: assert layout.unit == 1000 -def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_2(buf: IO[bytes]) -> IO[bytes]: ''' File contains no records. 1/2 unit/micron @@ -86,7 +86,7 @@ def test_file_2() -> None: assert layout.unit == 0.5 -def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_3(buf: IO[bytes]) -> IO[bytes]: ''' File contains no records. 10/4 unit/micron @@ -118,7 +118,7 @@ def test_file_3() -> None: assert layout.unit == 10 / 4 -def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_4(buf: IO[bytes]) -> IO[bytes]: ''' File contains no records. 12.5 unit/micron (float32) @@ -149,7 +149,7 @@ def test_file_4() -> None: assert layout.unit == 12.5 -def write_file_5(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_5(buf: IO[bytes]) -> IO[bytes]: ''' File contains no records. 12.5 unit/micron (float64) diff --git a/fatamorgana/test/test_files_layernames.py b/fatamorgana/test/test_files_layernames.py index 94a2cc8..d430aaf 100644 --- a/fatamorgana/test/test_files_layernames.py +++ b/fatamorgana/test/test_files_layernames.py @@ -1,18 +1,19 @@ # type: ignore -from typing import Sequence +from typing import Sequence, IO -from io import BytesIO, BufferedIOBase +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte from ..main import OasisLayout -LAYERS = [(1, 2), (1, 5), (1, 6), (1, 8), - (5, 2), (5, 5), (5, 6), (5, 8), - (6, 2), (6, 5), (6, 6), (6, 8), - (7, 2), (7, 5), (7, 6), (7, 8), - ] +LAYERS = [ + (1, 2), (1, 5), (1, 6), (1, 8), + (5, 2), (5, 5), (5, 6), (5, 8), + (6, 2), (6, 5), (6, 6), (6, 8), + (7, 2), (7, 5), (7, 6), (7, 8), + ] def base_tests(layout: OasisLayout) -> None: assert layout.version.string == '1.0' @@ -30,7 +31,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cells[0].properties -def write_names_geom(buf: BufferedIOBase, short: bool = False) -> BufferedIOBase: +def write_names_geom(buf: IO[bytes], short: bool = False) -> IO[bytes]: write_uint(buf, 11) # LAYERNAME record (geometry) write_bstring(buf, b'AA') # name write_uint(buf, 0) # all layers @@ -96,7 +97,7 @@ def write_names_geom(buf: BufferedIOBase, short: bool = False) -> BufferedIOBase return buf -def write_names_text(buf: BufferedIOBase, prefix: bytes = b'') -> BufferedIOBase: +def write_names_text(buf: IO[bytes], prefix: bytes = b'') -> IO[bytes]: write_uint(buf, 12) # LAYERNAME record (geometry) write_bstring(buf, prefix + b'AA') # name write_uint(buf, 0) # all layers @@ -128,7 +129,7 @@ def write_names_text(buf: BufferedIOBase, prefix: bytes = b'') -> BufferedIOBase write_uint(buf, 0) # all datatypes return buf -def write_geom(buf: BufferedIOBase) -> BufferedIOBase: +def write_geom(buf: IO[bytes]) -> IO[bytes]: for ll, dt in LAYERS: write_uint(buf, 27) # CIRCLE record write_byte(buf, 0b0011_1011) # 00rX_YRDL @@ -140,7 +141,7 @@ def write_geom(buf: BufferedIOBase) -> BufferedIOBase: return buf -def write_text(buf: BufferedIOBase) -> BufferedIOBase: +def write_text(buf: IO[bytes]) -> IO[bytes]: for ll, dt in LAYERS: write_uint(buf, 19) # TEXT record write_byte(buf, 0b0101_1011) # 0CNX_YRTL @@ -205,7 +206,7 @@ def elem_test_text(geometry: Sequence) -> None: assert not gg.properties, msg -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -235,7 +236,7 @@ def test_file_1() -> None: name_test(layout.layers, is_textlayer=False) -def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_2(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -265,7 +266,7 @@ def test_file_2() -> None: name_test(layout.layers, is_textlayer=True) -def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_3(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -281,7 +282,7 @@ def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: return buf -def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_4(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_modals.py b/fatamorgana/test/test_files_modals.py index d2417f2..9eac770 100644 --- a/fatamorgana/test/test_files_modals.py +++ b/fatamorgana/test/test_files_modals.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte @@ -20,7 +20,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_paths.py b/fatamorgana/test/test_files_paths.py index 8fb2cc0..3243a79 100644 --- a/fatamorgana/test/test_files_paths.py +++ b/fatamorgana/test/test_files_paths.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from numpy.testing import assert_equal @@ -26,7 +26,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cells[0].properties -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_placements.py b/fatamorgana/test/test_files_placements.py index 390876e..290ffee 100644 --- a/fatamorgana/test/test_files_placements.py +++ b/fatamorgana/test/test_files_placements.py @@ -1,11 +1,12 @@ # type: ignore -from typing import Tuple -from io import BytesIO, BufferedIOBase +from typing import Tuple, IO, cast, List +from io import BytesIO from numpy.testing import assert_equal from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte, write_float32, write_float64 +from ..records import Rectangle from ..main import OasisLayout @@ -21,7 +22,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_rectangle(buf: BufferedIOBase, pos: Tuple[int, int] = (300, -400)) -> None: +def write_rectangle(buf: IO[bytes], pos: Tuple[int, int] = (300, -400)) -> None: write_uint(buf, 20) # RECTANGLE record write_byte(buf, 0b0111_1011) # SWHX_YRDL write_uint(buf, 1) # layer @@ -32,7 +33,7 @@ def write_rectangle(buf: BufferedIOBase, pos: Tuple[int, int] = (300, -400)) -> write_sint(buf, pos[1]) # geometry-y (absolute) -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -173,7 +174,7 @@ def test_file_1() -> None: assert not layout.cells[1].properties assert not layout.cells[1].geometry - geometry = layout.cells[0].geometry + geometry = cast(List[Rectangle], layout.cells[0].geometry) assert len(geometry) == 1 assert geometry[0].layer == 1 assert geometry[0].datatype == 2 @@ -248,7 +249,7 @@ def test_file_1() -> None: assert placements[12].repetition.b_vector == [-330, 330] -def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' assert variant in (2, 3, 5, 7), 'Error in test definition!' @@ -514,7 +515,7 @@ def common_tests(layout: OasisLayout, variant: int) -> None: assert placements[6].y == 2400 -def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_4(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -593,7 +594,7 @@ def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: return buf -def write_file_6(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_6(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -746,7 +747,7 @@ def test_file_6() -> None: assert pp.y == [0, 1000][ii], msg -def write_file_8(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_8(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -842,7 +843,7 @@ def test_file_8() -> None: assert not layout.cells[2].properties assert not layout.cells[2].placements - geometry = layout.cells[2].geometry + geometry = cast(List[Rectangle], layout.cells[2].geometry) assert len(geometry) == 1 assert geometry[0].layer == 1 assert geometry[0].datatype == 2 diff --git a/fatamorgana/test/test_files_polygons.py b/fatamorgana/test/test_files_polygons.py index 2deb808..f89a019 100644 --- a/fatamorgana/test/test_files_polygons.py +++ b/fatamorgana/test/test_files_polygons.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO import numpy from numpy.testing import assert_equal @@ -106,7 +106,7 @@ def common_tests(layout: OasisLayout) -> None: assert_equal(geometry[ii].point_list, [[0, 150], [50, 0], [0, -50], [50, 0], [0, -100], [-100, 0]], err_msg=msg) -def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' assert variant in (1, 3), 'Error in test!!' @@ -375,7 +375,7 @@ def test_file_1() -> None: assert not gg.properties, f'Fail on polygon {ii}' -def write_file_2(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_2(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_properties.py b/fatamorgana/test/test_files_properties.py index 107b64a..99bdc37 100644 --- a/fatamorgana/test/test_files_properties.py +++ b/fatamorgana/test/test_files_properties.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO import pytest from numpy.testing import assert_equal @@ -23,7 +23,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' include_repetitions = variant in (2, 5) @@ -354,7 +354,7 @@ def test_file_5() -> None: assert gg.repetition.b_vector == [0, 320], msg -def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_3(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -579,7 +579,7 @@ def test_file_3() -> None: assert geometry[ii].properties[0].values[1].string == 'PROP_VALUE2', msg -def write_file_4_6(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_4_6(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' buf.write(HEADER) @@ -927,7 +927,7 @@ def test_file_6() -> None: assert placements[ii].properties[0].values[1].string == 'PROP_VALUE2', msg -def write_file_7_8_9(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_7_8_9(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_rectangles.py b/fatamorgana/test/test_files_rectangles.py index e9f0b99..a7ffdc7 100644 --- a/fatamorgana/test/test_files_rectangles.py +++ b/fatamorgana/test/test_files_rectangles.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte @@ -74,7 +74,7 @@ def base_tests(layout: OasisLayout) -> None: assert geometry[10].repetition.x_displacements == [200, 300] -def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: ''' ''' assert variant in (1, 2), 'Error in test!!' diff --git a/fatamorgana/test/test_files_texts.py b/fatamorgana/test/test_files_texts.py index 0ee22a0..0d10744 100644 --- a/fatamorgana/test/test_files_texts.py +++ b/fatamorgana/test/test_files_texts.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO import pytest @@ -99,7 +99,7 @@ def common_tests(layout: OasisLayout) -> None: assert geometry[19].repetition.y_displacements == [12, -9] -def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase: +def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: ''' Single cell with explicit name 'XYZ' ''' @@ -460,7 +460,7 @@ def test_file_12() -> None: assert layout.textstrings[2].string == 'B' -def write_file_3(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_3(buf: IO[bytes]) -> IO[bytes]: ''' File with one textstring with explicit id, and one with an implicit id. Should fail. @@ -497,7 +497,7 @@ def test_file_3() -> None: layout = OasisLayout.read(buf) -def write_file_4(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_4(buf: IO[bytes]) -> IO[bytes]: ''' File with a TEXT record that references a non-existent TEXTSTRING @@ -537,7 +537,7 @@ def test_file_4() -> None: base_tests(layout) -def write_file_6(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_6(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses an un-filled modal for the repetition ''' @@ -570,7 +570,7 @@ def test_file_6() -> None: layout = OasisLayout.read(buf) -def write_file_7(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_7(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses an un-filled modal for the layer ''' @@ -601,7 +601,7 @@ def test_file_7() -> None: layout = OasisLayout.read(buf) -def write_file_8(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_8(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses an un-filled modal for the datatype ''' @@ -632,7 +632,7 @@ def test_file_8() -> None: layout = OasisLayout.read(buf) -def write_file_9(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_9(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses a default modal for the x coordinate ''' @@ -668,7 +668,7 @@ def test_file_9() -> None: assert text.y == -200 -def write_file_10(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_10(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses a default modal for the y coordinate ''' @@ -704,7 +704,7 @@ def test_file_10() -> None: assert text.x == 100 -def write_file_11(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_11(buf: IO[bytes]) -> IO[bytes]: ''' File with TEXT record that uses an un-filled modal for the text string ''' diff --git a/fatamorgana/test/test_files_trapezoids.py b/fatamorgana/test/test_files_trapezoids.py index 574054d..cea3123 100644 --- a/fatamorgana/test/test_files_trapezoids.py +++ b/fatamorgana/test/test_files_trapezoids.py @@ -1,6 +1,6 @@ # type: ignore - -from io import BytesIO, BufferedIOBase +from typing import IO +from io import BytesIO from .utils import HEADER, FOOTER from ..basic import write_uint, write_sint, write_bstring, write_byte @@ -24,7 +24,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cells[0].properties -def write_file_1(buf: BufferedIOBase) -> BufferedIOBase: +def write_file_1(buf: IO[bytes]) -> IO[bytes]: ''' ''' buf.write(HEADER) From a4c1e52ff806788bbdec311ec79032d268b390ed Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sat, 30 Mar 2024 19:44:47 -0700 Subject: [PATCH 10/40] Modernize type annotations --- README.md | 4 +- fatamorgana/basic.py | 203 +++++----- fatamorgana/main.py | 109 +++--- fatamorgana/records.py | 819 ++++++++++++++++++++--------------------- pyproject.toml | 2 +- 5 files changed, 547 insertions(+), 590 deletions(-) diff --git a/README.md b/README.md index fc5f845..b7aa3d8 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ **fatamorgana** is a Python package for reading and writing OASIS format layout files. **Homepage:** https://mpxd.net/code/jan/fatamorgana +* [PyPI](https://pypi.org/project/fatamorgana) +* [Github mirror](https://github.com/anewusername/fatamorgana) **Capabilities:** * This package is a work-in-progress and is largely untested -- it works for @@ -20,7 +22,7 @@ ## Installation **Dependencies:** -* python 3.5 or newer +* python >=3.10 * (optional) numpy diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 476e5f6..ea96528 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -2,7 +2,7 @@ This module contains all datatypes and parsing/writing functions for all abstractions below the 'record' or 'block' level. """ -from typing import List, Tuple, Type, Union, Optional, Any, Sequence, IO +from typing import Type, Union, Any, Sequence, IO from fractions import Fraction from enum import Enum import math @@ -132,7 +132,7 @@ def write_byte(stream: IO[bytes], n: int) -> int: return stream.write(bytes((n,))) -def _py_read_bool_byte(stream: IO[bytes]) -> List[bool]: +def _py_read_bool_byte(stream: IO[bytes]) -> list[bool]: """ Read a single byte from the stream, and interpret its bits as a list of 8 booleans. @@ -147,7 +147,7 @@ def _py_read_bool_byte(stream: IO[bytes]) -> List[bool]: bits = [bool((byte >> i) & 0x01) for i in reversed(range(8))] return bits -def _py_write_bool_byte(stream: IO[bytes], bits: Tuple[Union[bool, int], ...]) -> int: +def _py_write_bool_byte(stream: IO[bytes], bits: tuple[bool | int, ...]) -> int: """ Pack 8 booleans into a byte, and write it to the stream. @@ -184,7 +184,7 @@ if _USE_NUMPY: byte_arr = _read(stream, 1) return numpy.unpackbits(numpy.frombuffer(byte_arr, dtype=numpy.uint8)) - def _np_write_bool_byte(stream: IO[bytes], bits: Tuple[Union[bool, int], ...]) -> int: + def _np_write_bool_byte(stream: IO[bytes], bits: tuple[Union[bool, int], ...]) -> int: """ Pack 8 booleans into a byte, and write it to the stream. @@ -457,7 +457,7 @@ def write_float64(stream: IO[bytes], f: float) -> int: return stream.write(b) -def read_real(stream: IO[bytes], real_type: Optional[int] = None) -> real_t: +def read_real(stream: IO[bytes], real_type: int | None = None) -> real_t: """ Read a real number from the stream. @@ -783,13 +783,12 @@ def write_astring(stream: IO[bytes], string: str) -> int: class ManhattanDelta: """ Class representing an axis-aligned ("Manhattan") vector. - - Attributes: - vertical (bool): `True` if aligned along y-axis - value (int): signed length of the vector """ vertical: bool + """`True` if aligned along y-axis""" + value: int + """signed length of the vector""" def __init__(self, x: int, y: int) -> None: """ @@ -810,7 +809,7 @@ class ManhattanDelta: self.vertical = True self.value = y - def as_list(self) -> List[int]: + def as_list(self) -> list[int]: """ Return a list representation of this vector. @@ -892,25 +891,26 @@ class ManhattanDelta: class OctangularDelta: """ Class representing an axis-aligned or 45-degree ("Octangular") vector. - - Attributes: - proj_mag (int): projection of the vector onto the x or y axis (non-zero) - octangle (int): bitfield: - bit 2: 1 if non-axis-aligned (non-Manhattan) - if Manhattan: - bit 1: 1 if direction is negative - bit 0: 1 if direction is y - if non-Manhattan: - bit 1: 1 if in lower half-plane - bit 0: 1 if x==-y - - Resulting directions: - 0: +x, 1: +y, 2: -x, 3: -y, - 4: +x+y, 5: -x+y, - 6: +x-y, 7: -x-y """ proj_mag: int + """projection of the vector onto the x or y axis (non-zero)""" + octangle: int + """ + bitfield: + bit 2: 1 if non-axis-aligned (non-Manhattan) + if Manhattan: + bit 1: 1 if direction is negative + bit 0: 1 if direction is y + if non-Manhattan: + bit 1: 1 if in lower half-plane + bit 0: 1 if x==-y + + Resulting directions: + 0: +x, 1: +y, 2: -x, 3: -y, + 4: +x+y, 5: -x+y, + 6: +x-y, 7: -x-y + """ def __init__(self, x: int, y: int) -> None: """ @@ -936,7 +936,7 @@ class OctangularDelta: else: raise InvalidDataError(f'Non-octangular delta! ({x}, {y})') - def as_list(self) -> List[int]: + def as_list(self) -> list[int]: """ Return a list representation of this vector. @@ -1028,13 +1028,12 @@ class OctangularDelta: class Delta: """ Class representing an arbitrary vector - - Attributes - x (int): x-displacement - y (int): y-displacement """ x: int + """x-displacement""" + y: int + """y-displacement""" def __init__(self, x: int, y: int) -> None: """ @@ -1047,7 +1046,7 @@ class Delta: self.x = x self.y = y - def as_list(self) -> List[int]: + def as_list(self) -> list[int]: """ Return a list representation of this vector. @@ -1168,32 +1167,35 @@ class ReuseRepetition: class GridRepetition: """ - Class representing a repetition entry denoting a 1D or 2D array - of regularly-spaced elements. The spacings are stored as one or - two lattice vectors, and the extent of the grid is stored as the - number of elements along each lattice vector. - - Attributes: - a_vector (Tuple[int, int]): `(xa, ya)` vector specifying a center-to-center - displacement between adjacent elements in the grid. - b_vector (Optional[Tuple[int, int]]): `(xb, yb)`, a second displacement, - present if a 2D grid is being specified. - a_count (int): number of elements (>=1) along the grid axis specified by - `a_vector`. - b_count (Optional[int]): Number of elements (>=1) along the grid axis - specified by `b_vector`, if `b_vector` is not `None`. + A repetition entry denoting a 1D or 2D array of regularly-spaced elements. The + spacings are stored as one or two lattice vectors, and the extent of the grid + is stored as the number of elements along each lattice vector. """ - a_vector: List[int] - b_vector: Optional[List[int]] = None + + a_vector: list[int] + """`(xa, ya)` vector specifying a center-to-center + displacement between adjacent elements in the grid. + """ + + b_vector: list[int] | None = None + """`(xb, yb)`, a second displacement, + present if a 2D grid is being specified. + """ + a_count: int - b_count: Optional[int] = None + """number of elements (>=1) along the grid axis specified by `a_vector`.""" + + b_count: int | None = None + """Number of elements (>=1) along the grid axis + specified by `b_vector`, if `b_vector` is not `None`. + """ def __init__( self, a_vector: Sequence[int], a_count: int, - b_vector: Optional[Sequence[int]] = None, - b_count: Optional[int] = None): + b_vector: Sequence[int] | None = None, + b_count: int | None = None): """ Args: a_vector: First lattice vector, of the form `[x, y]`. @@ -1245,8 +1247,8 @@ class GridRepetition: Raises: InvalidDataError: if `repetition_type` is invalid. """ - nb: Optional[int] - b_vector: Optional[List[int]] + nb: int | None + b_vector: list[int] | None if repetition_type == 1: na = read_uint(stream) + 2 nb = read_uint(stream) + 2 @@ -1352,14 +1354,13 @@ class ArbitraryRepetition: """ Class representing a repetition entry denoting a 1D or 2D array of arbitrarily-spaced elements. - - Attributes: - x_displacements (List[int]): x-displacements between consecutive elements - y_displacements (List[int]): y-displacements between consecutive elements """ - x_displacements: List[int] - y_displacements: List[int] + x_displacements: list[int] + """x-displacements between consecutive elements""" + + y_displacements: list[int] + """y-displacements between consecutive elements""" def __init__( self, @@ -1443,7 +1444,7 @@ class ArbitraryRepetition: Returns: Number of bytes written. """ - def get_gcd(vals: List[int]) -> int: + def get_gcd(vals: list[int]) -> int: """ Get the greatest common denominator of a list of ints. """ @@ -1506,7 +1507,7 @@ class ArbitraryRepetition: def read_point_list( stream: IO[bytes], implicit_closed: bool, - ) -> List[List[int]]: + ) -> Sequence[Sequence[int]]: """ Read a point list from a stream. @@ -1594,7 +1595,7 @@ def read_point_list( def write_point_list( stream: IO[bytes], - points: List[Sequence[int]], + points: list[Sequence[int]], fast: bool = False, implicit_closed: bool = True ) -> int: @@ -1655,7 +1656,7 @@ def write_point_list( return size # Try writing a bunch of Manhattan or Octangular deltas - deltas: Union[List[ManhattanDelta], List[OctangularDelta], List[Delta]] + deltas: list[ManhattanDelta] | list[OctangularDelta] | list[Delta] list_type = None try: deltas = [ManhattanDelta(x, y) for x, y in points] @@ -1717,13 +1718,12 @@ def write_point_list( class PropStringReference: """ Reference to a property string. - - Attributes: - ref (int): ID of the target - ref_type (Type): Type of the target: `bytes`, `NString`, or `AString` """ ref: int + """ID of the target""" + reference_type: Type + """Type of the target: `bytes`, `NString`, or `AString`""" def __init__(self, ref: int, ref_type: Type) -> None: """ @@ -1854,7 +1854,7 @@ def write_property_value( return size -def read_interval(stream: IO[bytes]) -> Tuple[Optional[int], Optional[int]]: +def read_interval(stream: IO[bytes]) -> tuple[int | None, int | None]: """ Read an interval from a stream. These are used for storing layer info. @@ -1896,8 +1896,8 @@ def read_interval(stream: IO[bytes]) -> Tuple[Optional[int], Optional[int]]: def write_interval( stream: IO[bytes], - min_bound: Optional[int] = None, - max_bound: Optional[int] = None, + min_bound: int | None = None, + max_bound: int | None = None, ) -> int: """ Write an interval to a stream. @@ -1931,23 +1931,24 @@ def write_interval( class OffsetEntry: """ Entry for the file's offset table. - - Attributes: - strict (bool): If `False`, the records pointed to by this - offset entry may also appear elsewhere in the file. If `True`, all - records of the type pointed to by this offset entry must be present - in a contiuous block at the specified offset [pad records also allowed]. - Additionally: - - All references to strict-mode records must be - explicit (using reference_number). - - The offset may point to an encapsulating CBlock record, if the first - record in that CBlock is of the target record type. A strict modei - table cannot begin in the middle of a CBlock. - offset (int): offset from the start of the file; may be 0 - for records that are not present. """ + strict: bool = False + """ + If `False`, the records pointed to by this offset entry may also appear + elsewhere in the file. If `True`, all records of the type pointed to by + this offset entry must be present in a contiuous block at the specified + offset [pad records also allowed]. + Additionally: + - All references to strict-mode records must be explicit (using + `reference_number`). + - The offset may point to an encapsulating CBlock record, if the first + record in that CBlock is of the target record type. A strict mode + table cannot begin in the middle of a CBlock. + """ + offset: int = 0 + """offset from the start of the file; 0 for records that are not present.""" def __init__(self, strict: bool = False, offset: int = 0) -> None: """ @@ -2006,14 +2007,6 @@ class OffsetTable: XName which are stored in the above order in the file's offset table. - - Attributes: - cellnames (OffsetEntry): Offset for CellNames - textstrings (OffsetEntry): Offset for TextStrings - propnames (OffsetEntry): Offset for PropNames - propstrings (OffsetEntry): Offset for PropStrings - layernames (OffsetEntry): Offset for LayerNames - xnames (OffsetEntry): Offset for XNames """ cellnames: OffsetEntry textstrings: OffsetEntry @@ -2024,12 +2017,12 @@ class OffsetTable: def __init__( self, - cellnames: Optional[OffsetEntry] = None, - textstrings: Optional[OffsetEntry] = None, - propnames: Optional[OffsetEntry] = None, - propstrings: Optional[OffsetEntry] = None, - layernames: Optional[OffsetEntry] = None, - xnames: Optional[OffsetEntry] = None, + cellnames: OffsetEntry | None = None, + textstrings: OffsetEntry | None = None, + propnames: OffsetEntry | None = None, + propstrings: OffsetEntry | None = None, + layernames: OffsetEntry | None = None, + xnames: OffsetEntry | None = None, ) -> None: """ All parameters default to a non-strict entry with offset `0`. @@ -2149,14 +2142,18 @@ class Validation: The checksum is calculated using the entire file, excluding the final 4 bytes (the value of the checksum itself). - Attributes: - checksum_type (int): `0` for no checksum, `1` for crc32, `2` for checksum32 - checksum (Optional[int]): value of the checksum """ checksum_type: int - checksum: Optional[int] = None + """ + `0` for no checksum, + `1` for crc32, + `2` for checksum32, + """ - def __init__(self, checksum_type: int, checksum: Optional[int] = None) -> None: + checksum: int | None = None + """value of the checksum""" + + def __init__(self, checksum_type: int, checksum: int | None = None) -> None: """ Args: checksum_type: 0,1,2 (No checksum, crc32, checksum32) diff --git a/fatamorgana/main.py b/fatamorgana/main.py index 8748d7f..1bb7258 100644 --- a/fatamorgana/main.py +++ b/fatamorgana/main.py @@ -3,7 +3,7 @@ This module contains data structures and functions for reading from and writing to whole OASIS layout files, and provides a few additional abstractions for the data contained inside them. """ -from typing import List, Dict, Union, Optional, Type, IO +from typing import Type, IO import io import logging @@ -27,20 +27,20 @@ class FileModals: """ File-scoped modal variables """ - cellname_implicit: Optional[bool] = None - propname_implicit: Optional[bool] = None - xname_implicit: Optional[bool] = None - textstring_implicit: Optional[bool] = None - propstring_implicit: Optional[bool] = None + cellname_implicit: bool | None = None + propname_implicit: bool | None = None + xname_implicit: bool | None = None + textstring_implicit: bool | None = None + propstring_implicit: bool | None = None - property_target: List[records.Property] + property_target: list[records.Property] within_cell: bool = False within_cblock: bool = False end_has_offset_table: bool = False started: bool = False - def __init__(self, property_target: List[records.Property]) -> None: + def __init__(self, property_target: list[records.Property]) -> None: self.property_target = property_target @@ -53,46 +53,48 @@ class OasisLayout: record objects. Cells are stored using `Cell` objects (different from `records.Cell` record objects). - - Attributes: - (File properties) - version (AString): Version string ('1.0') - unit (real_t): grid steps per micron - validation (Validation): checksum data - - (Names) - cellnames (Dict[int, CellName]): Cell names - propnames (Dict[int, NString]): Property names - xnames (Dict[int, XName]): Custom names - - (Strings) - textstrings (Dict[int, AString]): Text strings - propstrings (Dict[int, AString]): Property strings - - (Data) - layers (List[records.LayerName]): Layer definitions - properties (List[records.Property]): Property values - cells (List[Cell]): Layout cells """ + # File properties version: AString + """File format version string ('1.0')""" + unit: real_t + """grid steps per micron""" + validation: Validation + """checksum data""" - properties: List[records.Property] - cells: List['Cell'] + # Data + properties: list[records.Property] + """Property values""" - cellnames: Dict[int, 'CellName'] - propnames: Dict[int, NString] - xnames: Dict[int, 'XName'] + cells: list['Cell'] + """Layout cells""" - textstrings: Dict[int, AString] - propstrings: Dict[int, AString] - layers: List[records.LayerName] + layers: list[records.LayerName] + """Layer definitions""" + + # Names + cellnames: dict[int, 'CellName'] + """Cell names""" + + propnames: dict[int, NString] + """Property names""" + + xnames: dict[int, 'XName'] + """Custom names""" + + # String storage + textstrings: dict[int, AString] + """Text strings""" + + propstrings: dict[int, AString] + """Property strings""" def __init__( self, unit: real_t, - validation: Optional[Validation] = None, + validation: Validation | None = None, ) -> None: """ Args: @@ -404,26 +406,21 @@ class OasisLayout: class Cell: """ Representation of an OASIS cell. - - Attributes: - name (Union[NString, int]): name or "CellName reference" number - - properties (List[records.Property]): Properties of this cell - placements (List[records.Placement]): Placement record objects - geometry: (List[records.geometry_t]): Geometry record objectes """ - name: Union[NString, int] - properties: List[records.Property] - placements: List[records.Placement] - geometry: List[records.geometry_t] + name: NString | int + """name or "CellName reference" number""" + + properties: list[records.Property] + placements: list[records.Placement] + geometry: list[records.geometry_t] def __init__( self, - name: Union[NString, str, int], + name: NString | str | int, *, - properties: Optional[List[records.Property]] = None, - placements: Optional[List[records.Placement]] = None, - geometry: Optional[List[records.geometry_t]] = None, + properties: list[records.Property] | None = None, + placements: list[records.Placement] | None = None, + geometry: list[records.geometry_t] | None = None, ) -> None: self.name = name if isinstance(name, (NString, int)) else NString(name) self.properties = [] if properties is None else properties @@ -464,12 +461,12 @@ class CellName: with the reference data stripped out. """ nstring: NString - properties: List[records.Property] + properties: list[records.Property] def __init__( self, - nstring: Union[NString, str], - properties: Optional[List[records.Property]] = None, + nstring: NString | str, + properties: list[records.Property] | None = None, ) -> None: """ Args: @@ -531,7 +528,7 @@ class XName: # Mapping from record id to record class. -_GEOMETRY: Dict[int, Type[records.geometry_t]] = { +_GEOMETRY: dict[int, Type[records.geometry_t]] = { 19: records.Text, 20: records.Rectangle, 21: records.Polygon, diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 46beb48..3650262 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -10,7 +10,7 @@ Higher-level code (e.g. monitoring for combinations of records with parse, or code for dealing with nested records in a CBlock) should live in main.py instead. """ -from typing import List, Dict, Tuple, Union, Optional, Sequence, Any, TypeVar, IO +from typing import Union, Sequence, Any, TypeVar, IO from abc import ABCMeta, abstractmethod import copy import math @@ -40,7 +40,7 @@ logger = logging.getLogger(__name__) ''' geometry_t = Union['Text', 'Rectangle', 'Polygon', 'Path', 'Trapezoid', 'CTrapezoid', 'Circle', 'XElement', 'XGeometry'] -pathextension_t = Tuple['PathExtensionScheme', Optional[int]] +pathextension_t = tuple['PathExtensionScheme', int | None] point_list_t = Sequence[Sequence[int]] @@ -49,32 +49,32 @@ class Modals: Modal variables, used to store data about previously-written or -read records. """ - repetition: Optional[repetition_t] = None + repetition: repetition_t | None = None placement_x: int = 0 placement_y: int = 0 - placement_cell: Optional[NString] = None - layer: Optional[int] = None - datatype: Optional[int] = None - text_layer: Optional[int] = None - text_datatype: Optional[int] = None + placement_cell: NString | None = None + layer: int | None = None + datatype: int | None = None + text_layer: int | None = None + text_datatype: int | None = None text_x: int = 0 text_y: int = 0 - text_string: Union[AString, int, None] = None + text_string: AString | int | None = None geometry_x: int = 0 geometry_y: int = 0 xy_relative: bool = False - geometry_w: Optional[int] = None - geometry_h: Optional[int] = None - polygon_point_list: Optional[point_list_t] = None - path_half_width: Optional[int] = None - path_point_list: Optional[point_list_t] = None - path_extension_start: Optional[pathextension_t] = None - path_extension_end: Optional[pathextension_t] = None - ctrapezoid_type: Optional[int] = None - circle_radius: Optional[int] = None - property_value_list: Optional[Sequence[property_value_t]] = None - property_name: Union[int, NString, None] = None - property_is_standard: Optional[bool] = None + geometry_w: int | None = None + geometry_h: int | None = None + polygon_point_list: point_list_t | None = None + path_half_width: int | None = None + path_point_list: point_list_t | None = None + path_extension_start: pathextension_t | None = None + path_extension_end: pathextension_t | None = None + ctrapezoid_type: int | None = None + circle_radius: int | None = None + property_value_list: Sequence[property_value_t] | None = None + property_name: int | NString | None = None + property_is_standard: bool | None = None def __init__(self) -> None: self.reset() @@ -116,17 +116,17 @@ class Modals: T = TypeVar('T') -def verify_modal(var: Optional[T]) -> T: +def verify_modal(var: T | None) -> T: if var is None: raise UnfilledModalError return var -''' - - Records - -''' +# +# +# Records +# +# class Record(metaclass=ABCMeta): """ @@ -231,10 +231,10 @@ class GeometryMixin(metaclass=ABCMeta): """ Mixin defining common functions for geometry records """ - x: Optional[int] - y: Optional[int] - layer: Optional[int] - datatype: Optional[int] + x: int | None + y: int | None + layer: int | None + datatype: int | None def get_x(self) -> int: return verify_modal(self.x) @@ -242,7 +242,7 @@ class GeometryMixin(metaclass=ABCMeta): def get_y(self) -> int: return verify_modal(self.y) - def get_xy(self) -> Tuple[int, int]: + def get_xy(self) -> tuple[int, int]: return (self.get_x(), self.get_y()) def get_layer(self) -> int: @@ -251,15 +251,15 @@ class GeometryMixin(metaclass=ABCMeta): def get_datatype(self) -> int: return verify_modal(self.datatype) - def get_layer_tuple(self) -> Tuple[int, int]: + def get_layer_tuple(self) -> tuple[int, int]: return (self.get_layer(), self.get_datatype()) def read_refname( stream: IO[bytes], - is_present: Union[bool, int], - is_reference: Union[bool, int] - ) -> Union[None, int, NString]: + is_present: bool | int, + is_reference: bool | int, + ) -> int | NString | None: """ Helper function for reading a possibly-absent, possibly-referenced NString. @@ -282,9 +282,9 @@ def read_refname( def read_refstring( stream: IO[bytes], - is_present: Union[bool, int], - is_reference: Union[bool, int], - ) -> Union[None, int, AString]: + is_present: bool | int, + is_reference: bool | int, + ) -> int | AString | None: """ Helper function for reading a possibly-absent, possibly-referenced `AString`. @@ -369,22 +369,21 @@ class XYMode(Record): class Start(Record): """ Start Record (ID 1) - - Attributes: - version (AString): - unit (real_t): positive real number, grid steps per micron - offset_table (Optional[OffsetTable]): If `None` then table must be - placed in the `End` record) """ version: AString + """File format version string""" + unit: real_t - offset_table: Optional[OffsetTable] + """positive real number, grid steps per micron""" + + offset_table: OffsetTable | None + """If `None` then table must be placed in the `End` record""" def __init__( self, unit: real_t, - version: Union[AString, str] = "1.0", - offset_table: Optional[OffsetTable] = None, + version: AString | str = "1.0", + offset_table: OffsetTable | None = None, ) -> None: """ Args @@ -423,7 +422,7 @@ class Start(Record): version = AString.read(stream) unit = read_real(stream) has_offset_table = read_uint(stream) == 0 - offset_table: Optional[OffsetTable] + offset_table: OffsetTable | None if has_offset_table: offset_table = OffsetTable.read(stream) else: @@ -447,19 +446,17 @@ class End(Record): End record (ID 2) The end record is always padded to a total length of 256 bytes. - - Attributes: - offset_table (Optional[OffsetTable]): `None` if offset table was - written into the `Start` record instead - validation (Validation): object containing checksum """ - offset_table: Optional[OffsetTable] + offset_table: OffsetTable | None + """`None` if offset table was written into the `Start` record instead""" + validation: Validation + """object containing checksum""" def __init__( self, validation: Validation, - offset_table: Optional[OffsetTable] = None, + offset_table: OffsetTable | None = None, ) -> None: """ Args: @@ -485,7 +482,7 @@ class End(Record): if record_id != 2: raise InvalidDataError(f'Invalid record id for End {record_id}') if has_offset_table: - offset_table: Optional[OffsetTable] = OffsetTable.read(stream) + offset_table: OffsetTable | None = OffsetTable.read(stream) else: offset_table = None _padding_string = read_bstring(stream) # noqa @@ -514,15 +511,15 @@ class End(Record): class CBlock(Record): """ CBlock (Compressed Block) record (ID 34) - - Attributes: - compression_type (int): `0` for zlib - decompressed_byte_count (int): size after decompressing - compressed_bytes (bytes): compressed data """ compression_type: int + """ `0` for zlib""" + decompressed_byte_count: int + """size after decompressing""" + compressed_bytes: bytes + """compressed data""" def __init__( self, @@ -571,7 +568,7 @@ class CBlock(Record): def from_decompressed( decompressed_bytes: bytes, compression_type: int = 0, - compression_args: Optional[Dict[str, Any]] = None, + compression_args: dict[str, Any] | None = None, ) -> 'CBlock': """ Create a CBlock record from uncompressed data. @@ -600,7 +597,7 @@ class CBlock(Record): return CBlock(compression_type, count, compressed_bytes) - def decompress(self, decompression_args: Optional[Dict[str, Any]] = None) -> bytes: + def decompress(self, decompression_args: dict[str, Any] | None = None) -> bytes: """ Decompress the contents of this CBlock. @@ -630,18 +627,17 @@ class CBlock(Record): class CellName(Record): """ CellName record (ID 3, 4) - - Attributes: - nstring (NString): name - reference_number (Optional[int]): `None` results in implicit assignment """ nstring: NString - reference_number: Optional[int] + """name string""" + + reference_number: int | None + """`None` results in implicit assignment""" def __init__( self, - nstring: Union[NString, str], - reference_number: Optional[int] = None, + nstring: str | NString, + reference_number: int | None = None, ) -> None: """ Args: @@ -667,7 +663,7 @@ class CellName(Record): raise InvalidDataError(f'Invalid record id for CellName {record_id}') nstring = NString.read(stream) if record_id == 4: - reference_number: Optional[int] = read_uint(stream) + reference_number: int | None = read_uint(stream) else: reference_number = None record = CellName(nstring, reference_number) @@ -685,18 +681,17 @@ class CellName(Record): class PropName(Record): """ PropName record (ID 7, 8) - - Attributes: - nstring (NString): name - reference_number (Optional[int]): `None` results in implicit assignment """ nstring: NString - reference_number: Optional[int] = None + """name string""" + + reference_number: int | None = None + """`None` results in implicit assignment""" def __init__( self, - nstring: Union[NString, str], - reference_number: Optional[int] = None, + nstring: str | NString, + reference_number: int | None = None, ) -> None: """ Args: @@ -722,7 +717,7 @@ class PropName(Record): raise InvalidDataError(f'Invalid record id for PropName {record_id}') nstring = NString.read(stream) if record_id == 8: - reference_number: Optional[int] = read_uint(stream) + reference_number: int | None = read_uint(stream) else: reference_number = None record = PropName(nstring, reference_number) @@ -741,18 +736,17 @@ class PropName(Record): class TextString(Record): """ TextString record (ID 5, 6) - - Attributes: - astring (AString): string data - reference_number (Optional[int]): `None` results in implicit assignment """ astring: AString - reference_number: Optional[int] = None + """string contents""" + + reference_number: int | None = None + """`None` results in implicit assignment""" def __init__( self, - string: Union[AString, str], - reference_number: Optional[int] = None, + string: AString | str, + reference_number: int | None = None, ) -> None: """ Args: @@ -778,7 +772,7 @@ class TextString(Record): raise InvalidDataError(f'Invalid record id for TextString: {record_id}') astring = AString.read(stream) if record_id == 6: - reference_number: Optional[int] = read_uint(stream) + reference_number: int | None = read_uint(stream) else: reference_number = None record = TextString(astring, reference_number) @@ -797,18 +791,17 @@ class TextString(Record): class PropString(Record): """ PropString record (ID 9, 10) - - Attributes: - astring (AString): string data - reference_number (Optional[int]): `None` results in implicit assignment """ astring: AString - reference_number: Optional[int] + """string contents""" + + reference_number: int | None + """`None` results in implicit assignment""" def __init__( self, - string: Union[AString, str], - reference_number: Optional[int] = None, + string: AString | str, + reference_number: int | None = None, ) -> None: """ Args: @@ -834,7 +827,7 @@ class PropString(Record): raise InvalidDataError(f'Invalid record id for PropString: {record_id}') astring = AString.read(stream) if record_id == 10: - reference_number: Optional[int] = read_uint(stream) + reference_number: int | None = read_uint(stream) else: reference_number = None record = PropString(astring, reference_number) @@ -853,32 +846,31 @@ class PropString(Record): class LayerName(Record): """ LayerName record (ID 11, 12) - - Attributes: - nstring (NString): name - layer_interval (Tuple[Optional[int], Optional[int]]): bounds on the interval - type_interval (Tuple[Optional[int], Optional[int]]): bounds on the interval - is_textlayer (bool): Is this a text layer? """ nstring: NString - layer_interval: Tuple[Optional[int], Optional[int]] - type_interval: Tuple[Optional[int], Optional[int]] + """name string""" + + layer_interval: tuple[int | None, int | None] + """bounds on the interval""" + + type_interval: tuple[int | None, int | None] + """bounds on the interval""" + is_textlayer: bool + """Is this a text layer?""" def __init__( self, - nstring: Union[NString, str], - layer_interval: Tuple[Optional[int], Optional[int]], - type_interval: Tuple[Optional[int], Optional[int]], + nstring: str | NString, + layer_interval: tuple[int | None, int | None], + type_interval: tuple[int | None, int | None], is_textlayer: bool, ) -> None: """ Args: nstring: The layer name. - layer_interval: Tuple (int or None, int or None) giving bounds - (or lack of thereof) on the layer number. - type_interval: Tuple (int or None, int or None) giving bounds - (or lack of thereof) on the type number. + layer_interval: Tuple giving bounds (or lack of thereof) on the layer number. + type_interval: Tuple giving bounds (or lack of thereof) on the type number. is_textlayer: `True` if the layer is a text layer. """ if isinstance(nstring, NString): @@ -919,22 +911,18 @@ class LayerName(Record): class Property(Record): """ LayerName record (ID 28, 29) - - Attributes: - name (Union[NString, int, None]): `int` is an explicit reference, - `None` is a flag to use Modal) - values (Optional[List[property_value_t]]): List of property values. - is_standard (bool): Whether this is a standard property. """ - name: Optional[Union[NString, int]] - values: Optional[List[property_value_t]] - is_standard: Optional[bool] + name: NString | int | None + """`int` is an explicit reference, `None` is a flag to use Modal""" + values: list[property_value_t] | None + is_standard: bool | None + """Whether this is a standard property.""" def __init__( self, - name: Union[NString, str, int, None] = None, - values: Optional[List[property_value_t]] = None, - is_standard: Optional[bool] = None, + name: NString | str | int | None = None, + values: list[property_value_t] | None= None, + is_standard: bool | None = None, ) -> None: """ Args: @@ -952,10 +940,10 @@ class Property(Record): self.values = values self.is_standard = is_standard - def get_name(self) -> Union[NString, int]: + def get_name(self) -> NString | int: return verify_modal(self.name) # type: ignore - def get_values(self) -> List[property_value_t]: + def get_values(self) -> list[property_value_t]: return verify_modal(self.values) def get_is_standard(self) -> bool: @@ -992,8 +980,8 @@ class Property(Record): value_count = u else: value_count = read_uint(stream) - values: Optional[List[property_value_t]] = [read_property_value(stream) - for _ in range(value_count)] + values: list[property_value_t] | None = [read_property_value(stream) + for _ in range(value_count)] else: values = None # if u != 0: @@ -1041,21 +1029,21 @@ class Property(Record): class XName(Record): """ XName record (ID 30, 31) - - Attributes: - attribute (int): Attribute number - bstring (bytes): XName data - reference_number (Optional[int]): None means to use implicit numbering """ attribute: int + """Attribute number""" + bstring: bytes - reference_number: Optional[int] + """XName data""" + + reference_number: int | None + """None means to use implicit numbering""" def __init__( self, attribute: int, bstring: bytes, - reference_number: Optional[int] = None, + reference_number: int | None = None, ) -> None: """ Args: @@ -1081,7 +1069,7 @@ class XName(Record): attribute = read_uint(stream) bstring = read_bstring(stream) if record_id == 31: - reference_number: Optional[int] = read_uint(stream) + reference_number: int | None = read_uint(stream) else: reference_number = None record = XName(attribute, bstring, reference_number) @@ -1101,20 +1089,20 @@ class XName(Record): class XElement(Record): """ XElement record (ID 32) - - Attributes: - attribute (int): Attribute number. - bstring (bytes): XElement data. """ attribute: int + """Attribute number""" + bstring: bytes - properties: List['Property'] + """XElement data""" + + properties: list['Property'] def __init__( self, attribute: int, bstring: bytes, - properties: Optional[List['Property']] = None, + properties: list['Property'] | None = None, ) -> None: """ Args: @@ -1152,36 +1140,30 @@ class XElement(Record): class XGeometry(Record, GeometryMixin): """ XGeometry record (ID 33) - - Attributes: - attribute (int): Attribute number. - bstring (bytes): XGeometry data. - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): None means reuse modal - y (Optional[int]): None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ attribute: int + """Attribute number""" + bstring: bytes - layer: Optional[int] = None - datatype: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - properties: List['Property'] + """XGeometry data""" + + layer: int | None = None + datatype: int | None = None + x: int | None = None + y: int | None = None + repetition: repetition_t | None = None + properties: list['Property'] def __init__( self, attribute: int, bstring: bytes, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + layer: int | None = None, + datatype: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Args: @@ -1224,7 +1206,7 @@ class XGeometry(Record, GeometryMixin): if z0 or z1 or z2: raise InvalidDataError('Malformed XGeometry header') attribute = read_uint(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -1268,13 +1250,11 @@ class XGeometry(Record, GeometryMixin): class Cell(Record): """ Cell record (ID 13, 14) - - Attributes: - name (Union[int, NString]): int specifies "CellName reference" number """ - name: Union[int, NString] + name: int | NString + """int specifies "CellName reference" number""" - def __init__(self, name: Union[int, str, NString]) -> None: + def __init__(self, name: int | str | NString) -> None: """ Args: name: `NString`, or an int specifying a `CellName` reference number. @@ -1289,7 +1269,7 @@ class Cell(Record): @staticmethod def read(stream: IO[bytes], record_id: int) -> 'Cell': - name: Union[int, NString] + name: int | NString if record_id == 13: name = read_uint(stream) elif record_id == 14: @@ -1314,37 +1294,34 @@ class Cell(Record): class Placement(Record): """ Placement record (ID 17, 18) - - Attributes: - name (Union[NString, int, None]): name, "CellName reference" - number, or reuse modal - magnification (real_t): Magnification factor - angle (real_t): Rotation, degrees counterclockwise - x (Optional[int]): x-offset, None means reuse modal - y (Optional[int]): y-offset, None means reuse modal - repetition (repetition_t or None): Repetition, if any - flip (bool): Whether to perform reflection about the x-axis. - properties (List[Property]): List of property records associate with this record. """ - name: Union[NString, int, None] = None - magnification: Optional[real_t] = None - angle: Optional[real_t] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None + name: int | NString | None = None + """name, "CellName reference" number, or reuse modal""" + + magnification: real_t | None = None + """magnification factor""" + + angle: real_t | None = None + """Rotation, degrees counterclockwise""" + + x: int | None = None + y: int | None = None + repetition: repetition_t | None = None flip: bool - properties: List['Property'] + """Whether to perform reflection about the x-axis""" + + properties: list['Property'] def __init__( self, flip: bool, - name: Union[NString, str, int, None] = None, - magnification: Optional[real_t] = None, - angle: Optional[real_t] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + name: NString | str | int | None = None, + magnification: real_t | None = None, + angle: real_t | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Args: @@ -1371,7 +1348,7 @@ class Placement(Record): self.name = NString(name) self.properties = [] if properties is None else properties - def get_name(self) -> Union[NString, int]: + def get_name(self) -> NString | int: return verify_modal(self.name) # type: ignore def get_x(self) -> int: @@ -1398,7 +1375,7 @@ class Placement(Record): #CNXYRAAF (17) or CNXYRMAF (18) c, n, x, y, r, ma0, ma1, flip = read_bool_byte(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} name = read_refname(stream, c, n) if record_id == 17: aa = (ma0 << 1) | ma1 @@ -1466,33 +1443,24 @@ class Placement(Record): class Text(Record, GeometryMixin): """ Text record (ID 19) - - Attributes: - string (Union[AString, int, None]): None means reuse modal - layer (Optiona[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset, None means reuse modal - y (Optional[int]): y-offset, None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ - string: Optional[Union[AString, int]] = None - layer: Optional[int] = None - datatype: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - properties: List['Property'] + string: AString | int | None = None + layer: int | None = None + datatype: int | None = None + x: int | None = None + y: int | None = None + repetition: repetition_t | None = None + properties: list['Property'] def __init__( self, - string: Union[AString, str, int, None] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + string: AString | str | int | None = None, + layer: int | None = None, + datatype: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Args: @@ -1516,7 +1484,7 @@ class Text(Record, GeometryMixin): self.string = AString(string) self.properties = [] if properties is None else properties - def get_string(self) -> Union[AString, int]: + def get_string(self) -> AString | int: return verify_modal(self.string) # type: ignore def merge_with_modals(self, modals: Modals) -> None: @@ -1542,7 +1510,7 @@ class Text(Record, GeometryMixin): if z0: raise InvalidDataError('Malformed Text header') - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} string = read_refstring(stream, c, n) if l: optional['layer'] = read_uint(stream) @@ -1593,43 +1561,43 @@ class Rectangle(Record, GeometryMixin): Rectangle record (ID 20) (x, y) denotes the lower-left (min-x, min-y) corner of the rectangle. - - Attributes: - is_square (bool): `True` if this is a square. - If `True`, `height` must be `None`. - width (Optional[int]): X-width. `None` means reuse modal. - height (Optional[int]): Y-height. Must be `None` if `is_square` is `True`. - If `is_square` is `False`, `None` means reuse modal. - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset of the rectangle's lower-left (min-x) point. - None means reuse modal. - y (Optional[int]): y-offset of the rectangle's lower-left (min-y) point. - None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any. - properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] - datatype: Optional[int] - width: Optional[int] - height: Optional[int] - x: Optional[int] - y: Optional[int] - repetition: Optional[repetition_t] + layer: int | None + datatype: int | None + width: int | None + """X-width. `None` means reuse modal""" + + height: int | None + """Y-height. Must be `None` if `is_square` is `True`. + If `is_square` is `False`, `None` means reuse modal + """ + + x: int | None + """x-offset of the rectangle's lower-left (min-x) point. + None means reuse modal. + """ + y: int | None + """y-offset of the rectangle's lower-left (min-y) point. + None means reuse modal + """ + + repetition: repetition_t | None is_square: bool - properties: List['Property'] + """If `True`, `height` must be `None`""" + + properties: list['Property'] def __init__( self, is_square: bool = False, - layer: Optional[int] = None, - datatype: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + layer: int | None = None, + datatype: int | None = None, + width: int | None = None, + height: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: self.is_square = is_square self.layer = layer @@ -1679,7 +1647,7 @@ class Rectangle(Record, GeometryMixin): raise InvalidDataError(f'Invalid record id for Rectangle: {record_id}') is_square, w, h, x, y, r, d, l = read_bool_byte(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -1730,42 +1698,38 @@ class Rectangle(Record, GeometryMixin): class Polygon(Record, GeometryMixin): """ Polygon record (ID 21) - - Attributes: - point_list (Optional[point_list_t]): List of offsets from the - initial vertex (x, y) to the remaining vertices, - `[[dx0, dy0], [dx1, dy1], ...]`. - The list is an implicitly closed path, vertices are [int, int], - The initial vertex is located at (x, y) and is not represented - in `point_list`. - `None` means reuse modal. - layer (Optional[int]): Layer number. None means reuse modal - datatype (Optional[int]): Datatype number. None means reuse modal - x (Optional[int]): x-offset of the polygon's first point. - None means reuse modal - y (Optional[int]): y-offset of the polygon's first point. - None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any. - Default no repetition. - properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] - datatype: Optional[int] - x: Optional[int] - y: Optional[int] - repetition: Optional[repetition_t] - point_list: Optional[point_list_t] - properties: List['Property'] + layer: int | None + datatype: int | None + x: int | None + """x-offset of the polygon's first point. + None means reuse modal + """ + y: int | None + """y-offset of the polygon's first point. + None means reuse modal + """ + repetition: repetition_t | None + point_list: point_list_t | None + """ + List of offsets from the initial vertex (x, y) to the remaining + vertices, `[[dx0, dy0], [dx1, dy1], ...]`. + The list is an implicitly closed path, vertices are [int, int]. + The initial vertex is located at (x, y) and is not represented in `point_list`. + `None` means reuse modal. + """ + + properties: list['Property'] def __init__( self, - point_list: Optional[point_list_t] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + point_list: point_list_t | None = None, + layer: int | None = None, + datatype: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: self.layer = layer self.datatype = datatype @@ -1805,7 +1769,7 @@ class Polygon(Record, GeometryMixin): if z0 or z1: raise InvalidDataError('Invalid polygon header') - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -1851,51 +1815,50 @@ class Polygon(Record, GeometryMixin): class Path(Record, GeometryMixin): """ Polygon record (ID 22) - - Attributes: - point_list (Optional[point_list_t]): List of offsets from the - initial vertex (x, y) to the remaining vertices, - `[[dx0, dy0], [dx1, dy1], ...]`. - The initial vertex is located at (x, y) and is not represented - in `point_list`. - Offsets are [int, int]; `None` means reuse modal. - half_width (Optional[int]): None means reuse modal - extension_start (Optional[Tuple]): None means reuse modal. - Tuple is of the form (`PathExtensionScheme`, Optional[int]) - Second value is None unless using `PathExtensionScheme.Arbitrary` - Value determines extension past start point. - extension_end (Optional[Tuple]): Same form as `extension_end`. - Value determines extension past end point. - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset, None means reuse modal - y (Optional[int]): y-offset, None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] = None - datatype: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - point_list: Optional[point_list_t] = None - half_width: Optional[int] = None - extension_start: Optional[pathextension_t] = None - extension_end: Optional[pathextension_t] = None - properties: List['Property'] + layer: int | None = None + datatype: int | None = None + x: int | None = None + y: int | None = None + repetition: repetition_t | None = None + point_list: point_list_t | None = None + """ + List of offsets from the initial vertex (x, y) to the remaining vertices, + `[[dx0, dy0], [dx1, dy1], ...]`. + The initial vertex is located at (x, y) and is not represented in `point_list`. + Offsets are [int, int]; `None` means reuse modal. + """ + + half_width: int | None = None + """None means reuse modal""" + + extension_start: pathextension_t | None = None + """ + `None` means reuse modal. + Tuple is of the form (`PathExtensionScheme`, int | None) + Second value is None unless using `PathExtensionScheme.Arbitrary` + Value determines extension past start point. + """ + + extension_end: pathextension_t | None = None + """ + Same form as `extension_end`. Value determines extension past end point. + """ + + properties: list['Property'] def __init__( self, - point_list: Optional[point_list_t] = None, - half_width: Optional[int] = None, - extension_start: Optional[pathextension_t] = None, - extension_end: Optional[pathextension_t] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + point_list: point_list_t | None = None, + half_width: int | None = None, + extension_start: pathextension_t | None = None, + extension_end: pathextension_t | None = None, + layer: int | None = None, + datatype: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: self.layer = layer self.datatype = datatype @@ -1946,7 +1909,7 @@ class Path(Record, GeometryMixin): raise InvalidDataError(f'Invalid record id for Path: {record_id}') e, w, p, x, y, r, d, l = read_bool_byte(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -1958,7 +1921,7 @@ class Path(Record, GeometryMixin): scheme_end = scheme & 0b11 scheme_start = (scheme >> 2) & 0b11 - def get_pathext(ext_scheme: int) -> Optional[pathextension_t]: + def get_pathext(ext_scheme: int) -> pathextension_t | None: if ext_scheme == 0: return None elif ext_scheme == 1: @@ -2031,55 +1994,61 @@ class Trapezoid(Record, GeometryMixin): Trapezoid with at least two sides parallel to the x- or y-axis. (x, y) denotes the lower-left (min-x, min-y) corner of the trapezoid's bounding box. - - Attributes: - delta_a (Optional[int]): If horizontal, signed x-distance from top left - vertex to bottom left vertex. If vertical, signed y-distance from - bottom left vertex to bottom right vertex. - None means reuse modal. - delta_b (Optional[int]): If horizontal, signed x-distance from bottom right - vertex to top right vertex. If vertical, signed y-distance from top - right vertex to top left vertex. - None means reuse modal. - is_vertical (bool): `True` if the left and right sides are aligned to - the y-axis. If the trapezoid is a rectangle, either `True` or `False` - can be used. - width (Optional[int]): Bounding box x-width, None means reuse modal. - height (Optional[int]): Bounding box y-height, None means reuse modal. - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset to lower-left corner of the trapezoid's bounding box. - None means reuse modal - y (Optional[int]): y-offset to lower-left corner of the trapezoid's bounding box. - None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] = None - datatype: Optional[int] = None - width: Optional[int] = None - height: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None + layer: int | None = None + datatype: int | None = None + width: int | None = None + """Bounding box x-width, None means reuse modal.""" + + height: int | None = None + """Bounding box y-height, None means reuse modal.""" + + x: int | None = None + """x-offset to lower-left corner of the trapezoid's bounding box. + None means reuse modal + """ + + y: int | None = None + """y-offset to lower-left corner of the trapezoid's bounding box. + None means reuse modal + """ + + repetition: repetition_t | None = None delta_a: int = 0 + """ + If horizontal, signed x-distance from top left vertex to bottom left vertex. + If vertical, signed y-distance from bottom left vertex to bottom right vertex. + None means reuse modal. + """ + delta_b: int = 0 + """ + If horizontal, signed x-distance from bottom right vertex to top right vertex. + If vertical, signed y-distance from top right vertex to top left vertex. + None means reuse modal. + """ + is_vertical: bool - properties: List['Property'] + """ + `True` if the left and right sides are aligned to the y-axis. + If the trapezoid is a rectangle, either `True` or `False` can be used. + """ + + properties: list['Property'] def __init__( self, is_vertical: bool, delta_a: int = 0, delta_b: int = 0, - layer: Optional[int] = None, - datatype: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + layer: int | None = None, + datatype: int | None = None, + width: int | None = None, + height: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Raises: @@ -2141,7 +2110,7 @@ class Trapezoid(Record, GeometryMixin): raise InvalidDataError(f'Invalid record id for Trapezoid: {record_id}') is_vertical, w, h, x, y, r, d, l = read_bool_byte(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -2241,44 +2210,45 @@ class CTrapezoid(Record, GeometryMixin): w = h w = 2h w = h set h = None set w = None set h = None - - Attributes: - ctrapezoid_type (Optional[int]): See above for details. - None means reuse modal. - width (Optional[int]): Bounding box x-width. - None means unnecessary, or reuse modal if necessary. - height (Optional[int]): Bounding box y-height. - None means unnecessary, or reuse modal if necessary. - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset of lower-left (min-x) point of bounding box. - None means reuse modal - y (Optional[int]): y-offset of lower-left (min-y) point of bounding box. - None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ - ctrapezoid_type: Optional[int] = None - layer: Optional[int] = None - datatype: Optional[int] = None - width: Optional[int] = None - height: Optional[int] = None - x: Optional[int] = None - y: Optional[int] = None - repetition: Optional[repetition_t] = None - properties: List['Property'] + ctrapezoid_type: int | None = None + """See class docstring for details. None means reuse modal.""" + + layer: int | None = None + datatype: int | None = None + width: int | None = None + """width: Bounding box x-width + None means unnecessary, or reuse modal if necessary. + """ + + height: int | None = None + """Bounding box y-height. + None means unnecessary, or reuse modal if necessary. + """ + + x: int | None = None + """x-offset of lower-left (min-x) point of bounding box. + None means reuse modal + """ + y: int | None = None + """y-offset of lower-left (min-y) point of bounding box. + None means reuse modal + """ + + repetition: repetition_t | None = None + properties: list['Property'] def __init__( self, - ctrapezoid_type: Optional[int] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + ctrapezoid_type: int | None = None, + layer: int | None = None, + datatype: int | None = None, + width: int | None = None, + height: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Raises: @@ -2363,7 +2333,7 @@ class CTrapezoid(Record, GeometryMixin): raise InvalidDataError(f'Invalid record id for CTrapezoid: {record_id}') t, w, h, x, y, r, d, l = read_bool_byte(stream) - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: @@ -2441,33 +2411,24 @@ class CTrapezoid(Record, GeometryMixin): class Circle(Record, GeometryMixin): """ Circle record (ID 27) - - Attributes: - radius (Optional[int]): None means reuse modal - layer (Optional[int]): None means reuse modal - datatype (Optional[int]): None means reuse modal - x (Optional[int]): x-offset, None means reuse modal - y (Optional[int]): y-offset, None means reuse modal - repetition (Optional[repetition_t]): Repetition, if any - properties (List[Property]): List of property records associate with this record. """ - layer: Optional[int] - datatype: Optional[int] - x: Optional[int] - y: Optional[int] - repetition: Optional[repetition_t] - radius: Optional[int] - properties: List['Property'] + layer: int | None + datatype: int | None + x: int | None + y: int | None + repetition: repetition_t | None + radius: int | None + properties: list['Property'] def __init__( self, - radius: Optional[int] = None, - layer: Optional[int] = None, - datatype: Optional[int] = None, - x: Optional[int] = None, - y: Optional[int] = None, - repetition: Optional[repetition_t] = None, - properties: Optional[List['Property']] = None, + radius: int | None = None, + layer: int | None = None, + datatype: int | None = None, + x: int | None = None, + y: int | None = None, + repetition: repetition_t | None = None, + properties: list['Property'] | None = None, ) -> None: """ Args: @@ -2516,7 +2477,7 @@ class Circle(Record, GeometryMixin): if z0 or z1: raise InvalidDataError('Malformed circle header') - optional: Dict[str, Any] = {} + optional: dict[str, Any] = {} if l: optional['layer'] = read_uint(stream) if d: diff --git a/pyproject.toml b/pyproject.toml index 146471e..3e6d0d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ classifiers = [ "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", ] -requires-python = ">=3.8" +requires-python = ">=3.10" dynamic = ["version"] dependencies = [ ] From 931bc599d72e4e88b4ce49d4437fa0c562a16f50 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 03:22:10 -0700 Subject: [PATCH 11/40] repeat names for re-export --- fatamorgana/__init__.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/fatamorgana/__init__.py b/fatamorgana/__init__.py index d3bce93..7de7472 100644 --- a/fatamorgana/__init__.py +++ b/fatamorgana/__init__.py @@ -24,14 +24,25 @@ help(fatamorgana.OasisLayout) ``` """ -import pathlib - -from .main import OasisLayout, Cell, XName +from .main import ( + OasisLayout as OasisLayout, + Cell as Cell, + XName as XName, + ) from .basic import ( - NString, AString, Validation, OffsetTable, OffsetEntry, - EOFError, SignedError, InvalidDataError, InvalidRecordError, - UnfilledModalError, - ReuseRepetition, GridRepetition, ArbitraryRepetition + NString as NString, + AString as AString, + Validation as Validation, + OffsetTable as OffsetTable, + OffsetEntry as OffsetEntry, + EOFError as EOFError, + SignedError as SignedError, + InvalidDataError as InvalidDataError, + InvalidRecordError as InvalidRecordError, + UnfilledModalError as UnfilledModalError, + ReuseRepetition as ReuseRepetition, + GridRepetition as GridRepetition, + ArbitraryRepetition as ArbitraryRepetition, ) From bd288d1363aac279e5ccda4614045ec6164329ed Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 03:52:02 -0700 Subject: [PATCH 12/40] double-up single-letter variable names --- fatamorgana/records.py | 463 ++++++++++++++++++++--------------------- 1 file changed, 230 insertions(+), 233 deletions(-) diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 3650262..774ea98 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -968,26 +968,26 @@ class Property(Record): record = Property() else: byte = read_byte(stream) # UUUUVCNS - u = 0x0f & (byte >> 4) - v = 0x01 & (byte >> 3) - c = 0x01 & (byte >> 2) - n = 0x01 & (byte >> 1) - s = 0x01 & (byte >> 0) + uu = 0x0f & (byte >> 4) + vv = 0x01 & (byte >> 3) + cc = 0x01 & (byte >> 2) + nn = 0x01 & (byte >> 1) + ss = 0x01 & (byte >> 0) - name = read_refname(stream, c, n) - if v == 0: - if u < 0x0f: - value_count = u + name = read_refname(stream, cc, nn) + if vv == 0: + if uu < 0x0f: + value_count = uu else: value_count = read_uint(stream) values: list[property_value_t] | None = [read_property_value(stream) for _ in range(value_count)] else: values = None -# if u != 0: +# if uu != 0: # logger.warning('Malformed property record header; requested modal' # ' values but had nonzero count. Ignoring count.') - record = Property(name, values, bool(s)) + record = Property(name, values, bool(ss)) logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record @@ -999,30 +999,27 @@ class Property(Record): raise InvalidDataError('Property has value or name, but no is_standard flag!') if self.values is not None: value_count = len(self.values) - v = 0 - if value_count >= 0x0f: - u = 0x0f - else: - u = value_count + vv = 0 + uu = 0x0f if value_count >= 0x0f else value_count else: - v = 1 - u = 0 + vv = 1 + uu = 0 - c = self.name is not None - n = c and isinstance(self.name, int) - s = self.is_standard + cc = self.name is not None + nn = cc and isinstance(self.name, int) + ss = self.is_standard size = write_uint(stream, 28) - size += write_byte(stream, (u << 4) | (v << 3) | (c << 2) | (n << 1) | s) - if c: - if n: + size += write_byte(stream, (uu << 4) | (vv << 3) | (cc << 2) | (nn << 1) | ss) + if cc: + if nn: size += write_uint(stream, self.name) # type: ignore else: size += self.name.write(stream) # type: ignore - if not v: - if u == 0x0f: + if not vv: + if uu == 0x0f: size += write_uint(stream, len(self.values)) # type: ignore - size += sum(write_property_value(stream, p) for p in self.values) # type: ignore + size += sum(write_property_value(stream, pp) for pp in self.values) # type: ignore return size @@ -1202,21 +1199,21 @@ class XGeometry(Record, GeometryMixin): if record_id != 33: raise InvalidDataError(f'Invalid record id for XGeometry: {record_id}') - z0, z1, z2, x, y, r, d, l = read_bool_byte(stream) + z0, z1, z2, xx, yy, rr, dd, ll = read_bool_byte(stream) if z0 or z1 or z2: raise InvalidDataError('Malformed XGeometry header') attribute = read_uint(stream) optional: dict[str, Any] = {} - if l: + if ll: optional['layer'] = read_uint(stream) - if d: + if dd: optional['datatype'] = read_uint(stream) bstring = read_bstring(stream) - if x: + if xx: optional['x'] = read_sint(stream) - if y: + if yy: optional['y'] = read_sint(stream) - if r: + if rr: optional['repetition'] = read_repetition(stream) record = XGeometry(attribute, bstring, **optional) @@ -1224,25 +1221,25 @@ class XGeometry(Record, GeometryMixin): return record def write(self, stream: IO[bytes]) -> int: - x = self.x is not None - y = self.y is not None - r = self.repetition is not None - d = self.datatype is not None - l = self.layer is not None + xx = self.x is not None + yy = self.y is not None + rr = self.repetition is not None + dd = self.datatype is not None + ll = self.layer is not None size = write_uint(stream, 33) - size += write_bool_byte(stream, (0, 0, 0, x, y, r, d, l)) + size += write_bool_byte(stream, (0, 0, 0, xx, yy, rr, dd, ll)) size += write_uint(stream, self.attribute) - if l: + if ll: size += write_uint(stream, self.layer) # type: ignore - if d: + if dd: size += write_uint(stream, self.datatype) # type: ignore size += write_bstring(stream, self.bstring) - if x: + if xx: size += write_sint(stream, self.x) # type: ignore - if y: + if yy: size += write_sint(stream, self.y) # type: ignore - if r: + if rr: size += self.repetition.write(stream) # type: ignore return size @@ -1373,25 +1370,25 @@ class Placement(Record): raise InvalidDataError(f'Invalid record id for Placement: {record_id}') #CNXYRAAF (17) or CNXYRMAF (18) - c, n, x, y, r, ma0, ma1, flip = read_bool_byte(stream) + cc, nn, xx, yy, rr, ma0, ma1, flip = read_bool_byte(stream) optional: dict[str, Any] = {} - name = read_refname(stream, c, n) + name = read_refname(stream, cc, nn) if record_id == 17: aa = (ma0 << 1) | ma1 optional['angle'] = aa * 90 elif record_id == 18: - m = ma0 - a = ma1 - if m: + mm = ma0 + aa1 = ma1 + if mm: optional['magnification'] = read_real(stream) - if a: + if aa1: optional['angle'] = read_real(stream) - if x: + if xx: optional['x'] = read_sint(stream) - if y: + if yy: optional['y'] = read_sint(stream) - if r: + if rr: optional['repetition'] = read_repetition(stream) record = Placement(flip, name, **optional) @@ -1399,43 +1396,43 @@ class Placement(Record): return record def write(self, stream: IO[bytes]) -> int: - c = self.name is not None - n = c and isinstance(self.name, int) - x = self.x is not None - y = self.y is not None - r = self.repetition is not None - f = self.flip + cc = self.name is not None + nn = cc and isinstance(self.name, int) + xx = self.x is not None + yy = self.y is not None + rr = self.repetition is not None + ff = self.flip if (self.magnification == 1 and self.angle is not None and abs(self.angle % 90.0) < 1e-14): aa = int((self.angle / 90) % 4.0) - bools = (c, n, x, y, r, aa & 0b10, aa & 0b01, f) - m = False - a = False + bools = (cc, nn, xx, yy, rr, aa & 0b10, aa & 0b01, ff) + mm = False + aq = False record_id = 17 else: - m = self.magnification is not None - a = self.angle is not None - bools = (c, n, x, y, r, m, a, f) + mm = self.magnification is not None + aq = self.angle is not None + bools = (cc, nn, xx, yy, rr, mm, aq, ff) record_id = 18 size = write_uint(stream, record_id) size += write_bool_byte(stream, bools) - if c: - if n: + if cc: + if nn: size += write_uint(stream, self.name) # type: ignore else: size += self.name.write(stream) # type: ignore - if m: + if mm: size += write_real(stream, self.magnification) # type: ignore - if a: + if aa: size += write_real(stream, self.angle) # type: ignore - if x: + if xx: size += write_sint(stream, self.x) # type: ignore - if y: + if yy: size += write_sint(stream, self.y) # type: ignore - if r: + if rr: size += self.repetition.write(stream) # type: ignore return size @@ -1506,21 +1503,21 @@ class Text(Record, GeometryMixin): if record_id != 19: raise InvalidDataError(f'Invalid record id for Text: {record_id}') - z0, c, n, x, y, r, d, l = read_bool_byte(stream) + z0, cc, nn, xx, yy, rr, dd, ll = read_bool_byte(stream) if z0: raise InvalidDataError('Malformed Text header') optional: dict[str, Any] = {} - string = read_refstring(stream, c, n) - if l: + string = read_refstring(stream, cc, nn) + if ll: optional['layer'] = read_uint(stream) - if d: + if dd: optional['datatype'] = read_uint(stream) - if x: + if xx: optional['x'] = read_sint(stream) - if y: + if yy: optional['y'] = read_sint(stream) - if r: + if rr: optional['repetition'] = read_repetition(stream) record = Text(string, **optional) @@ -1528,30 +1525,30 @@ class Text(Record, GeometryMixin): return record def write(self, stream: IO[bytes]) -> int: - c = self.string is not None - n = c and isinstance(self.string, int) - x = self.x is not None - y = self.y is not None - r = self.repetition is not None - d = self.datatype is not None - l = self.layer is not None + cc = self.string is not None + nn = cc and isinstance(self.string, int) + xx = self.x is not None + yy = self.y is not None + rr = self.repetition is not None + dd = self.datatype is not None + ll = self.layer is not None size = write_uint(stream, 19) - size += write_bool_byte(stream, (0, c, n, x, y, r, d, l)) - if c: - if n: + size += write_bool_byte(stream, (0, cc, nn, xx, yy, rr, dd, ll)) + if cc: + if nn: size += write_uint(stream, self.string) # type: ignore else: size += self.string.write(stream) # type: ignore - if l: + if ll: size += write_uint(stream, self.layer) # type: ignore - if d: + if dd: size += write_uint(stream, self.datatype) # type: ignore - if x: + if xx: size += write_sint(stream, self.x) # type: ignore - if y: + if yy: size += write_sint(stream, self.y) # type: ignore - if r: + if rr: size += self.repetition.write(stream) # type: ignore return size @@ -1646,51 +1643,51 @@ class Rectangle(Record, GeometryMixin): if record_id != 20: raise InvalidDataError(f'Invalid record id for Rectangle: {record_id}') - is_square, w, h, x, y, r, d, l = read_bool_byte(stream) + is_square, ww, hh, xx, yy, rr, dd, ll = read_bool_byte(stream) optional: dict[str, Any] = {} - if l: + if ll: optional['layer'] = read_uint(stream) - if d: + if dd: optional['datatype'] = read_uint(stream) - if w: + if ww: optional['width'] = read_uint(stream) - if h: + if hh: optional['height'] = read_uint(stream) - if x: + if xx: optional['x'] = read_sint(stream) - if y: + if yy: optional['y'] = read_sint(stream) - if r: + if rr: optional['repetition'] = read_repetition(stream) record = Rectangle(is_square, **optional) logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: IO[bytes]) -> int: - s = self.is_square - w = self.width is not None - h = self.height is not None - x = self.x is not None - y = self.y is not None - r = self.repetition is not None - d = self.datatype is not None - l = self.layer is not None + ss = self.is_square + ww = self.width is not None + hh = self.height is not None + xx = self.x is not None + yy = self.y is not None + rr = self.repetition is not None + dd = self.datatype is not None + ll = self.layer is not None size = write_uint(stream, 20) - size += write_bool_byte(stream, (s, w, h, x, y, r, d, l)) - if l: + size += write_bool_byte(stream, (ss, ww, hh, xx, yy, rr, dd, ll)) + if ll: size += write_uint(stream, self.layer) # type: ignore - if d: + if dd: size += write_uint(stream, self.datatype) # type: ignore - if w: + if ww: size += write_uint(stream, self.width) # type: ignore - if h: + if hh: size += write_uint(stream, self.height) # type: ignore - if x: + if xx: size += write_sint(stream, self.x) # type: ignore - if y: + if yy: size += write_sint(stream, self.y) # type: ignore - if r: + if rr: size += self.repetition.write(stream) # type: ignore return size @@ -1765,49 +1762,49 @@ class Polygon(Record, GeometryMixin): if record_id != 21: raise InvalidDataError(f'Invalid record id for Polygon: {record_id}') - z0, z1, p, x, y, r, d, l = read_bool_byte(stream) + z0, z1, pp, xx, yy, rr, dd, ll = read_bool_byte(stream) if z0 or z1: raise InvalidDataError('Invalid polygon header') optional: dict[str, Any] = {} - if l: + if ll: optional['layer'] = read_uint(stream) - if d: + if dd: optional['datatype'] = read_uint(stream) - if p: + if pp: optional['point_list'] = read_point_list(stream, implicit_closed=True) - if x: + if xx: optional['x'] = read_sint(stream) - if y: + if yy: optional['y'] = read_sint(stream) - if r: + if rr: optional['repetition'] = read_repetition(stream) record = Polygon(**optional) logger.debug('Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: IO[bytes], fast: bool = False) -> int: - p = self.point_list is not None - x = self.x is not None - y = self.y is not None - r = self.repetition is not None - d = self.datatype is not None - l = self.layer is not None + pp = self.point_list is not None + xx = self.x is not None + yy = self.y is not None + rr = self.repetition is not None + dd = self.datatype is not None + ll = self.layer is not None size = write_uint(stream, 21) - size += write_bool_byte(stream, (0, 0, p, x, y, r, d, l)) - if l: + size += write_bool_byte(stream, (0, 0, pp, xx, yy, rr, dd, ll)) + if ll: size += write_uint(stream, self.layer) # type: ignore - if d: + if dd: size += write_uint(stream, self.datatype) # type: ignore - if p: + if pp: size += write_point_list(stream, self.point_list, # type: ignore implicit_closed=True, fast=fast) - if x: + if xx: size += write_sint(stream, self.x) # type: ignore - if y: + if yy: size += write_sint(stream, self.y) # type: ignore - if r: + if rr: size += self.repetition.write(stream) # type: ignore return size @@ -1908,15 +1905,15 @@ class Path(Record, GeometryMixin): if record_id != 22: raise InvalidDataError(f'Invalid record id for Path: {record_id}') - e, w, p, x, y, r, d, l = read_bool_byte(stream) + ee, ww, pp, xx, yy, rr, dd, ll = read_bool_byte(stream) optional: dict[str, Any] = {} - if l: + if ll: optional['layer'] = read_uint(stream) - if d: + if dd: optional['datatype'] = read_uint(stream) - if w: + if ww: optional['half_width'] = read_uint(stream) - if e: + if ee: scheme = read_uint(stream) scheme_end = scheme & 0b11 scheme_start = (scheme >> 2) & 0b11 @@ -1935,37 +1932,37 @@ class Path(Record, GeometryMixin): optional['extension_start'] = get_pathext(scheme_start) optional['extension_end'] = get_pathext(scheme_end) - if p: + if pp: optional['point_list'] = read_point_list(stream, implicit_closed=False) - if x: + if xx: optional['x'] = read_sint(stream) - if y: + if yy: optional['y'] = read_sint(stream) - if r: + if rr: optional['repetition'] = read_repetition(stream) record = Path(**optional) logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: IO[bytes], fast: bool = False) -> int: - e = self.extension_start is not None or self.extension_end is not None - w = self.half_width is not None - p = self.point_list is not None - x = self.x is not None - y = self.y is not None - r = self.repetition is not None - d = self.datatype is not None - l = self.layer is not None + ee = self.extension_start is not None or self.extension_end is not None + ww = self.half_width is not None + pp = self.point_list is not None + xx = self.x is not None + yy = self.y is not None + rr = self.repetition is not None + dd = self.datatype is not None + ll = self.layer is not None size = write_uint(stream, 21) - size += write_bool_byte(stream, (e, w, p, x, y, r, d, l)) - if l: + size += write_bool_byte(stream, (ee, ww, pp, xx, yy, rr, dd, ll)) + if ll: size += write_uint(stream, self.layer) # type: ignore - if d: + if dd: size += write_uint(stream, self.datatype) # type: ignore - if w: + if ww: size += write_uint(stream, self.half_width) # type: ignore - if e: + if ee: scheme = 0 if self.extension_start is not None: scheme += self.extension_start[0].value << 2 @@ -1976,14 +1973,14 @@ class Path(Record, GeometryMixin): size += write_sint(stream, self.extension_start[1]) # type: ignore if scheme & 0b0011 == 0b0011: size += write_sint(stream, self.extension_end[1]) # type: ignore - if p: + if pp: size += write_point_list(stream, self.point_list, # type: ignore implicit_closed=False, fast=fast) - if x: + if xx: size += write_sint(stream, self.x) # type: ignore - if y: + if yy: size += write_sint(stream, self.y) # type: ignore - if r: + if rr: size += self.repetition.write(stream) # type: ignore return size @@ -2109,39 +2106,39 @@ class Trapezoid(Record, GeometryMixin): if record_id not in (23, 24, 25): raise InvalidDataError(f'Invalid record id for Trapezoid: {record_id}') - is_vertical, w, h, x, y, r, d, l = read_bool_byte(stream) + is_vertical, ww, hh, xx, yy, rr, dd, ll = read_bool_byte(stream) optional: dict[str, Any] = {} - if l: + if ll: optional['layer'] = read_uint(stream) - if d: + if dd: optional['datatype'] = read_uint(stream) - if w: + if ww: optional['width'] = read_uint(stream) - if h: + if hh: optional['height'] = read_uint(stream) if record_id != 25: optional['delta_a'] = read_sint(stream) if record_id != 24: optional['delta_b'] = read_sint(stream) - if x: + if xx: optional['x'] = read_sint(stream) - if y: + if yy: optional['y'] = read_sint(stream) - if r: + if rr: optional['repetition'] = read_repetition(stream) record = Trapezoid(bool(is_vertical), **optional) logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: IO[bytes]) -> int: - v = self.is_vertical - w = self.width is not None - h = self.height is not None - x = self.x is not None - y = self.y is not None - r = self.repetition is not None - d = self.datatype is not None - l = self.layer is not None + vv = self.is_vertical + ww = self.width is not None + hh = self.height is not None + xx = self.x is not None + yy = self.y is not None + rr = self.repetition is not None + dd = self.datatype is not None + ll = self.layer is not None if self.delta_b == 0: record_id = 24 @@ -2150,24 +2147,24 @@ class Trapezoid(Record, GeometryMixin): else: record_id = 23 size = write_uint(stream, record_id) - size += write_bool_byte(stream, (v, w, h, x, y, r, d, l)) - if l: + size += write_bool_byte(stream, (vv, ww, hh, xx, yy, rr, dd, ll)) + if ll: size += write_uint(stream, self.layer) # type: ignore - if d: + if dd: size += write_uint(stream, self.datatype) # type: ignore - if w: + if ww: size += write_uint(stream, self.width) # type: ignore - if h: + if hh: size += write_uint(stream, self.height) # type: ignore if record_id != 25: size += write_sint(stream, self.delta_a) # type: ignore if record_id != 24: size += write_sint(stream, self.delta_b) # type: ignore - if x: + if xx: size += write_sint(stream, self.x) # type: ignore - if y: + if yy: size += write_sint(stream, self.y) # type: ignore - if r: + if rr: size += self.repetition.write(stream) # type: ignore return size @@ -2332,55 +2329,55 @@ class CTrapezoid(Record, GeometryMixin): if record_id != 26: raise InvalidDataError(f'Invalid record id for CTrapezoid: {record_id}') - t, w, h, x, y, r, d, l = read_bool_byte(stream) + tt, ww, hh, xx, yy, rr, dd, ll = read_bool_byte(stream) optional: dict[str, Any] = {} - if l: + if ll: optional['layer'] = read_uint(stream) - if d: + if dd: optional['datatype'] = read_uint(stream) - if t: + if tt: optional['ctrapezoid_type'] = read_uint(stream) - if w: + if ww: optional['width'] = read_uint(stream) - if h: + if hh: optional['height'] = read_uint(stream) - if x: + if xx: optional['x'] = read_sint(stream) - if y: + if yy: optional['y'] = read_sint(stream) - if r: + if rr: optional['repetition'] = read_repetition(stream) record = CTrapezoid(**optional) logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: IO[bytes]) -> int: - t = self.ctrapezoid_type is not None - w = self.width is not None - h = self.height is not None - x = self.x is not None - y = self.y is not None - r = self.repetition is not None - d = self.datatype is not None - l = self.layer is not None + tt = self.ctrapezoid_type is not None + ww = self.width is not None + hh = self.height is not None + xx = self.x is not None + yy = self.y is not None + rr = self.repetition is not None + dd = self.datatype is not None + ll = self.layer is not None size = write_uint(stream, 26) - size += write_bool_byte(stream, (t, w, h, x, y, r, d, l)) - if l: + size += write_bool_byte(stream, (tt, ww, hh, xx, yy, rr, dd, ll)) + if ll: size += write_uint(stream, self.layer) # type: ignore - if d: + if dd: size += write_uint(stream, self.datatype) # type: ignore - if t: + if tt: size += write_uint(stream, self.ctrapezoid_type) # type: ignore - if w: + if ww: size += write_uint(stream, self.width) # type: ignore - if h: + if hh: size += write_uint(stream, self.height) # type: ignore - if x: + if xx: size += write_sint(stream, self.x) # type: ignore - if y: + if yy: size += write_sint(stream, self.y) # type: ignore - if r: + if rr: size += self.repetition.write(stream) # type: ignore return size @@ -2473,48 +2470,48 @@ class Circle(Record, GeometryMixin): if record_id != 27: raise InvalidDataError(f'Invalid record id for Circle: {record_id}') - z0, z1, has_radius, x, y, r, d, l = read_bool_byte(stream) + z0, z1, has_radius, xx, yy, rr, dd, ll = read_bool_byte(stream) if z0 or z1: raise InvalidDataError('Malformed circle header') optional: dict[str, Any] = {} - if l: + if ll: optional['layer'] = read_uint(stream) - if d: + if dd: optional['datatype'] = read_uint(stream) if has_radius: optional['radius'] = read_uint(stream) - if x: + if xx: optional['x'] = read_sint(stream) - if y: + if yy: optional['y'] = read_sint(stream) - if r: + if rr: optional['repetition'] = read_repetition(stream) record = Circle(**optional) logger.debug(f'Record ending at 0x{stream.tell():x}:\n {record}') return record def write(self, stream: IO[bytes]) -> int: - s = self.radius is not None - x = self.x is not None - y = self.y is not None - r = self.repetition is not None - d = self.datatype is not None - l = self.layer is not None + ss = self.radius is not None + xx = self.x is not None + yy = self.y is not None + rr = self.repetition is not None + dd = self.datatype is not None + ll = self.layer is not None size = write_uint(stream, 27) - size += write_bool_byte(stream, (0, 0, s, x, y, r, d, l)) - if l: + size += write_bool_byte(stream, (0, 0, ss, xx, yy, rr, dd, ll)) + if ll: size += write_uint(stream, self.layer) # type: ignore - if d: + if dd: size += write_uint(stream, self.datatype) # type: ignore - if s: + if ss: size += write_uint(stream, self.radius) # type: ignore - if x: + if xx: size += write_sint(stream, self.x) # type: ignore - if y: + if yy: size += write_sint(stream, self.y) # type: ignore - if r: + if rr: size += self.repetition.write(stream) # type: ignore return size From d83ef1ce2d275b1a063c7b45787c95622900a89e Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 03:53:08 -0700 Subject: [PATCH 13/40] update type annotations --- fatamorgana/basic.py | 17 +++++++++-------- fatamorgana/main.py | 4 ++-- fatamorgana/records.py | 3 ++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index ea96528..57b3919 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -2,7 +2,8 @@ This module contains all datatypes and parsing/writing functions for all abstractions below the 'record' or 'block' level. """ -from typing import Type, Union, Any, Sequence, IO +from typing import Any, IO, Union +from collections.abc import Sequence from fractions import Fraction from enum import Enum import math @@ -20,7 +21,7 @@ except ImportError: ''' Type definitions ''' -real_t = Union[int, float, Fraction] +real_t = int | float | Fraction repetition_t = Union['ReuseRepetition', 'GridRepetition', 'ArbitraryRepetition'] property_value_t = Union[int, bytes, 'AString', 'NString', 'PropStringReference', float, Fraction] bytes_t = bytes @@ -184,7 +185,7 @@ if _USE_NUMPY: byte_arr = _read(stream, 1) return numpy.unpackbits(numpy.frombuffer(byte_arr, dtype=numpy.uint8)) - def _np_write_bool_byte(stream: IO[bytes], bits: tuple[Union[bool, int], ...]) -> int: + def _np_write_bool_byte(stream: IO[bytes], bits: tuple[bool | int, ...]) -> int: """ Pack 8 booleans into a byte, and write it to the stream. @@ -563,7 +564,7 @@ class NString: """ _string: str - def __init__(self, string_or_bytes: Union[bytes, str]) -> None: + def __init__(self, string_or_bytes: bytes | str) -> None: """ Args: string_or_bytes: Content of the `NString`. @@ -677,7 +678,7 @@ class AString: """ _string: str - def __init__(self, string_or_bytes: Union[bytes, str]) -> None: + def __init__(self, string_or_bytes: bytes | str) -> None: """ Args: string_or_bytes: Content of the AString. @@ -1722,10 +1723,10 @@ class PropStringReference: ref: int """ID of the target""" - reference_type: Type + reference_type: type """Type of the target: `bytes`, `NString`, or `AString`""" - def __init__(self, ref: int, ref_type: Type) -> None: + def __init__(self, ref: int, ref_type: type) -> None: """ :param ref: ID number of the target. :param ref_type: Type of the target. One of bytes, NString, AString. @@ -1767,7 +1768,7 @@ def read_property_value(stream: IO[bytes]) -> property_value_t: Raises: InvalidDataError: if an invalid type is read. """ - ref_type: Type + ref_type: type prop_type = read_uint(stream) if 0 <= prop_type <= 7: return read_real(stream, prop_type) diff --git a/fatamorgana/main.py b/fatamorgana/main.py index 1bb7258..978d842 100644 --- a/fatamorgana/main.py +++ b/fatamorgana/main.py @@ -3,7 +3,7 @@ This module contains data structures and functions for reading from and writing to whole OASIS layout files, and provides a few additional abstractions for the data contained inside them. """ -from typing import Type, IO +from typing import IO import io import logging @@ -528,7 +528,7 @@ class XName: # Mapping from record id to record class. -_GEOMETRY: dict[int, Type[records.geometry_t]] = { +_GEOMETRY: dict[int, type[records.geometry_t]] = { 19: records.Text, 20: records.Rectangle, 21: records.Polygon, diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 774ea98..81364ca 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -10,7 +10,8 @@ Higher-level code (e.g. monitoring for combinations of records with parse, or code for dealing with nested records in a CBlock) should live in main.py instead. """ -from typing import Union, Sequence, Any, TypeVar, IO +from typing import Any, TypeVar, IO, Union +from collections.abc import Sequence from abc import ABCMeta, abstractmethod import copy import math From c9e894879f840d5717e6a2aaa270fe0ee8d28c58 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 03:53:23 -0700 Subject: [PATCH 14/40] use "is" over == for types --- fatamorgana/basic.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 57b3919..1f11bb3 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -1735,7 +1735,7 @@ class PropStringReference: self.ref_type = ref_type def __eq__(self, other: Any) -> bool: - return isinstance(other, type(self)) and self.ref == other.ref and self.reference_type == other.reference_type + return isinstance(other, type(self)) and self.ref == other.ref and self.reference_type is other.reference_type def __repr__(self) -> str: return f'[{self.ref_type} : {self.ref}]' @@ -1843,11 +1843,11 @@ def write_property_value( size = write_uint(stream, 12) size += value.write(stream) elif isinstance(value, PropStringReference): - if value.ref_type == AString: + if value.ref_type is AString: size = write_uint(stream, 13) - elif value.ref_type == bytes: + elif value.ref_type is bytes: size = write_uint(stream, 14) - if value.ref_type == AString: + if value.ref_type is AString: size = write_uint(stream, 15) size += write_uint(stream, value.ref) else: From ab8b71b149d9e7d7c2501ef3cc11cafd3d7563da Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 03:53:44 -0700 Subject: [PATCH 15/40] fix overflow when using numpy 2.0 --- fatamorgana/records.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 81364ca..9b3881a 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -1376,7 +1376,7 @@ class Placement(Record): optional: dict[str, Any] = {} name = read_refname(stream, cc, nn) if record_id == 17: - aa = (ma0 << 1) | ma1 + aa = int((ma0 << 1) | ma1) optional['angle'] = aa * 90 elif record_id == 18: mm = ma0 From d05561af41b5d185a8489c3d34c9866a23f56f6d Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 03:53:59 -0700 Subject: [PATCH 16/40] comment style --- fatamorgana/basic.py | 5 +++-- fatamorgana/records.py | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 1f11bb3..6010d23 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -1728,8 +1728,9 @@ class PropStringReference: def __init__(self, ref: int, ref_type: type) -> None: """ - :param ref: ID number of the target. - :param ref_type: Type of the target. One of bytes, NString, AString. + Args: + ref: ID number of the target. + ref_type: Type of the target. One of bytes, NString, AString. """ self.ref = ref self.ref_type = ref_type diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 9b3881a..87e4da8 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -47,8 +47,7 @@ point_list_t = Sequence[Sequence[int]] class Modals: """ - Modal variables, used to store data about previously-written or - -read records. + Modal variables, used to store data about previously-written or -read records. """ repetition: repetition_t | None = None placement_x: int = 0 From 5ea5e8d8f96e215acbde3e94f765bf5cd16168bb Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 03:54:16 -0700 Subject: [PATCH 17/40] prefix unused variables --- fatamorgana/test/test_files_cells.py | 4 ++-- fatamorgana/test/test_files_properties.py | 4 ++-- fatamorgana/test/test_files_texts.py | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fatamorgana/test/test_files_cells.py b/fatamorgana/test/test_files_cells.py index 59bc6d4..285bd08 100644 --- a/fatamorgana/test/test_files_cells.py +++ b/fatamorgana/test/test_files_cells.py @@ -113,7 +113,7 @@ def test_file_3() -> None: buf.seek(0) with pytest.raises(InvalidRecordError): - layout = OasisLayout.read(buf) + _layout = OasisLayout.read(buf) def write_file_4(buf: IO[bytes]) -> IO[bytes]: @@ -226,7 +226,7 @@ def test_file_6() -> None: buf.seek(0) with pytest.raises(InvalidDataError): - layout = OasisLayout.read(buf) + _layout = OasisLayout.read(buf) #base_tests(layout) #assert len(layout.cellnames) == 2 diff --git a/fatamorgana/test/test_files_properties.py b/fatamorgana/test/test_files_properties.py index 99bdc37..0100318 100644 --- a/fatamorgana/test/test_files_properties.py +++ b/fatamorgana/test/test_files_properties.py @@ -1065,7 +1065,7 @@ def test_file_8() -> None: buf.seek(0) with pytest.raises(InvalidDataError): - layout = OasisLayout.read(buf) + _layout = OasisLayout.read(buf) def test_file_9() -> None: @@ -1075,4 +1075,4 @@ def test_file_9() -> None: buf.seek(0) with pytest.raises(InvalidDataError): - layout = OasisLayout.read(buf) + _layout = OasisLayout.read(buf) diff --git a/fatamorgana/test/test_files_texts.py b/fatamorgana/test/test_files_texts.py index 0d10744..2603691 100644 --- a/fatamorgana/test/test_files_texts.py +++ b/fatamorgana/test/test_files_texts.py @@ -494,7 +494,7 @@ def test_file_3() -> None: buf.seek(0) with pytest.raises(InvalidRecordError): - layout = OasisLayout.read(buf) + _layout = OasisLayout.read(buf) def write_file_4(buf: IO[bytes]) -> IO[bytes]: @@ -567,7 +567,7 @@ def test_file_6() -> None: buf.seek(0) with pytest.raises(InvalidDataError): - layout = OasisLayout.read(buf) + _layout = OasisLayout.read(buf) def write_file_7(buf: IO[bytes]) -> IO[bytes]: @@ -598,7 +598,7 @@ def test_file_7() -> None: buf.seek(0) with pytest.raises(InvalidDataError): - layout = OasisLayout.read(buf) + _layout = OasisLayout.read(buf) def write_file_8(buf: IO[bytes]) -> IO[bytes]: @@ -629,7 +629,7 @@ def test_file_8() -> None: buf.seek(0) with pytest.raises(InvalidDataError): - layout = OasisLayout.read(buf) + _layout = OasisLayout.read(buf) def write_file_9(buf: IO[bytes]) -> IO[bytes]: @@ -732,4 +732,4 @@ def test_file_11() -> None: buf.seek(0) with pytest.raises(InvalidDataError): - layout = OasisLayout.read(buf) + _layout = OasisLayout.read(buf) From 31e52e20d6f86ff03d89743efec6b9f0fe21b934 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 17:53:03 -0700 Subject: [PATCH 18/40] use double quotes for docstrings --- fatamorgana/test/build_testfiles.py | 4 +-- fatamorgana/test/test_files_cblocks.py | 4 +-- fatamorgana/test/test_files_cells.py | 28 ++++++++--------- fatamorgana/test/test_files_circles.py | 4 +-- fatamorgana/test/test_files_ctrapezoids.py | 8 ++--- fatamorgana/test/test_files_empty.py | 20 ++++++------ fatamorgana/test/test_files_layernames.py | 16 +++++----- fatamorgana/test/test_files_modals.py | 4 +-- fatamorgana/test/test_files_paths.py | 4 +-- fatamorgana/test/test_files_placements.py | 20 ++++++------ fatamorgana/test/test_files_polygons.py | 8 ++--- fatamorgana/test/test_files_properties.py | 32 +++++++++---------- fatamorgana/test/test_files_rectangles.py | 4 +-- fatamorgana/test/test_files_texts.py | 36 +++++++++++----------- fatamorgana/test/test_files_trapezoids.py | 4 +-- 15 files changed, 98 insertions(+), 98 deletions(-) diff --git a/fatamorgana/test/build_testfiles.py b/fatamorgana/test/build_testfiles.py index 5bb7525..649de3e 100644 --- a/fatamorgana/test/build_testfiles.py +++ b/fatamorgana/test/build_testfiles.py @@ -1,6 +1,6 @@ -''' +""" Build files equivalent to the test cases used by KLayout. -''' +""" from typing import Callable, IO diff --git a/fatamorgana/test/test_files_cblocks.py b/fatamorgana/test/test_files_cblocks.py index 3f02e93..f4d32b5 100644 --- a/fatamorgana/test/test_files_cblocks.py +++ b/fatamorgana/test/test_files_cblocks.py @@ -27,8 +27,8 @@ def base_tests(layout: OasisLayout) -> None: def write_file_1(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) diff --git a/fatamorgana/test/test_files_cells.py b/fatamorgana/test/test_files_cells.py index 285bd08..40a6009 100644 --- a/fatamorgana/test/test_files_cells.py +++ b/fatamorgana/test/test_files_cells.py @@ -24,9 +24,9 @@ def base_tests(layout: OasisLayout) -> None: def write_file_1(buf: IO[bytes]) -> IO[bytes]: - ''' + """ Single cell with explicit name 'XYZ' - ''' + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) @@ -49,9 +49,9 @@ def test_file_1() -> None: def write_file_2(buf: IO[bytes]) -> IO[bytes]: - ''' + """ Two cellnames ('XYZ', 'ABC') and two cells with name references. - ''' + """ buf.write(HEADER) write_uint(buf, 3) # CELLNAME record (implicit id 0) @@ -86,9 +86,9 @@ def test_file_2() -> None: def write_file_3(buf: IO[bytes]) -> IO[bytes]: - ''' + """ Invalid file, contains a mix of explicit and implicit cellnames - ''' + """ buf.write(HEADER) write_uint(buf, 4) # CELLNAME record (explicit id) @@ -117,9 +117,9 @@ def test_file_3() -> None: def write_file_4(buf: IO[bytes]) -> IO[bytes]: - ''' + """ Two cells referencing two names with explicit ids (unsorted) - ''' + """ buf.write(HEADER) write_uint(buf, 4) # CELLNAME record (explicit id) @@ -156,9 +156,9 @@ def test_file_4() -> None: def write_file_5(buf: IO[bytes]) -> IO[bytes]: - ''' + """ Reference to non-existent cell name. - ''' + """ buf.write(HEADER) write_uint(buf, 4) # CELLNAME record (explicit id) @@ -197,9 +197,9 @@ def test_file_5() -> None: def write_file_6(buf: IO[bytes]) -> IO[bytes]: - ''' + """ Cellname with invalid n-string. - ''' + """ buf.write(HEADER) write_uint(buf, 4) # CELLNAME record (explicit id) @@ -238,9 +238,9 @@ def test_file_6() -> None: def write_file_7(buf: IO[bytes]) -> IO[bytes]: - ''' + """ Unused cellname. - ''' + """ buf.write(HEADER) write_uint(buf, 4) # CELLNAME record (explicit id) diff --git a/fatamorgana/test/test_files_circles.py b/fatamorgana/test/test_files_circles.py index f29b18f..b5d2cba 100644 --- a/fatamorgana/test/test_files_circles.py +++ b/fatamorgana/test/test_files_circles.py @@ -25,8 +25,8 @@ def base_tests(layout: OasisLayout) -> None: def write_file_1(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) diff --git a/fatamorgana/test/test_files_ctrapezoids.py b/fatamorgana/test/test_files_ctrapezoids.py index 095909f..b6f8bc0 100644 --- a/fatamorgana/test/test_files_ctrapezoids.py +++ b/fatamorgana/test/test_files_ctrapezoids.py @@ -21,8 +21,8 @@ def base_tests(layout: OasisLayout) -> None: def write_file_1(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) @@ -154,8 +154,8 @@ def test_file_1() -> None: def write_file_2(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) diff --git a/fatamorgana/test/test_files_empty.py b/fatamorgana/test/test_files_empty.py index 8554c28..1f9e6f3 100644 --- a/fatamorgana/test/test_files_empty.py +++ b/fatamorgana/test/test_files_empty.py @@ -23,11 +23,11 @@ def base_tests(layout: OasisLayout) -> None: def write_file_1(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File contains one PAD record. 1000 units/micron Offset table inside START. - ''' + """ buf.write(MAGIC_BYTES) write_uint(buf, 1) # START record @@ -56,11 +56,11 @@ def test_file_1() -> None: def write_file_2(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File contains no records. 1/2 unit/micron Offset table inside START. - ''' + """ buf.write(MAGIC_BYTES) write_uint(buf, 1) # START record @@ -87,11 +87,11 @@ def test_file_2() -> None: def write_file_3(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File contains no records. 10/4 unit/micron Offset table inside START. - ''' + """ buf.write(MAGIC_BYTES) write_uint(buf, 1) # START record @@ -119,11 +119,11 @@ def test_file_3() -> None: def write_file_4(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File contains no records. 12.5 unit/micron (float32) Offset table inside START. - ''' + """ buf.write(MAGIC_BYTES) write_uint(buf, 1) # START record @@ -150,11 +150,11 @@ def test_file_4() -> None: def write_file_5(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File contains no records. 12.5 unit/micron (float64) Offset table inside START. - ''' + """ buf.write(MAGIC_BYTES) write_uint(buf, 1) # START record diff --git a/fatamorgana/test/test_files_layernames.py b/fatamorgana/test/test_files_layernames.py index d430aaf..304835f 100644 --- a/fatamorgana/test/test_files_layernames.py +++ b/fatamorgana/test/test_files_layernames.py @@ -207,8 +207,8 @@ def elem_test_text(geometry: Sequence) -> None: def write_file_1(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_names_geom(buf) @@ -237,8 +237,8 @@ def test_file_1() -> None: def write_file_2(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_names_text(buf) @@ -267,8 +267,8 @@ def test_file_2() -> None: def write_file_3(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_names_text(buf, prefix=b'T') write_names_geom(buf, short=True) @@ -283,8 +283,8 @@ def write_file_3(buf: IO[bytes]) -> IO[bytes]: def write_file_4(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) diff --git a/fatamorgana/test/test_files_modals.py b/fatamorgana/test/test_files_modals.py index 9eac770..7b6662e 100644 --- a/fatamorgana/test/test_files_modals.py +++ b/fatamorgana/test/test_files_modals.py @@ -21,8 +21,8 @@ def base_tests(layout: OasisLayout) -> None: def write_file_1(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) diff --git a/fatamorgana/test/test_files_paths.py b/fatamorgana/test/test_files_paths.py index 3243a79..e54315d 100644 --- a/fatamorgana/test/test_files_paths.py +++ b/fatamorgana/test/test_files_paths.py @@ -27,8 +27,8 @@ def base_tests(layout: OasisLayout) -> None: def write_file_1(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) diff --git a/fatamorgana/test/test_files_placements.py b/fatamorgana/test/test_files_placements.py index 290ffee..2a718c0 100644 --- a/fatamorgana/test/test_files_placements.py +++ b/fatamorgana/test/test_files_placements.py @@ -34,8 +34,8 @@ def write_rectangle(buf: IO[bytes], pos: Tuple[int, int] = (300, -400)) -> None: def write_file_1(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) @@ -250,8 +250,8 @@ def test_file_1() -> None: def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: - ''' - ''' + """ + """ assert variant in (2, 3, 5, 7), 'Error in test definition!' buf.write(HEADER) @@ -516,8 +516,8 @@ def common_tests(layout: OasisLayout, variant: int) -> None: def write_file_4(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 3) # CELLNAME record (implicit id 0) @@ -595,8 +595,8 @@ def write_file_4(buf: IO[bytes]) -> IO[bytes]: def write_file_6(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) @@ -748,8 +748,8 @@ def test_file_6() -> None: def write_file_8(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) diff --git a/fatamorgana/test/test_files_polygons.py b/fatamorgana/test/test_files_polygons.py index f89a019..a3d9bfa 100644 --- a/fatamorgana/test/test_files_polygons.py +++ b/fatamorgana/test/test_files_polygons.py @@ -107,8 +107,8 @@ def common_tests(layout: OasisLayout) -> None: def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: - ''' - ''' + """ + """ assert variant in (1, 3), 'Error in test!!' buf.write(HEADER) @@ -376,8 +376,8 @@ def test_file_1() -> None: def write_file_2(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) diff --git a/fatamorgana/test/test_files_properties.py b/fatamorgana/test/test_files_properties.py index 0100318..433ed54 100644 --- a/fatamorgana/test/test_files_properties.py +++ b/fatamorgana/test/test_files_properties.py @@ -24,8 +24,8 @@ def base_tests(layout: OasisLayout) -> None: def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: - ''' - ''' + """ + """ include_repetitions = variant in (2, 5) def var_byte(buf, byte): @@ -355,8 +355,8 @@ def test_file_5() -> None: def write_file_3(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 10) # PROPSTRING (explicit id) @@ -580,8 +580,8 @@ def test_file_3() -> None: def write_file_4_6(buf: IO[bytes], variant: int) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 10) # PROPSTRING (explicit id) @@ -786,8 +786,8 @@ def write_file_4_6(buf: IO[bytes], variant: int) -> IO[bytes]: def test_file_4() -> None: - ''' - ''' + """ + """ buf = write_file_4_6(BytesIO(), 4) buf.seek(0) @@ -855,8 +855,8 @@ def test_file_4() -> None: def test_file_6() -> None: - ''' - ''' + """ + """ buf = write_file_4_6(BytesIO(), 6) buf.seek(0) @@ -928,8 +928,8 @@ def test_file_6() -> None: def write_file_7_8_9(buf: IO[bytes], variant: int) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 28) # PROPERTY record @@ -1059,8 +1059,8 @@ def test_file_7() -> None: def test_file_8() -> None: - ''' - ''' + """ + """ buf = write_file_7_8_9(BytesIO(), 8) buf.seek(0) @@ -1069,8 +1069,8 @@ def test_file_8() -> None: def test_file_9() -> None: - ''' - ''' + """ + """ buf = write_file_7_8_9(BytesIO(), 9) buf.seek(0) diff --git a/fatamorgana/test/test_files_rectangles.py b/fatamorgana/test/test_files_rectangles.py index a7ffdc7..82ec564 100644 --- a/fatamorgana/test/test_files_rectangles.py +++ b/fatamorgana/test/test_files_rectangles.py @@ -75,8 +75,8 @@ def base_tests(layout: OasisLayout) -> None: def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: - ''' - ''' + """ + """ assert variant in (1, 2), 'Error in test!!' buf.write(HEADER) diff --git a/fatamorgana/test/test_files_texts.py b/fatamorgana/test/test_files_texts.py index 2603691..60679ce 100644 --- a/fatamorgana/test/test_files_texts.py +++ b/fatamorgana/test/test_files_texts.py @@ -100,9 +100,9 @@ def common_tests(layout: OasisLayout) -> None: def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: - ''' + """ Single cell with explicit name 'XYZ' - ''' + """ assert variant in (1, 2, 5, 12), 'Error in test!!' buf.write(HEADER) @@ -461,10 +461,10 @@ def test_file_12() -> None: def write_file_3(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File with one textstring with explicit id, and one with an implicit id. Should fail. - ''' + """ buf.write(HEADER) write_uint(buf, 6) # TEXTSTRING record (explicit id) @@ -498,11 +498,11 @@ def test_file_3() -> None: def write_file_4(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File with a TEXT record that references a non-existent TEXTSTRING TODO add an optional check for valid references - ''' + """ buf.write(HEADER) write_uint(buf, 5) # TEXTSTRING record (implicit id 0) @@ -538,9 +538,9 @@ def test_file_4() -> None: def write_file_6(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File with TEXT record that uses an un-filled modal for the repetition - ''' + """ buf.write(HEADER) write_uint(buf, 5) # TEXTSTRING record (implicit id 0) @@ -571,9 +571,9 @@ def test_file_6() -> None: def write_file_7(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File with TEXT record that uses an un-filled modal for the layer - ''' + """ buf.write(HEADER) write_uint(buf, 5) # TEXTSTRING record (implicit id 0) @@ -602,9 +602,9 @@ def test_file_7() -> None: def write_file_8(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File with TEXT record that uses an un-filled modal for the datatype - ''' + """ buf.write(HEADER) write_uint(buf, 5) # TEXTSTRING record (implicit id 0) @@ -633,9 +633,9 @@ def test_file_8() -> None: def write_file_9(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File with TEXT record that uses a default modal for the x coordinate - ''' + """ buf.write(HEADER) write_uint(buf, 5) # TEXTSTRING record (implicit id 0) @@ -669,9 +669,9 @@ def test_file_9() -> None: def write_file_10(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File with TEXT record that uses a default modal for the y coordinate - ''' + """ buf.write(HEADER) write_uint(buf, 5) # TEXTSTRING record (implicit id 0) @@ -705,9 +705,9 @@ def test_file_10() -> None: def write_file_11(buf: IO[bytes]) -> IO[bytes]: - ''' + """ File with TEXT record that uses an un-filled modal for the text string - ''' + """ buf.write(HEADER) write_uint(buf, 5) # TEXTSTRING record (implicit id 0) diff --git a/fatamorgana/test/test_files_trapezoids.py b/fatamorgana/test/test_files_trapezoids.py index cea3123..4f47332 100644 --- a/fatamorgana/test/test_files_trapezoids.py +++ b/fatamorgana/test/test_files_trapezoids.py @@ -25,8 +25,8 @@ def base_tests(layout: OasisLayout) -> None: def write_file_1(buf: IO[bytes]) -> IO[bytes]: - ''' - ''' + """ + """ buf.write(HEADER) write_uint(buf, 14) # CELL record (explicit) From f87dc7d771693edf1dabaebb9a3744dd0877977c Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 17:56:43 -0700 Subject: [PATCH 19/40] use ii > 4 instead of 4 < ii --- fatamorgana/test/test_files_placements.py | 4 ++-- fatamorgana/test/test_files_properties.py | 4 ++-- fatamorgana/test/test_files_trapezoids.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fatamorgana/test/test_files_placements.py b/fatamorgana/test/test_files_placements.py index 2a718c0..7c5c500 100644 --- a/fatamorgana/test/test_files_placements.py +++ b/fatamorgana/test/test_files_placements.py @@ -202,7 +202,7 @@ def test_file_1() -> None: if ii < 3: assert pp.y == 400 * (ii + 1), msg - elif 7 <= ii: + elif ii >= 7: assert pp.y == 0, msg if ii < 4 or ii == 5: @@ -214,7 +214,7 @@ def test_file_1() -> None: assert pp.angle == 0, msg elif ii in (5, 6): assert pp.angle == 90, msg - elif 7 <= ii: + elif ii >= 7: assert pp.angle == 270, msg if ii < 7: diff --git a/fatamorgana/test/test_files_properties.py b/fatamorgana/test/test_files_properties.py index 433ed54..7dab690 100644 --- a/fatamorgana/test/test_files_properties.py +++ b/fatamorgana/test/test_files_properties.py @@ -823,7 +823,7 @@ def test_file_4() -> None: assert pp.x == [-300, 0, 0, 300, 700, 700, 700, 2000, 4000, 6000, 8000, 10000, 12000][ii], msg assert pp.y == [400, 200, 400, 400, 400, 1400, 2400, 0, 0, 0, 0, 0, 0][ii], msg - if ii == 4 or 6 <= ii: + if ii == 4 or ii >= 6: assert pp.flip, msg else: assert not pp.flip, msg @@ -892,7 +892,7 @@ def test_file_6() -> None: assert pp.x == [-300, 0, 0, 300, 700, 700, 700, 2000, 4000, 6000, 8000, 10000, 12000][ii], msg assert pp.y == [400, 400, 400, 400, 400, 1400, 2400, 0, 0, 0, 0, 0, 0][ii], msg - if ii == 4 or 6 <= ii: + if ii == 4 or ii >= 6: assert pp.flip, msg else: assert not pp.flip, msg diff --git a/fatamorgana/test/test_files_trapezoids.py b/fatamorgana/test/test_files_trapezoids.py index 4f47332..e57b8f7 100644 --- a/fatamorgana/test/test_files_trapezoids.py +++ b/fatamorgana/test/test_files_trapezoids.py @@ -209,7 +209,7 @@ def test_file_1() -> None: if ii in (0, 4): assert gg.delta_a == -20, msg - elif 8 <= ii: + elif ii >= 8: assert gg.delta_a == 0, msg else: assert gg.delta_a == 20, msg From 50117506378d719882cf7b743d876258933e1dea Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:00:32 -0700 Subject: [PATCH 20/40] improve type annotations in tests --- fatamorgana/test/build_testfiles.py | 3 ++- fatamorgana/test/test_files_cblocks.py | 2 +- fatamorgana/test/test_files_cells.py | 2 +- fatamorgana/test/test_files_circles.py | 2 +- fatamorgana/test/test_files_ctrapezoids.py | 2 +- fatamorgana/test/test_files_empty.py | 1 - fatamorgana/test/test_files_layernames.py | 6 +++--- fatamorgana/test/test_files_modals.py | 2 +- fatamorgana/test/test_files_paths.py | 4 ++-- fatamorgana/test/test_files_placements.py | 10 +++++----- fatamorgana/test/test_files_polygons.py | 6 +++--- fatamorgana/test/test_files_properties.py | 4 ++-- fatamorgana/test/test_files_rectangles.py | 8 ++++---- fatamorgana/test/test_files_texts.py | 2 +- fatamorgana/test/test_files_trapezoids.py | 2 +- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/fatamorgana/test/build_testfiles.py b/fatamorgana/test/build_testfiles.py index 649de3e..0f85fce 100644 --- a/fatamorgana/test/build_testfiles.py +++ b/fatamorgana/test/build_testfiles.py @@ -2,7 +2,8 @@ Build files equivalent to the test cases used by KLayout. """ -from typing import Callable, IO +from typing import IO +from collections.abc import Callable from . import ( diff --git a/fatamorgana/test/test_files_cblocks.py b/fatamorgana/test/test_files_cblocks.py index f4d32b5..18c76fa 100644 --- a/fatamorgana/test/test_files_cblocks.py +++ b/fatamorgana/test/test_files_cblocks.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr" from typing import IO from io import BytesIO diff --git a/fatamorgana/test/test_files_cells.py b/fatamorgana/test/test_files_cells.py index 40a6009..ba286a7 100644 --- a/fatamorgana/test/test_files_cells.py +++ b/fatamorgana/test/test_files_cells.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr" from typing import IO from io import BytesIO diff --git a/fatamorgana/test/test_files_circles.py b/fatamorgana/test/test_files_circles.py index b5d2cba..39e54a0 100644 --- a/fatamorgana/test/test_files_circles.py +++ b/fatamorgana/test/test_files_circles.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr" from typing import IO from io import BytesIO diff --git a/fatamorgana/test/test_files_ctrapezoids.py b/fatamorgana/test/test_files_ctrapezoids.py index b6f8bc0..c831146 100644 --- a/fatamorgana/test/test_files_ctrapezoids.py +++ b/fatamorgana/test/test_files_ctrapezoids.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr" from typing import IO from io import BytesIO diff --git a/fatamorgana/test/test_files_empty.py b/fatamorgana/test/test_files_empty.py index 1f9e6f3..a0fdbee 100644 --- a/fatamorgana/test/test_files_empty.py +++ b/fatamorgana/test/test_files_empty.py @@ -1,4 +1,3 @@ -# type: ignore from typing import IO from io import BytesIO import struct diff --git a/fatamorgana/test/test_files_layernames.py b/fatamorgana/test/test_files_layernames.py index 304835f..72e9af6 100644 --- a/fatamorgana/test/test_files_layernames.py +++ b/fatamorgana/test/test_files_layernames.py @@ -1,5 +1,5 @@ -# type: ignore -from typing import Sequence, IO +from typing import IO +from collections.abc import Sequence from io import BytesIO @@ -27,7 +27,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.cellnames assert len(layout.cells) == 1 - assert layout.cells[0].name.string == 'A' + assert layout.cells[0].name.string == 'A' # type: ignore assert not layout.cells[0].properties diff --git a/fatamorgana/test/test_files_modals.py b/fatamorgana/test/test_files_modals.py index 7b6662e..fddc576 100644 --- a/fatamorgana/test/test_files_modals.py +++ b/fatamorgana/test/test_files_modals.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr" from typing import IO from io import BytesIO diff --git a/fatamorgana/test/test_files_paths.py b/fatamorgana/test/test_files_paths.py index e54315d..1dc1def 100644 --- a/fatamorgana/test/test_files_paths.py +++ b/fatamorgana/test/test_files_paths.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr" from typing import IO from io import BytesIO @@ -182,7 +182,7 @@ def test_file_1() -> None: else: assert gg.half_width == 12, msg - assert len(gg.point_list) == 3, msg + assert len(gg.point_list) == 3, msg # type: ignore assert_equal(gg.point_list, [[150, 0], [0, 50], [-50, 0]], err_msg=msg) if ii >= 4: diff --git a/fatamorgana/test/test_files_placements.py b/fatamorgana/test/test_files_placements.py index 7c5c500..ce4c8aa 100644 --- a/fatamorgana/test/test_files_placements.py +++ b/fatamorgana/test/test_files_placements.py @@ -1,5 +1,5 @@ -# type: ignore -from typing import Tuple, IO, cast, List +# mypy: disable-error-code="union-attr" +from typing import IO, cast from io import BytesIO from numpy.testing import assert_equal @@ -22,7 +22,7 @@ def base_tests(layout: OasisLayout) -> None: assert not layout.layers -def write_rectangle(buf: IO[bytes], pos: Tuple[int, int] = (300, -400)) -> None: +def write_rectangle(buf: IO[bytes], pos: tuple[int, int] = (300, -400)) -> None: write_uint(buf, 20) # RECTANGLE record write_byte(buf, 0b0111_1011) # SWHX_YRDL write_uint(buf, 1) # layer @@ -174,7 +174,7 @@ def test_file_1() -> None: assert not layout.cells[1].properties assert not layout.cells[1].geometry - geometry = cast(List[Rectangle], layout.cells[0].geometry) + geometry = cast(list[Rectangle], layout.cells[0].geometry) assert len(geometry) == 1 assert geometry[0].layer == 1 assert geometry[0].datatype == 2 @@ -843,7 +843,7 @@ def test_file_8() -> None: assert not layout.cells[2].properties assert not layout.cells[2].placements - geometry = cast(List[Rectangle], layout.cells[2].geometry) + geometry = cast(list[Rectangle], layout.cells[2].geometry) assert len(geometry) == 1 assert geometry[0].layer == 1 assert geometry[0].datatype == 2 diff --git a/fatamorgana/test/test_files_polygons.py b/fatamorgana/test/test_files_polygons.py index a3d9bfa..7ac0102 100644 --- a/fatamorgana/test/test_files_polygons.py +++ b/fatamorgana/test/test_files_polygons.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr, arg-type" from typing import IO from io import BytesIO @@ -445,7 +445,7 @@ def test_file_3() -> None: for ii, gg in enumerate(geometry): msg = f'Fail on polygon {ii}' assert len(gg.properties) == 1, msg - assert gg.properties[0].name == 0, msg + assert gg.properties[0].name == 0, msg # type: ignore assert len(gg.properties[0].values) == 1, msg - assert gg.properties[0].values[0] * 5 == 1, msg + assert gg.properties[0].values[0] * 5 == 1, msg # type: ignore diff --git a/fatamorgana/test/test_files_properties.py b/fatamorgana/test/test_files_properties.py index 7dab690..98fdede 100644 --- a/fatamorgana/test/test_files_properties.py +++ b/fatamorgana/test/test_files_properties.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr, index, arg-type" from typing import IO from io import BytesIO @@ -28,7 +28,7 @@ def write_file_common(buf: IO[bytes], variant: int) -> IO[bytes]: """ include_repetitions = variant in (2, 5) - def var_byte(buf, byte): + def var_byte(buf: IO[bytes], byte: int) -> None: if include_repetitions: byte |= 0b0100 write_byte(buf, byte) diff --git a/fatamorgana/test/test_files_rectangles.py b/fatamorgana/test/test_files_rectangles.py index 82ec564..204b9b3 100644 --- a/fatamorgana/test/test_files_rectangles.py +++ b/fatamorgana/test/test_files_rectangles.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr" from typing import IO from io import BytesIO @@ -267,7 +267,7 @@ def test_file_2() -> None: prop = gg.properties[0] assert prop.name == 0, msg - assert len(prop.values) == 1, msg - assert prop.values[0].numerator == 1, msg - assert prop.values[0].denominator == 5, msg + assert len(prop.values) == 1, msg # type: ignore + assert prop.values[0].numerator == 1, msg # type: ignore + assert prop.values[0].denominator == 5, msg # type: ignore diff --git a/fatamorgana/test/test_files_texts.py b/fatamorgana/test/test_files_texts.py index 60679ce..0575618 100644 --- a/fatamorgana/test/test_files_texts.py +++ b/fatamorgana/test/test_files_texts.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr, index" from typing import IO from io import BytesIO diff --git a/fatamorgana/test/test_files_trapezoids.py b/fatamorgana/test/test_files_trapezoids.py index e57b8f7..262f449 100644 --- a/fatamorgana/test/test_files_trapezoids.py +++ b/fatamorgana/test/test_files_trapezoids.py @@ -1,4 +1,4 @@ -# type: ignore +# mypy: disable-error-code="union-attr" from typing import IO from io import BytesIO From 891007054f323bea7a34026fa46873f60be64be4 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:00:54 -0700 Subject: [PATCH 21/40] use pathlibto validate path --- fatamorgana/test/build_testfiles.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fatamorgana/test/build_testfiles.py b/fatamorgana/test/build_testfiles.py index 0f85fce..50511ba 100644 --- a/fatamorgana/test/build_testfiles.py +++ b/fatamorgana/test/build_testfiles.py @@ -4,6 +4,7 @@ Build files equivalent to the test cases used by KLayout. from typing import IO from collections.abc import Callable +from pathlib import Path from . import ( @@ -16,8 +17,8 @@ from . import ( def build_file(num: str, func: Callable[[IO[bytes]], IO[bytes]]) -> None: - with open('t' + num + '.oas', 'wb') as f: - func(f) + with Path('t' + num + '.oas').open('wb') as ff: + func(ff) def write_all_files() -> None: From dc9ed8e79464760dd6f3f0e553b7f124aa71a634 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:06:59 -0700 Subject: [PATCH 22/40] flatten and simplify conditionals --- fatamorgana/basic.py | 93 +++++++++----------- fatamorgana/main.py | 3 +- fatamorgana/records.py | 99 ++++++++++------------ fatamorgana/test/test_files_ctrapezoids.py | 11 ++- 4 files changed, 93 insertions(+), 113 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 6010d23..66ba118 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -950,7 +950,7 @@ class OctangularDelta: sign = self.octangle & 0x02 > 0 xy[axis] = self.proj_mag * (1 - 2 * sign) return xy - else: + else: # noqa: RET505 yn = (self.octangle & 0x02) > 0 xyn = (self.octangle & 0x01) > 0 ys = 1 - 2 * yn @@ -1097,10 +1097,9 @@ class Delta: """ if self.x == 0 or self.y == 0 or abs(self.x) == abs(self.y): return write_uint(stream, OctangularDelta(self.x, self.y).as_uint() << 1) - else: - size = write_uint(stream, (encode_sint(self.x) << 1) | 0x01) - size += write_uint(stream, encode_sint(self.y)) - return size + size = write_uint(stream, (encode_sint(self.x) << 1) | 0x01) + size += write_uint(stream, encode_sint(self.y)) + return size def __eq__(self, other: Any) -> bool: return hasattr(other, 'as_list') and self.as_list() == other.as_list() @@ -1125,12 +1124,11 @@ def read_repetition(stream: IO[bytes]) -> repetition_t: rtype = read_uint(stream) if rtype == 0: return ReuseRepetition.read(stream, rtype) - elif rtype in (1, 2, 3, 8, 9): + if rtype in (1, 2, 3, 8, 9): return GridRepetition.read(stream, rtype) - elif rtype in (4, 5, 6, 7, 10, 11): + if rtype in (4, 5, 6, 7, 10, 11): return ArbitraryRepetition.read(stream, rtype) - else: - raise InvalidDataError(f'Unexpected repetition type: {rtype}') + raise InvalidDataError(f'Unexpected repetition type: {rtype}') def write_repetition(stream: IO[bytes], repetition: repetition_t) -> int: @@ -1311,7 +1309,7 @@ class GridRepetition: size = write_uint(stream, 9) size += write_uint(stream, self.a_count - 2) size += Delta(*self.a_vector).write(stream) - else: + else: # noqa: PLR5501 if self.a_vector[1] == 0 and self.b_vector[0] == 0: size = write_uint(stream, 1) size += write_uint(stream, self.a_count - 2) @@ -1637,11 +1635,10 @@ def write_point_list( h_first = False v_first = False break - else: - if point[1] != previous[1] or point[0] == previous[0]: - h_first = False - v_first = False - break + elif point[1] != previous[1] or point[0] == previous[0]: + h_first = False + v_first = False + break previous = point # If one of h_first or v_first, write a bunch of 1-deltas @@ -1650,7 +1647,7 @@ def write_point_list( size += write_uint(stream, len(points)) size += sum(write_sint(stream, x + y) for x, y in points) return size - elif v_first: + if v_first: size = write_uint(stream, 1) size += write_uint(stream, len(points)) size += sum(write_sint(stream, x + y) for x, y in points) @@ -1773,30 +1770,29 @@ def read_property_value(stream: IO[bytes]) -> property_value_t: prop_type = read_uint(stream) if 0 <= prop_type <= 7: return read_real(stream, prop_type) - elif prop_type == 8: + if prop_type == 8: return read_uint(stream) - elif prop_type == 9: + if prop_type == 9: return read_sint(stream) - elif prop_type == 10: + if prop_type == 10: return AString.read(stream) - elif prop_type == 11: + if prop_type == 11: return read_bstring(stream) - elif prop_type == 12: + if prop_type == 12: return NString.read(stream) - elif prop_type == 13: + if prop_type == 13: ref_type = AString ref = read_uint(stream) return PropStringReference(ref, ref_type) - elif prop_type == 14: + if prop_type == 14: ref_type = bytes ref = read_uint(stream) return PropStringReference(ref, ref_type) - elif prop_type == 15: + if prop_type == 15: ref_type = NString ref = read_uint(stream) return PropStringReference(ref, ref_type) - else: - raise InvalidDataError(f'Invalid property type: {prop_type}') + raise InvalidDataError(f'Invalid property type: {prop_type}') def write_property_value( @@ -1883,17 +1879,16 @@ def read_interval(stream: IO[bytes]) -> tuple[int | None, int | None]: interval_type = read_uint(stream) if interval_type == 0: return None, None - elif interval_type == 1: + if interval_type == 1: return None, read_uint(stream) - elif interval_type == 2: + if interval_type == 2: return read_uint(stream), None - elif interval_type == 3: + if interval_type == 3: v = read_uint(stream) return v, v - elif interval_type == 4: + if interval_type == 4: return read_uint(stream), read_uint(stream) - else: - raise InvalidDataError(f'Unrecognized interval type: {interval_type}') + raise InvalidDataError(f'Unrecognized interval type: {interval_type}') def write_interval( @@ -1916,18 +1911,15 @@ def write_interval( if min_bound is None: if max_bound is None: return write_uint(stream, 0) - else: - return write_uint(stream, 1) + write_uint(stream, max_bound) - else: - if max_bound is None: - return write_uint(stream, 2) + write_uint(stream, min_bound) - elif min_bound == max_bound: - return write_uint(stream, 3) + write_uint(stream, min_bound) - else: - size = write_uint(stream, 4) - size += write_uint(stream, min_bound) - size += write_uint(stream, max_bound) - return size + return write_uint(stream, 1) + write_uint(stream, max_bound) + if max_bound is None: + return write_uint(stream, 2) + write_uint(stream, min_bound) + if min_bound == max_bound: + return write_uint(stream, 3) + write_uint(stream, min_bound) + size = write_uint(stream, 4) + size += write_uint(stream, min_bound) + size += write_uint(stream, max_bound) + return size class OffsetEntry: @@ -2190,9 +2182,7 @@ class Validation: checksum_type = read_uint(stream) if checksum_type == 0: checksum = None - elif checksum_type == 1: - checksum = read_u32(stream) - elif checksum_type == 2: + elif checksum_type in (1, 2): checksum = read_u32(stream) else: raise InvalidDataError('Invalid validation type!') @@ -2214,14 +2204,13 @@ class Validation: """ if self.checksum_type == 0: return write_uint(stream, 0) - elif self.checksum is None: + if self.checksum is None: raise InvalidDataError(f'Checksum is empty but type is {self.checksum_type}') - elif self.checksum_type == 1: + if self.checksum_type == 1: return write_uint(stream, 1) + write_u32(stream, self.checksum) - elif self.checksum_type == 2: + if self.checksum_type == 2: return write_uint(stream, 2) + write_u32(stream, self.checksum) - else: - raise InvalidDataError(f'Unrecognized checksum type: {self.checksum_type}') + raise InvalidDataError(f'Unrecognized checksum type: {self.checksum_type}') def __repr__(self) -> str: return f'Validation(type: {self.checksum_type} sum: {self.checksum})' diff --git a/fatamorgana/main.py b/fatamorgana/main.py index 978d842..317378c 100644 --- a/fatamorgana/main.py +++ b/fatamorgana/main.py @@ -193,8 +193,7 @@ class OasisLayout: if record_id == 1: if file_state.started: raise InvalidRecordError('Duplicate Start record') - else: - file_state.started = True + file_state.started = True if record_id == 2 and file_state.within_cblock: raise InvalidRecordError('End within CBlock') diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 87e4da8..0de9739 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -274,10 +274,9 @@ def read_refname( """ if not is_present: return None - elif is_reference: + if is_reference: return read_uint(stream) - else: - return NString.read(stream) + return NString.read(stream) def read_refstring( @@ -299,10 +298,9 @@ def read_refstring( """ if not is_present: return None - elif is_reference: + if is_reference: return read_uint(stream) - else: - return AString.read(stream) + return AString.read(stream) class Pad(Record): @@ -994,32 +992,33 @@ class Property(Record): def write(self, stream: IO[bytes]) -> int: if self.is_standard is None and self.values is None and self.name is None: return write_uint(stream, 29) + + if self.is_standard is None: + raise InvalidDataError('Property has value or name, but no is_standard flag!') + + if self.values is not None: + value_count = len(self.values) + vv = 0 + uu = 0x0f if value_count >= 0x0f else value_count else: - if self.is_standard is None: - raise InvalidDataError('Property has value or name, but no is_standard flag!') - if self.values is not None: - value_count = len(self.values) - vv = 0 - uu = 0x0f if value_count >= 0x0f else value_count + vv = 1 + uu = 0 + + cc = self.name is not None + nn = cc and isinstance(self.name, int) + ss = self.is_standard + + size = write_uint(stream, 28) + size += write_byte(stream, (uu << 4) | (vv << 3) | (cc << 2) | (nn << 1) | ss) + if cc: + if nn: + size += write_uint(stream, self.name) # type: ignore else: - vv = 1 - uu = 0 - - cc = self.name is not None - nn = cc and isinstance(self.name, int) - ss = self.is_standard - - size = write_uint(stream, 28) - size += write_byte(stream, (uu << 4) | (vv << 3) | (cc << 2) | (nn << 1) | ss) - if cc: - if nn: - size += write_uint(stream, self.name) # type: ignore - else: - size += self.name.write(stream) # type: ignore - if not vv: - if uu == 0x0f: - size += write_uint(stream, len(self.values)) # type: ignore - size += sum(write_property_value(stream, pp) for pp in self.values) # type: ignore + size += self.name.write(stream) # type: ignore + if not vv: + if uu == 0x0f: + size += write_uint(stream, len(self.values)) # type: ignore + size += sum(write_property_value(stream, pp) for pp in self.values) # type: ignore return size @@ -1736,9 +1735,8 @@ class Polygon(Record, GeometryMixin): self.point_list = point_list self.properties = [] if properties is None else properties - if point_list is not None: - if len(point_list) < 3: - warn('Polygon with < 3 points') + if point_list is not None and len(point_list) < 3: + warn('Polygon with < 3 points', stacklevel=2) def get_point_list(self) -> point_list_t: return verify_modal(self.point_list) @@ -1921,14 +1919,13 @@ class Path(Record, GeometryMixin): def get_pathext(ext_scheme: int) -> pathextension_t | None: if ext_scheme == 0: return None - elif ext_scheme == 1: + if ext_scheme == 1: return PathExtensionScheme.Flush, None - elif ext_scheme == 2: + if ext_scheme == 2: return PathExtensionScheme.HalfWidth, None - elif ext_scheme == 3: + if ext_scheme == 3: return PathExtensionScheme.Arbitrary, read_sint(stream) - else: - raise InvalidDataError(f'Invalid ext_scheme: {ext_scheme}') + raise InvalidDataError(f'Invalid ext_scheme: {ext_scheme}') optional['extension_start'] = get_pathext(scheme_start) optional['extension_end'] = get_pathext(scheme_end) @@ -2066,9 +2063,8 @@ class Trapezoid(Record, GeometryMixin): if self.is_vertical: if height is not None and delta_b - delta_a > height: raise InvalidDataError(f'Trapezoid: h < delta_b - delta_a ({height} < {delta_b} - {delta_a})') - else: - if width is not None and delta_b - delta_a > width: - raise InvalidDataError(f'Trapezoid: w < delta_b - delta_a ({width} < {delta_b} - {delta_a})') + elif width is not None and delta_b - delta_a > width: + raise InvalidDataError(f'Trapezoid: w < delta_b - delta_a ({width} < {delta_b} - {delta_a})') def get_is_vertical(self) -> bool: return verify_modal(self.is_vertical) @@ -2392,7 +2388,7 @@ class CTrapezoid(Record, GeometryMixin): raise InvalidDataError(f'CTrapezoid has spurious height entry: {height}') if width is not None and height is not None: - if ctrapezoid_type in range(0, 4) and width < height: + if ctrapezoid_type in range(0, 4) and width < height: # noqa: PIE808 raise InvalidDataError(f'CTrapezoid has width < height ({width} < {height})') if ctrapezoid_type in range(4, 8) and width < 2 * height: raise InvalidDataError(f'CTrapezoid has width < 2*height ({width} < 2 * {height})') @@ -2401,7 +2397,7 @@ class CTrapezoid(Record, GeometryMixin): if ctrapezoid_type in range(12, 16) and 2 * width > height: raise InvalidDataError(f'CTrapezoid has 2*width > height ({width} > 2 * {height})') - if ctrapezoid_type is not None and ctrapezoid_type not in range(0, 26): + if ctrapezoid_type is not None and ctrapezoid_type not in range(0, 26): # noqa: PIE808 raise InvalidDataError(f'CTrapezoid has invalid type: {ctrapezoid_type}') @@ -2532,8 +2528,7 @@ def adjust_repetition(record, modals: Modals) -> None: if isinstance(record.repetition, ReuseRepetition): if modals.repetition is None: raise InvalidDataError('Unfillable repetition') - else: - record.repetition = copy.copy(modals.repetition) + record.repetition = copy.copy(modals.repetition) else: modals.repetition = copy.copy(record.repetition) @@ -2679,20 +2674,18 @@ def dedup_coordinates(record, modals: Modals, mx_field: str, my_field: str) -> N if modals.xy_relative: record.x -= mx setattr(modals, mx_field, record.x) + elif record.x == mx: + record.x = None else: - if record.x == mx: - record.x = None - else: - setattr(modals, mx_field, record.x) + setattr(modals, mx_field, record.x) if record.y is not None: my = getattr(modals, my_field) if modals.xy_relative: record.y -= my setattr(modals, my_field, record.y) + elif record.y == my: + record.y = None else: - if record.y == my: - record.y = None - else: - setattr(modals, my_field, record.y) + setattr(modals, my_field, record.y) diff --git a/fatamorgana/test/test_files_ctrapezoids.py b/fatamorgana/test/test_files_ctrapezoids.py index c831146..d0429bf 100644 --- a/fatamorgana/test/test_files_ctrapezoids.py +++ b/fatamorgana/test/test_files_ctrapezoids.py @@ -135,13 +135,12 @@ def test_file_1() -> None: assert gg.width == [250, None][is_ctrapz], msg elif ct_type in range(22, 24) or ct_type == 25: assert gg.height == [100, None][is_ctrapz], msg + elif ct_type < 8 or 16 <= ct_type < 25 or ct_type >= 26: + assert gg.width == 250, msg + assert gg.height == 100, msg else: - if ct_type < 8 or 16 <= ct_type < 25 or 26 <= ct_type: - assert gg.width == 250, msg - assert gg.height == 100, msg - else: - assert gg.width == 100, msg - assert gg.height == 250, msg + assert gg.width == 100, msg + assert gg.height == 250, msg elif ii < 3 and ii % 2: assert gg.ctrapezoid_type == 24, msg elif ii == 55: From 691ce03150f80933f9a3063540a1f04e4dc1180c Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:08:16 -0700 Subject: [PATCH 23/40] use strict zip --- fatamorgana/basic.py | 4 ++-- fatamorgana/records.py | 16 ++++++++-------- fatamorgana/test/test_files_ctrapezoids.py | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 66ba118..f72000d 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -1485,13 +1485,13 @@ class ArbitraryRepetition: size = write_uint(stream, 10) size += write_uint(stream, len(self.x_displacements) - 1) size += sum(Delta(x, y).write(stream) - for x, y in zip(self.x_displacements, self.y_displacements)) + for x, y in zip(self.x_displacements, self.y_displacements, strict=True)) else: size = write_uint(stream, 11) size += write_uint(stream, len(self.x_displacements) - 1) size += write_uint(stream, gcd) size += sum(Delta(x // gcd, y // gcd).write(stream) - for x, y in zip(self.x_displacements, self.y_displacements)) + for x, y in zip(self.x_displacements, self.y_displacements, strict=True)) return size def __eq__(self, other: Any) -> bool: diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 0de9739..1e16cbf 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -2632,22 +2632,22 @@ def dedup_field(record, r_field: str, modals: Modals, m_field: str) -> None: Args: InvalidDataError: if both fields are `None` """ - r = getattr(record, r_field) - m = getattr(modals, m_field) - if r is not None: + rr = getattr(record, r_field) + mm = getattr(modals, m_field) + if rr is not None: if m_field in ('polygon_point_list', 'path_point_list'): if _USE_NUMPY: - equal = numpy.array_equal(m, r) + equal = numpy.array_equal(mm, rr) else: - equal = (m is not None) and all(tuple(mm) == tuple(rr) for mm, rr in zip(m, r)) + equal = (mm is not None) and all(tuple(mmm) == tuple(rrr) for mmm, rrr in zip(mm, rr, strict=True)) else: - equal = (m is not None) and m == r + equal = (mm is not None) and mm == rr if equal: setattr(record, r_field, None) else: - setattr(modals, m_field, r) - elif m is None: + setattr(modals, m_field, rr) + elif mm is None: raise InvalidDataError('Unfillable field') diff --git a/fatamorgana/test/test_files_ctrapezoids.py b/fatamorgana/test/test_files_ctrapezoids.py index d0429bf..37fc80f 100644 --- a/fatamorgana/test/test_files_ctrapezoids.py +++ b/fatamorgana/test/test_files_ctrapezoids.py @@ -61,7 +61,7 @@ def write_file_1(buf: IO[bytes]) -> IO[bytes]: + [0b11, 0b10] ) - for t, (x, x_en) in enumerate(zip(wh, wh_en)): + for t, (x, x_en) in enumerate(zip(wh, wh_en, strict=True)): write_uint(buf, 26) # CTRAPEZOID record write_byte(buf, 0b1000_1011 | (x_en << 5)) # TWHX_YRDL write_uint(buf, 1) # layer From 8e451c64db8f9671f9407466a81f7f81d442a4c8 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:08:55 -0700 Subject: [PATCH 24/40] improve type annotations --- fatamorgana/basic.py | 9 +++++---- fatamorgana/main.py | 2 +- fatamorgana/records.py | 39 ++++++++++++++++++++++++--------------- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index f72000d..fcd5d0b 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -344,7 +344,7 @@ def read_bstring(stream: IO[bytes]) -> bytes: return _read(stream, length) -def write_bstring(stream: IO[bytes], bstring: bytes): +def write_bstring(stream: IO[bytes], bstring: bytes) -> int: """ Write a binary string to the stream. See `read_bstring()` for format details. @@ -1194,7 +1194,8 @@ class GridRepetition: a_vector: Sequence[int], a_count: int, b_vector: Sequence[int] | None = None, - b_count: int | None = None): + b_count: int | None = None, + ) -> None: """ Args: a_vector: First lattice vector, of the form `[x, y]`. @@ -1828,7 +1829,7 @@ def write_property_value( else: size = write_uint(stream, 8) size += write_uint(stream, value) - elif isinstance(value, (Fraction, float, int)): + elif isinstance(value, Fraction | float | int): size = write_real(stream, value, force_float32) elif isinstance(value, AString): size = write_uint(stream, 10) @@ -2229,7 +2230,7 @@ def write_magic_bytes(stream: IO[bytes]) -> int: return stream.write(MAGIC_BYTES) -def read_magic_bytes(stream: IO[bytes]): +def read_magic_bytes(stream: IO[bytes]) -> None: """ Read the magic byte sequence from a stream. Raise an `InvalidDataError` if it was not found. diff --git a/fatamorgana/main.py b/fatamorgana/main.py index 317378c..74c37aa 100644 --- a/fatamorgana/main.py +++ b/fatamorgana/main.py @@ -421,7 +421,7 @@ class Cell: placements: list[records.Placement] | None = None, geometry: list[records.geometry_t] | None = None, ) -> None: - self.name = name if isinstance(name, (NString, int)) else NString(name) + self.name = name if isinstance(name, NString | int) else NString(name) self.properties = [] if properties is None else properties self.placements = [] if placements is None else placements self.geometry = [] if geometry is None else geometry diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 1e16cbf..88863a7 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -10,7 +10,7 @@ Higher-level code (e.g. monitoring for combinations of records with parse, or code for dealing with nested records in a CBlock) should live in main.py instead. """ -from typing import Any, TypeVar, IO, Union +from typing import Any, TypeVar, IO, Union, Protocol from collections.abc import Sequence from abc import ABCMeta, abstractmethod import copy @@ -227,6 +227,15 @@ class Record(metaclass=ABCMeta): return f'{self.__class__}: ' + pprint.pformat(self.__dict__) +class HasRepetition(Protocol): + repetition: repetition_t | None + + +class HasXY(Protocol): + x: int | None + y: int | None + + class GeometryMixin(metaclass=ABCMeta): """ Mixin defining common functions for geometry records @@ -465,10 +474,10 @@ class End(Record): self.validation = validation self.offset_table = offset_table - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: pass - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: pass @staticmethod @@ -703,10 +712,10 @@ class PropName(Record): self.nstring = NString(nstring) self.reference_number = reference_number - def merge_with_modals(self, modals: Modals): + def merge_with_modals(self, modals: Modals) -> None: modals.reset() - def deduplicate_with_modals(self, modals: Modals): + def deduplicate_with_modals(self, modals: Modals) -> None: modals.reset() @staticmethod @@ -931,7 +940,7 @@ class Property(Record): is_standard: `True` if this is a standard property. `None` to use modal. Default `None`. """ - if isinstance(name, (NString, int)) or name is None: + if isinstance(name, NString | int) or name is None: self.name = name else: self.name = NString(name) @@ -1255,7 +1264,7 @@ class Cell(Record): Args: name: `NString`, or an int specifying a `CellName` reference number. """ - self.name = name if isinstance(name, (int, NString)) else NString(name) + self.name = name if isinstance(name, int | NString) else NString(name) def merge_with_modals(self, modals: Modals) -> None: modals.reset() @@ -1338,7 +1347,7 @@ class Placement(Record): self.flip = flip self.magnification = magnification self.angle = angle - if isinstance(name, (int, NString)) or name is None: + if isinstance(name, int | NString) or name is None: self.name = name else: self.name = NString(name) @@ -1474,7 +1483,7 @@ class Text(Record, GeometryMixin): self.x = x self.y = y self.repetition = repetition - if isinstance(string, (AString, int)) or string is None: + if isinstance(string, int | AString) or string is None: self.string = string else: self.string = AString(string) @@ -2512,7 +2521,7 @@ class Circle(Record, GeometryMixin): return size -def adjust_repetition(record, modals: Modals) -> None: +def adjust_repetition(record: HasRepetition, modals: Modals) -> None: """ Merge the record's repetition entry with the one in the modals @@ -2533,7 +2542,7 @@ def adjust_repetition(record, modals: Modals) -> None: modals.repetition = copy.copy(record.repetition) -def adjust_field(record, r_field: str, modals: Modals, m_field: str) -> None: +def adjust_field(record: Record, r_field: str, modals: Modals, m_field: str) -> None: """ Merge `record.r_field` with `modals.m_field` @@ -2557,7 +2566,7 @@ def adjust_field(record, r_field: str, modals: Modals, m_field: str) -> None: raise InvalidDataError(f'Unfillable field: {m_field}') -def adjust_coordinates(record, modals: Modals, mx_field: str, my_field: str) -> None: +def adjust_coordinates(record: HasXY, modals: Modals, mx_field: str, my_field: str) -> None: """ Merge `record.x` and `record.y` with `modals.mx_field` and `modals.my_field`, taking into account the value of `modals.xy_relative`. @@ -2591,7 +2600,7 @@ def adjust_coordinates(record, modals: Modals, mx_field: str, my_field: str) -> # TODO: Clarify the docs on the dedup_* functions -def dedup_repetition(record, modals: Modals) -> None: +def dedup_repetition(record: HasRepetition, modals: Modals) -> None: """ Deduplicate the record's repetition entry with the one in the modals. Update the one in the modals if they are different. @@ -2618,7 +2627,7 @@ def dedup_repetition(record, modals: Modals) -> None: modals.repetition = record.repetition -def dedup_field(record, r_field: str, modals: Modals, m_field: str) -> None: +def dedup_field(record: Record, r_field: str, modals: Modals, m_field: str) -> None: """ Deduplicate `record.r_field` using `modals.m_field` Update the `modals.m_field` if they are different. @@ -2651,7 +2660,7 @@ def dedup_field(record, r_field: str, modals: Modals, m_field: str) -> None: raise InvalidDataError('Unfillable field') -def dedup_coordinates(record, modals: Modals, mx_field: str, my_field: str) -> None: +def dedup_coordinates(record: HasXY, modals: Modals, mx_field: str, my_field: str) -> None: """ Deduplicate `record.x` and `record.y` using `modals.mx_field` and `modals.my_field`, taking into account the value of `modals.xy_relative`. From 1252edb7b54290e9af2b9cb12b542741b8fb8225 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:09:01 -0700 Subject: [PATCH 25/40] add missing asserts --- fatamorgana/test/test_files_texts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fatamorgana/test/test_files_texts.py b/fatamorgana/test/test_files_texts.py index 0575618..8980868 100644 --- a/fatamorgana/test/test_files_texts.py +++ b/fatamorgana/test/test_files_texts.py @@ -30,8 +30,8 @@ def common_tests(layout: OasisLayout) -> None: geometry = layout.cells[0].geometry - geometry[0].layer == 1 - geometry[0].datatype == 2 + assert geometry[0].layer == 1 + assert geometry[0].datatype == 2 for ii, gg in enumerate(geometry[1:]): assert gg.layer == 2, f'textstring #{ii + 1}' assert gg.datatype == 1, f'textstring #{ii + 1}' From 3ee1c03f66e2a586c4d62f90408ed11b531a2433 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:09:20 -0700 Subject: [PATCH 26/40] improve error handling --- fatamorgana/main.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fatamorgana/main.py b/fatamorgana/main.py index 74c37aa..d0f5c29 100644 --- a/fatamorgana/main.py +++ b/fatamorgana/main.py @@ -163,11 +163,10 @@ class OasisLayout: """ try: record_id = read_uint(stream) - except EOFError as e: + except EOFError: if file_state.within_cblock: return True - else: - raise e + raise logger.info(f'read_record of type {record_id} at position 0x{stream.tell():x}') @@ -203,7 +202,7 @@ class OasisLayout: file_state.within_cell = False elif record_id in range(15, 28) or record_id in (32, 33): if not file_state.within_cell: - raise Exception('Geometry outside Cell') + raise InvalidRecordError('Geometry outside Cell') elif record_id in (13, 14): file_state.within_cell = True else: From d3ba2ca2af8cd1a23bf01ebc9e847e7fc19e6f85 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:09:36 -0700 Subject: [PATCH 27/40] warn at higher stacklevel --- fatamorgana/basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index fcd5d0b..315e377 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -1221,7 +1221,7 @@ class GridRepetition: if b_count < 2: b_count = None b_vector = None - warnings.warn('Removed b_count and b_vector since b_count == 1') + warnings.warn('Removed b_count and b_vector since b_count == 1', stacklevel=2) if a_count < 2: raise InvalidDataError(f'Repetition has too-small a_count: {a_count}') From 37bac2af0d2adef3d0bb3ab555818b18a5ec6cf9 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:09:47 -0700 Subject: [PATCH 28/40] simplify a comparison --- fatamorgana/basic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 315e377..fee40dc 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -1342,7 +1342,7 @@ class GridRepetition: return True if self.b_vector is None or other.b_vector is None: return False - if any(self.b_vector[ii] != other.b_vector[ii] for ii in range(2)): + if any(self.b_vector[ii] != other.b_vector[ii] for ii in range(2)): # noqa: SIM103 return False return True @@ -1580,7 +1580,7 @@ def read_point_list( assert (dx == 0) or (dy == 0) close_points = [[-dx, -dy]] elif list_type == 3: - assert (dx == 0) or (dy == 0) or (dx == dy) or (dx == -dy) + assert 0 in (dx, dy) or dx in (dy, -dy) close_points = [[-dx, -dy]] else: close_points = [[-dx, -dy]] From f4866fb2bb4f228b395905ee87dbe1e7dc2e3581 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:10:05 -0700 Subject: [PATCH 29/40] add ruff config --- pyproject.toml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 3e6d0d5..785382b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,3 +54,36 @@ path = "fatamorgana/__init__.py" [project.optional-dependencies] numpy = ["numpy~=1.21"] + +[tool.ruff] +exclude = [ + ".git", + "dist", + ] +line-length = 145 +indent-width = 4 +lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" +lint.select = [ + "NPY", "E", "F", "W", "B", "ANN", "UP", "SLOT", "SIM", "LOG", + "C4", "ISC", "PIE", "PT", "RET", "TCH", "PTH", "INT", + "ARG", "PL", "R", "TRY", + "G010", "G101", "G201", "G202", + "Q002", "Q003", "Q004", + ] +lint.ignore = [ + #"ANN001", # No annotation + "ANN002", # *args + "ANN003", # **kwargs + "ANN401", # Any + "ANN101", # self: Self + "SIM108", # single-line if / else assignment + "RET504", # x=y+z; return x + "PIE790", # unnecessary pass + "ISC003", # non-implicit string concatenation + "C408", # dict(x=y) instead of {'x': y} + "PLR09", # Too many xxx + "PLR2004", # magic number + "PLC0414", # import x as x + "TRY003", # Long exception message + ] + From 19324ee1473226a0113814972b406e9b3dae7848 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:10:24 -0700 Subject: [PATCH 30/40] bump minimum versions and allow numpy 2.0 --- README.md | 2 +- pyproject.toml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b7aa3d8..350a0d0 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ ## Installation **Dependencies:** -* python >=3.10 +* python >=3.11 * (optional) numpy diff --git a/pyproject.toml b/pyproject.toml index 785382b..c91c0d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ classifiers = [ "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", ] -requires-python = ">=3.10" +requires-python = ">=3.11" dynamic = ["version"] dependencies = [ ] @@ -53,7 +53,8 @@ dependencies = [ path = "fatamorgana/__init__.py" [project.optional-dependencies] -numpy = ["numpy~=1.21"] +numpy = ["numpy>=1.26"] + [tool.ruff] exclude = [ From cc08efcf17028cd6fbd953849ac2024658475d24 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:20:47 -0700 Subject: [PATCH 31/40] update python version in comment --- fatamorgana/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fatamorgana/__init__.py b/fatamorgana/__init__.py index 7de7472..b8e426b 100644 --- a/fatamorgana/__init__.py +++ b/fatamorgana/__init__.py @@ -15,7 +15,7 @@ numpy to speed up reading/writing. Dependencies: - - Python 3.8 or later + - Python 3.11 or later - numpy (optional, faster but no additional functionality) To get started, try: From 968392a4a32956a6b85112673908516249f1a021 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Mon, 29 Jul 2024 18:21:52 -0700 Subject: [PATCH 32/40] bump version number to v0.13 Main changes are numpy 2.0 compatibility and improved type annotations --- fatamorgana/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fatamorgana/__init__.py b/fatamorgana/__init__.py index b8e426b..27c9c74 100644 --- a/fatamorgana/__init__.py +++ b/fatamorgana/__init__.py @@ -47,5 +47,5 @@ from .basic import ( __author__ = 'Jan Petykiewicz' -__version__ = '0.12' +__version__ = '0.13' version = __version__ From 12debf0b02beb985e6223c15d0980e22ac55f100 Mon Sep 17 00:00:00 2001 From: jan Date: Tue, 30 Dec 2025 02:54:45 -0800 Subject: [PATCH 33/40] update tags --- pyproject.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c91c0d1..9c149ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,15 +34,14 @@ keywords = [ ] classifiers = [ "Programming Language :: Python :: 3", - "Development Status :: 3 - Alpha", - "Environment :: Other Environment", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: Manufacturing", "Intended Audience :: Science/Research", "License :: OSI Approved :: GNU Affero General Public License v3", - "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", + "Topic :: File Formats", ] requires-python = ">=3.11" dynamic = ["version"] From 0503ceb7255a1b4b596acf54932ca9dfe5b191e7 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sun, 15 Feb 2026 15:11:25 -0800 Subject: [PATCH 34/40] [Path] fix Path writing the wrong record type --- fatamorgana/records.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fatamorgana/records.py b/fatamorgana/records.py index 88863a7..c7bacc1 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -1960,7 +1960,7 @@ class Path(Record, GeometryMixin): dd = self.datatype is not None ll = self.layer is not None - size = write_uint(stream, 21) + size = write_uint(stream, 22) size += write_bool_byte(stream, (ee, ww, pp, xx, yy, rr, dd, ll)) if ll: size += write_uint(stream, self.layer) # type: ignore From a82c555cda52d095096029a1376dff15a01bfd73 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sun, 15 Feb 2026 15:45:20 -0800 Subject: [PATCH 35/40] [Polygon] fix overeager warning --- fatamorgana/records.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fatamorgana/records.py b/fatamorgana/records.py index c7bacc1..e298ca9 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -1744,7 +1744,7 @@ class Polygon(Record, GeometryMixin): self.point_list = point_list self.properties = [] if properties is None else properties - if point_list is not None and len(point_list) < 3: + if point_list is not None and len(point_list) < 2: warn('Polygon with < 3 points', stacklevel=2) def get_point_list(self) -> point_list_t: From 7f7431f018f3e16440f77f6d7c5f5dc4dcb66526 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sun, 15 Feb 2026 15:46:45 -0800 Subject: [PATCH 36/40] [Polygon / Path] clarify docs --- fatamorgana/records.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fatamorgana/records.py b/fatamorgana/records.py index e298ca9..f4d898c 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -1717,8 +1717,8 @@ class Polygon(Record, GeometryMixin): repetition: repetition_t | None point_list: point_list_t | None """ - List of offsets from the initial vertex (x, y) to the remaining - vertices, `[[dx0, dy0], [dx1, dy1], ...]`. + List of offsets between consecutive vertices, starting from the initial + vertex (x, y): `[[dx0, dy0], [dx1, dy1], ...]`. The list is an implicitly closed path, vertices are [int, int]. The initial vertex is located at (x, y) and is not represented in `point_list`. `None` means reuse modal. @@ -1827,8 +1827,8 @@ class Path(Record, GeometryMixin): repetition: repetition_t | None = None point_list: point_list_t | None = None """ - List of offsets from the initial vertex (x, y) to the remaining vertices, - `[[dx0, dy0], [dx1, dy1], ...]`. + List of offsets between consecutive vertices, starting from the initial + vertex (x, y): `[[dx0, dy0], [dx1, dy1], ...]`. The initial vertex is located at (x, y) and is not represented in `point_list`. Offsets are [int, int]; `None` means reuse modal. """ From 5b42cdf609cc78e3dafd27de6575481404daef39 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sun, 15 Feb 2026 16:25:21 -0800 Subject: [PATCH 37/40] [basic] cast to the expected types before conversion --- fatamorgana/basic.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index fee40dc..3c35d5e 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -2,7 +2,7 @@ This module contains all datatypes and parsing/writing functions for all abstractions below the 'record' or 'block' level. """ -from typing import Any, IO, Union +from typing import Any, IO, Union, TYPE_CHECKING from collections.abc import Sequence from fractions import Fraction from enum import Enum @@ -250,6 +250,7 @@ def write_uint(stream: IO[bytes], n: int) -> int: Raises: SignedError: if `n` is negative. """ + n = int(n) if n < 0: raise SignedError(f'uint must be positive: {n}') @@ -295,6 +296,7 @@ def encode_sint(sint: int) -> int: Returns: Unsigned integer encoding for the input. """ + sint = int(sint) return (abs(sint) << 1) | (sint < 0) @@ -1595,7 +1597,7 @@ def read_point_list( def write_point_list( stream: IO[bytes], - points: list[Sequence[int]], + points: 'list[Sequence[int]] | NDArray', fast: bool = False, implicit_closed: bool = True ) -> int: @@ -1618,6 +1620,8 @@ def write_point_list( Number of bytes written. """ # If we're in a hurry, just write the points as arbitrary Deltas + if _USE_NUMPY: + points = numpy.asarray(points, dtype=int) if fast: size = write_uint(stream, 4) size += write_uint(stream, len(points)) From c869da03bf5a3d322fa1f5aee3ef2dcfadd1df0a Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sun, 15 Feb 2026 19:21:28 -0800 Subject: [PATCH 38/40] [GridRepetition] convert to expected types --- fatamorgana/basic.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fatamorgana/basic.py b/fatamorgana/basic.py index 3c35d5e..70da126 100644 --- a/fatamorgana/basic.py +++ b/fatamorgana/basic.py @@ -1213,6 +1213,10 @@ class GridRepetition: InvalidDataError: if `b_count` and `b_vector` inputs conflict with each other or if `a_count < 1`. """ + a_count = int(a_count) + if b_count is not None: + b_count = int(b_count) + if b_vector is None or b_count is None: if b_vector is not None or b_count is not None: raise InvalidDataError('Repetition has only one of' From cceabe46ee92ad9c866e18cf1ba839869c529cde Mon Sep 17 00:00:00 2001 From: jan Date: Mon, 16 Feb 2026 21:50:29 -0800 Subject: [PATCH 39/40] README update: drop github mirror --- README.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/README.md b/README.md index 350a0d0..d4df9bb 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ **Homepage:** https://mpxd.net/code/jan/fatamorgana * [PyPI](https://pypi.org/project/fatamorgana) -* [Github mirror](https://github.com/anewusername/fatamorgana) **Capabilities:** * This package is a work-in-progress and is largely untested -- it works for @@ -28,12 +27,7 @@ Install with pip from PyPi (preferred): ```bash -pip3 install fatamorgana -``` - -Install directly from git repository: -```bash -pip3 install git+https://mpxd.net/code/jan/fatamorgana.git@release +pip install fatamorgana ``` ## Documentation @@ -44,7 +38,6 @@ To read the inline help, import fatamorgana help(fatamorgana.OasisLayout) ``` -The documentation is currently very sparse and I expect to improve it whenever possible! ## Examples From 93e4075d8902863e2c40380f833e3d9904023338 Mon Sep 17 00:00:00 2001 From: jan Date: Tue, 17 Feb 2026 00:44:56 -0800 Subject: [PATCH 40/40] [Placement] fix writing placement --- fatamorgana/records.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fatamorgana/records.py b/fatamorgana/records.py index f4d898c..a137b42 100644 --- a/fatamorgana/records.py +++ b/fatamorgana/records.py @@ -1434,7 +1434,7 @@ class Placement(Record): size += self.name.write(stream) # type: ignore if mm: size += write_real(stream, self.magnification) # type: ignore - if aa: + if aq: size += write_real(stream, self.angle) # type: ignore if xx: size += write_sint(stream, self.x) # type: ignore