Compare commits
27 Commits
7efc5a39d4
...
968392a4a3
Author | SHA1 | Date | |
---|---|---|---|
968392a4a3 | |||
cc08efcf17 | |||
19324ee147 | |||
f4866fb2bb | |||
37bac2af0d | |||
d3ba2ca2af | |||
3ee1c03f66 | |||
1252edb7b5 | |||
8e451c64db | |||
691ce03150 | |||
dc9ed8e794 | |||
891007054f | |||
5011750637 | |||
f87dc7d771 | |||
31e52e20d6 | |||
5ea5e8d8f9 | |||
d05561af41 | |||
ab8b71b149 | |||
c9e894879f | |||
d83ef1ce2d | |||
bd288d1363 | |||
931bc599d7 | |||
a4c1e52ff8 | |||
d61bbc530f | |||
01b3f9ca3a | |||
b2928c8b1c | |||
f9d4cfec33 |
1
.flake8
1
.flake8
@ -27,3 +27,4 @@ ignore =
|
|||||||
per-file-ignores =
|
per-file-ignores =
|
||||||
# F401 import without use
|
# F401 import without use
|
||||||
*/__init__.py: F401,
|
*/__init__.py: F401,
|
||||||
|
__init__.py: F401,
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
**fatamorgana** is a Python package for reading and writing OASIS format layout files.
|
**fatamorgana** is a Python package for reading and writing OASIS format layout files.
|
||||||
|
|
||||||
**Homepage:** https://mpxd.net/code/jan/fatamorgana
|
**Homepage:** https://mpxd.net/code/jan/fatamorgana
|
||||||
|
* [PyPI](https://pypi.org/project/fatamorgana)
|
||||||
|
* [Github mirror](https://github.com/anewusername/fatamorgana)
|
||||||
|
|
||||||
**Capabilities:**
|
**Capabilities:**
|
||||||
* This package is a work-in-progress and is largely untested -- it works for
|
* This package is a work-in-progress and is largely untested -- it works for
|
||||||
@ -20,7 +22,7 @@
|
|||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
**Dependencies:**
|
**Dependencies:**
|
||||||
* python 3.5 or newer
|
* python >=3.11
|
||||||
* (optional) numpy
|
* (optional) numpy
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
numpy to speed up reading/writing.
|
numpy to speed up reading/writing.
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
- Python 3.8 or later
|
- Python 3.11 or later
|
||||||
- numpy (optional, faster but no additional functionality)
|
- numpy (optional, faster but no additional functionality)
|
||||||
|
|
||||||
To get started, try:
|
To get started, try:
|
||||||
@ -24,17 +24,28 @@
|
|||||||
help(fatamorgana.OasisLayout)
|
help(fatamorgana.OasisLayout)
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
import pathlib
|
from .main import (
|
||||||
|
OasisLayout as OasisLayout,
|
||||||
from .main import OasisLayout, Cell, XName
|
Cell as Cell,
|
||||||
|
XName as XName,
|
||||||
|
)
|
||||||
from .basic import (
|
from .basic import (
|
||||||
NString, AString, Validation, OffsetTable, OffsetEntry,
|
NString as NString,
|
||||||
EOFError, SignedError, InvalidDataError, InvalidRecordError,
|
AString as AString,
|
||||||
UnfilledModalError,
|
Validation as Validation,
|
||||||
ReuseRepetition, GridRepetition, ArbitraryRepetition
|
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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
__author__ = 'Jan Petykiewicz'
|
__author__ = 'Jan Petykiewicz'
|
||||||
__version__ = '0.12'
|
__version__ = '0.13'
|
||||||
version = __version__
|
version = __version__
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
writing to whole OASIS layout files, and provides a few additional
|
||||||
abstractions for the data contained inside them.
|
abstractions for the data contained inside them.
|
||||||
"""
|
"""
|
||||||
from typing import List, Dict, Union, Optional, Type
|
from typing import IO
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -27,20 +27,20 @@ class FileModals:
|
|||||||
"""
|
"""
|
||||||
File-scoped modal variables
|
File-scoped modal variables
|
||||||
"""
|
"""
|
||||||
cellname_implicit: Optional[bool] = None
|
cellname_implicit: bool | None = None
|
||||||
propname_implicit: Optional[bool] = None
|
propname_implicit: bool | None = None
|
||||||
xname_implicit: Optional[bool] = None
|
xname_implicit: bool | None = None
|
||||||
textstring_implicit: Optional[bool] = None
|
textstring_implicit: bool | None = None
|
||||||
propstring_implicit: Optional[bool] = None
|
propstring_implicit: bool | None = None
|
||||||
|
|
||||||
property_target: List[records.Property]
|
property_target: list[records.Property]
|
||||||
|
|
||||||
within_cell: bool = False
|
within_cell: bool = False
|
||||||
within_cblock: bool = False
|
within_cblock: bool = False
|
||||||
end_has_offset_table: bool = False
|
end_has_offset_table: bool = False
|
||||||
started: 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
|
self.property_target = property_target
|
||||||
|
|
||||||
|
|
||||||
@ -53,43 +53,49 @@ class OasisLayout:
|
|||||||
record objects.
|
record objects.
|
||||||
Cells are stored using `Cell` objects (different from `records.Cell`
|
Cells are stored using `Cell` objects (different from `records.Cell`
|
||||||
record objects).
|
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
|
version: AString
|
||||||
|
"""File format version string ('1.0')"""
|
||||||
|
|
||||||
unit: real_t
|
unit: real_t
|
||||||
|
"""grid steps per micron"""
|
||||||
|
|
||||||
validation: Validation
|
validation: Validation
|
||||||
|
"""checksum data"""
|
||||||
|
|
||||||
properties: List[records.Property]
|
# Data
|
||||||
cells: List['Cell']
|
properties: list[records.Property]
|
||||||
|
"""Property values"""
|
||||||
|
|
||||||
cellnames: Dict[int, 'CellName']
|
cells: list['Cell']
|
||||||
propnames: Dict[int, NString]
|
"""Layout cells"""
|
||||||
xnames: Dict[int, 'XName']
|
|
||||||
|
|
||||||
textstrings: Dict[int, AString]
|
layers: list[records.LayerName]
|
||||||
propstrings: Dict[int, AString]
|
"""Layer definitions"""
|
||||||
layers: List[records.LayerName]
|
|
||||||
|
|
||||||
def __init__(self, unit: real_t, validation: Validation = None):
|
# 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: Validation | None = None,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
unit: Real number (i.e. int, float, or `Fraction`), grid steps per micron.
|
unit: Real number (i.e. int, float, or `Fraction`), grid steps per micron.
|
||||||
@ -112,7 +118,7 @@ class OasisLayout:
|
|||||||
self.layers = []
|
self.layers = []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def read(stream: io.BufferedIOBase) -> 'OasisLayout':
|
def read(stream: IO[bytes]) -> 'OasisLayout':
|
||||||
"""
|
"""
|
||||||
Read an entire .oas file into an `OasisLayout` object.
|
Read an entire .oas file into an `OasisLayout` object.
|
||||||
|
|
||||||
@ -132,8 +138,9 @@ class OasisLayout:
|
|||||||
pass
|
pass
|
||||||
return layout
|
return layout
|
||||||
|
|
||||||
def read_record(self,
|
def read_record(
|
||||||
stream: io.BufferedIOBase,
|
self,
|
||||||
|
stream: IO[bytes],
|
||||||
modals: Modals,
|
modals: Modals,
|
||||||
file_state: FileModals
|
file_state: FileModals
|
||||||
) -> bool:
|
) -> bool:
|
||||||
@ -156,13 +163,12 @@ class OasisLayout:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
record_id = read_uint(stream)
|
record_id = read_uint(stream)
|
||||||
except EOFError as e:
|
except EOFError:
|
||||||
if file_state.within_cblock:
|
if file_state.within_cblock:
|
||||||
return True
|
return True
|
||||||
else:
|
raise
|
||||||
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
|
record: Record
|
||||||
|
|
||||||
@ -182,11 +188,10 @@ class OasisLayout:
|
|||||||
|
|
||||||
# Make sure order is valid (eg, no out-of-cell geometry)
|
# Make sure order is valid (eg, no out-of-cell geometry)
|
||||||
if not file_state.started and record_id != 1:
|
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 record_id == 1:
|
||||||
if file_state.started:
|
if file_state.started:
|
||||||
raise InvalidRecordError('Duplicate Start record')
|
raise InvalidRecordError('Duplicate Start record')
|
||||||
else:
|
|
||||||
file_state.started = True
|
file_state.started = True
|
||||||
if record_id == 2 and file_state.within_cblock:
|
if record_id == 2 and file_state.within_cblock:
|
||||||
raise InvalidRecordError('End within CBlock')
|
raise InvalidRecordError('End within CBlock')
|
||||||
@ -197,11 +202,11 @@ class OasisLayout:
|
|||||||
file_state.within_cell = False
|
file_state.within_cell = False
|
||||||
elif record_id in range(15, 28) or record_id in (32, 33):
|
elif record_id in range(15, 28) or record_id in (32, 33):
|
||||||
if not file_state.within_cell:
|
if not file_state.within_cell:
|
||||||
raise Exception('Geometry outside Cell')
|
raise InvalidRecordError('Geometry outside Cell')
|
||||||
elif record_id in (13, 14):
|
elif record_id in (13, 14):
|
||||||
file_state.within_cell = True
|
file_state.within_cell = True
|
||||||
else:
|
else:
|
||||||
raise InvalidRecordError('Unknown record id: {}'.format(record_id))
|
raise InvalidRecordError(f'Unknown record id: {record_id}')
|
||||||
|
|
||||||
if record_id == 0:
|
if record_id == 0:
|
||||||
''' Pad '''
|
''' Pad '''
|
||||||
@ -335,10 +340,10 @@ class OasisLayout:
|
|||||||
self.cells[-1].geometry.append(record)
|
self.cells[-1].geometry.append(record)
|
||||||
file_state.property_target = record.properties
|
file_state.property_target = record.properties
|
||||||
else:
|
else:
|
||||||
raise InvalidRecordError('Unknown record id: {}'.format(record_id))
|
raise InvalidRecordError(f'Unknown record id: {record_id}')
|
||||||
return False
|
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.
|
Write this object in OASIS fromat to a stream.
|
||||||
|
|
||||||
@ -399,32 +404,28 @@ class OasisLayout:
|
|||||||
class Cell:
|
class Cell:
|
||||||
"""
|
"""
|
||||||
Representation of an OASIS 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]
|
name: NString | int
|
||||||
properties: List[records.Property]
|
"""name or "CellName reference" number"""
|
||||||
placements: List[records.Placement]
|
|
||||||
geometry: List[records.geometry_t]
|
|
||||||
|
|
||||||
def __init__(self,
|
properties: list[records.Property]
|
||||||
name: Union[NString, str, int],
|
placements: list[records.Placement]
|
||||||
|
geometry: list[records.geometry_t]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: NString | str | int,
|
||||||
*,
|
*,
|
||||||
properties: Optional[List[records.Property]] = None,
|
properties: list[records.Property] | None = None,
|
||||||
placements: Optional[List[records.Placement]] = None,
|
placements: list[records.Placement] | None = None,
|
||||||
geometry: Optional[List[records.geometry_t]] = 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.properties = [] if properties is None else properties
|
||||||
self.placements = [] if placements is None else placements
|
self.placements = [] if placements is None else placements
|
||||||
self.geometry = [] if geometry is None else geometry
|
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
|
Write this cell to a stream, using the provided modal variables to
|
||||||
deduplicate any repeated data.
|
deduplicate any repeated data.
|
||||||
@ -458,11 +459,13 @@ class CellName:
|
|||||||
with the reference data stripped out.
|
with the reference data stripped out.
|
||||||
"""
|
"""
|
||||||
nstring: NString
|
nstring: NString
|
||||||
properties: List[records.Property]
|
properties: list[records.Property]
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
nstring: Union[NString, str],
|
self,
|
||||||
properties: Optional[List[records.Property]] = None):
|
nstring: NString | str,
|
||||||
|
properties: list[records.Property] | None = None,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
nstring: The contained string.
|
nstring: The contained string.
|
||||||
@ -499,7 +502,7 @@ class XName:
|
|||||||
attribute: int
|
attribute: int
|
||||||
bstring: bytes
|
bstring: bytes
|
||||||
|
|
||||||
def __init__(self, attribute: int, bstring: bytes):
|
def __init__(self, attribute: int, bstring: bytes) -> None:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
attribute: Attribute number.
|
attribute: Attribute number.
|
||||||
@ -523,7 +526,7 @@ class XName:
|
|||||||
|
|
||||||
|
|
||||||
# Mapping from record id to record class.
|
# Mapping from record id to record class.
|
||||||
_GEOMETRY: Dict[int, Type[records.geometry_t]] = {
|
_GEOMETRY: dict[int, type[records.geometry_t]] = {
|
||||||
19: records.Text,
|
19: records.Text,
|
||||||
20: records.Rectangle,
|
20: records.Rectangle,
|
||||||
21: records.Polygon,
|
21: records.Polygon,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,10 @@
|
|||||||
'''
|
"""
|
||||||
Build files equivalent to the test cases used by KLayout.
|
Build files equivalent to the test cases used by KLayout.
|
||||||
'''
|
"""
|
||||||
# type: ignore
|
|
||||||
|
|
||||||
from typing import Callable
|
from typing import IO
|
||||||
from io import BufferedIOBase
|
from collections.abc import Callable
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
@ -12,12 +12,13 @@ from . import (
|
|||||||
test_files_circles, test_files_ctrapezoids, test_files_trapezoids,
|
test_files_circles, test_files_ctrapezoids, test_files_trapezoids,
|
||||||
test_files_placements, test_files_paths, test_files_modals,
|
test_files_placements, test_files_paths, test_files_modals,
|
||||||
test_files_polygons, test_files_rectangles, test_files_empty,
|
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:
|
def build_file(num: str, func: Callable[[IO[bytes]], IO[bytes]]) -> None:
|
||||||
with open('t' + num + '.oas', 'wb') as f:
|
with Path('t' + num + '.oas').open('wb') as ff:
|
||||||
func(f)
|
func(ff)
|
||||||
|
|
||||||
|
|
||||||
def write_all_files() -> None:
|
def write_all_files() -> None:
|
||||||
|
@ -1,17 +1,11 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr"
|
||||||
|
from typing import IO
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
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 numpy.testing import assert_equal
|
||||||
|
|
||||||
from .utils import HEADER, FOOTER
|
from .utils import HEADER, FOOTER
|
||||||
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
|
from ..basic import write_uint, write_bstring, write_byte
|
||||||
from ..basic import InvalidRecordError, InvalidDataError
|
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -32,9 +26,9 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.cells[0].properties
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
@ -98,11 +92,15 @@ def test_file_1() -> None:
|
|||||||
assert geometry[1].height == 610
|
assert geometry[1].height == 610
|
||||||
assert geometry[1].width == 680
|
assert geometry[1].width == 680
|
||||||
|
|
||||||
assert_equal(geometry[2].point_list,
|
assert_equal(geometry[2].point_list, [
|
||||||
[[-30, -360], [480, -50], [180, 430], [-630, -20]])
|
[-30, -360],
|
||||||
|
[480, -50],
|
||||||
|
[180, 430],
|
||||||
|
[-630, -20],
|
||||||
|
])
|
||||||
|
|
||||||
assert_equal(geometry[3].point_list,
|
assert_equal(geometry[3].point_list, [
|
||||||
[[-30, -400],
|
[-30, -400],
|
||||||
[450, 40],
|
[450, 40],
|
||||||
[70, -220],
|
[70, -220],
|
||||||
[10, 210],
|
[10, 210],
|
||||||
@ -123,23 +121,29 @@ def test_file_1() -> None:
|
|||||||
[210, 10],
|
[210, 10],
|
||||||
[40, 820],
|
[40, 820],
|
||||||
[-1340, 60],
|
[-1340, 60],
|
||||||
[30, -1370]])
|
[30, -1370],
|
||||||
|
])
|
||||||
|
|
||||||
assert_equal(geometry[4].point_list,
|
assert_equal(geometry[4].point_list, [
|
||||||
[[40, -760], [490, -50], [110, 800], [-640, 10]])
|
[40, -760],
|
||||||
|
[490, -50],
|
||||||
|
[110, 800],
|
||||||
|
[-640, 10],
|
||||||
|
])
|
||||||
|
|
||||||
assert_equal(geometry[5].point_list,
|
assert_equal(geometry[5].point_list, [
|
||||||
[[140, -380],
|
[140, -380],
|
||||||
[340, -10],
|
[340, -10],
|
||||||
[30, -100],
|
[30, -100],
|
||||||
[-320, 20],
|
[-320, 20],
|
||||||
[130, -460],
|
[130, -460],
|
||||||
[-480, -20],
|
[-480, -20],
|
||||||
[-210, 910],
|
[-210, 910],
|
||||||
[370, 40]])
|
[370, 40],
|
||||||
|
])
|
||||||
|
|
||||||
assert_equal(geometry[6].point_list,
|
assert_equal(geometry[6].point_list, [
|
||||||
[[720, -20],
|
[720, -20],
|
||||||
[20, 20],
|
[20, 20],
|
||||||
[690, 0],
|
[690, 0],
|
||||||
[-10, 650],
|
[-10, 650],
|
||||||
@ -153,10 +157,11 @@ def test_file_1() -> None:
|
|||||||
[-90, -20],
|
[-90, -20],
|
||||||
[-60, 140],
|
[-60, 140],
|
||||||
[-1390, 50],
|
[-1390, 50],
|
||||||
[10, 30]])
|
[10, 30],
|
||||||
|
])
|
||||||
|
|
||||||
assert_equal(geometry[7].point_list,
|
assert_equal(geometry[7].point_list, [
|
||||||
[[150, -830],
|
[150, -830],
|
||||||
[-1320, 40],
|
[-1320, 40],
|
||||||
[-70, 370],
|
[-70, 370],
|
||||||
[310, -30],
|
[310, -30],
|
||||||
@ -167,17 +172,25 @@ def test_file_1() -> None:
|
|||||||
[-20, 290],
|
[-20, 290],
|
||||||
[-1070, 20],
|
[-1070, 20],
|
||||||
[0, 230],
|
[0, 230],
|
||||||
[1380, -60]])
|
[1380, -60],
|
||||||
|
])
|
||||||
|
|
||||||
assert_equal(geometry[8].point_list,
|
assert_equal(geometry[8].point_list, [
|
||||||
[[330, 0], [-10, 480], [620, -20], [-10, 330], [-930, 60], [0, -850]])
|
[330, 0],
|
||||||
|
[-10, 480],
|
||||||
|
[620, -20],
|
||||||
|
[-10, 330],
|
||||||
|
[-930, 60],
|
||||||
|
[0, -850],
|
||||||
|
])
|
||||||
|
|
||||||
assert_equal(geometry[9].point_list,
|
assert_equal(geometry[9].point_list, [
|
||||||
[[-140, -410],
|
[-140, -410],
|
||||||
[10, -140],
|
[10, -140],
|
||||||
[270, 0],
|
[270, 0],
|
||||||
[130, 1030],
|
[130, 1030],
|
||||||
[-500, 50],
|
[-500, 50],
|
||||||
[10, -330],
|
[10, -330],
|
||||||
[210, -10],
|
[210, -10],
|
||||||
[10, -190]])
|
[10, -190],
|
||||||
|
])
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr"
|
||||||
|
from typing import IO
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
from typing import List, Tuple, Iterable
|
import pytest
|
||||||
from itertools import chain
|
|
||||||
from io import BytesIO, BufferedIOBase
|
|
||||||
import struct
|
|
||||||
|
|
||||||
import pytest # type: ignore
|
|
||||||
|
|
||||||
from .utils import HEADER, FOOTER
|
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 ..basic import InvalidRecordError, InvalidDataError
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
@ -26,10 +23,10 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.layers
|
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'
|
Single cell with explicit name 'XYZ'
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
@ -51,10 +48,10 @@ def test_file_1() -> None:
|
|||||||
assert not layout.cellnames
|
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.
|
Two cellnames ('XYZ', 'ABC') and two cells with name references.
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 3) # CELLNAME record (implicit id 0)
|
write_uint(buf, 3) # CELLNAME record (implicit id 0)
|
||||||
@ -88,10 +85,10 @@ def test_file_2() -> None:
|
|||||||
assert layout.cells[1].name == 1
|
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
|
Invalid file, contains a mix of explicit and implicit cellnames
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 4) # CELLNAME record (explicit id)
|
write_uint(buf, 4) # CELLNAME record (explicit id)
|
||||||
@ -116,13 +113,13 @@ def test_file_3() -> None:
|
|||||||
|
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
with pytest.raises(InvalidRecordError):
|
with pytest.raises(InvalidRecordError):
|
||||||
layout = OasisLayout.read(buf)
|
_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)
|
Two cells referencing two names with explicit ids (unsorted)
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 4) # CELLNAME record (explicit id)
|
write_uint(buf, 4) # CELLNAME record (explicit id)
|
||||||
@ -158,10 +155,10 @@ def test_file_4() -> None:
|
|||||||
assert layout.cells[1].name == 1
|
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.
|
Reference to non-existent cell name.
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 4) # CELLNAME record (explicit id)
|
write_uint(buf, 4) # CELLNAME record (explicit id)
|
||||||
@ -199,10 +196,10 @@ def test_file_5() -> None:
|
|||||||
#TODO add optional error checking for this case
|
#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.
|
Cellname with invalid n-string.
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 4) # CELLNAME record (explicit id)
|
write_uint(buf, 4) # CELLNAME record (explicit id)
|
||||||
@ -229,7 +226,7 @@ def test_file_6() -> None:
|
|||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
|
|
||||||
with pytest.raises(InvalidDataError):
|
with pytest.raises(InvalidDataError):
|
||||||
layout = OasisLayout.read(buf)
|
_layout = OasisLayout.read(buf)
|
||||||
|
|
||||||
#base_tests(layout)
|
#base_tests(layout)
|
||||||
#assert len(layout.cellnames) == 2
|
#assert len(layout.cellnames) == 2
|
||||||
@ -240,10 +237,10 @@ def test_file_6() -> None:
|
|||||||
#assert layout.cells[1].name == 1
|
#assert layout.cells[1].name == 1
|
||||||
|
|
||||||
|
|
||||||
def write_file_7(buf: BufferedIOBase) -> BufferedIOBase:
|
def write_file_7(buf: IO[bytes]) -> IO[bytes]:
|
||||||
'''
|
"""
|
||||||
Unused cellname.
|
Unused cellname.
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 4) # CELLNAME record (explicit id)
|
write_uint(buf, 4) # CELLNAME record (explicit id)
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr"
|
||||||
|
from typing import IO
|
||||||
from typing import List, Tuple, Iterable
|
from io import BytesIO
|
||||||
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 .utils import HEADER, FOOTER
|
||||||
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
|
from ..basic import write_uint, write_sint, write_bstring, write_byte
|
||||||
from ..basic import InvalidRecordError, InvalidDataError
|
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -32,9 +24,9 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.cells[0].properties
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr"
|
||||||
|
from typing import IO
|
||||||
from typing import List, Tuple, Iterable
|
from io import BytesIO
|
||||||
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 .utils import HEADER, FOOTER
|
||||||
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
|
from ..basic import write_uint, write_sint, write_bstring, write_byte
|
||||||
from ..basic import InvalidRecordError, InvalidDataError
|
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -28,9 +20,9 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.layers
|
assert not layout.layers
|
||||||
|
|
||||||
|
|
||||||
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
|
def write_file_1(buf: IO[bytes]) -> IO[bytes]:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
@ -66,9 +58,10 @@ def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
|
|||||||
+ [0b10] * 4
|
+ [0b10] * 4
|
||||||
+ [0b01] * 2
|
+ [0b01] * 2
|
||||||
+ [0b10] * 2
|
+ [0b10] * 2
|
||||||
+ [0b11, 0b10])
|
+ [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_uint(buf, 26) # CTRAPEZOID record
|
||||||
write_byte(buf, 0b1000_1011 | (x_en << 5)) # TWHX_YRDL
|
write_byte(buf, 0b1000_1011 | (x_en << 5)) # TWHX_YRDL
|
||||||
write_uint(buf, 1) # layer
|
write_uint(buf, 1) # layer
|
||||||
@ -142,8 +135,7 @@ def test_file_1() -> None:
|
|||||||
assert gg.width == [250, None][is_ctrapz], msg
|
assert gg.width == [250, None][is_ctrapz], msg
|
||||||
elif ct_type in range(22, 24) or ct_type == 25:
|
elif ct_type in range(22, 24) or ct_type == 25:
|
||||||
assert gg.height == [100, None][is_ctrapz], msg
|
assert gg.height == [100, None][is_ctrapz], msg
|
||||||
else:
|
elif ct_type < 8 or 16 <= ct_type < 25 or ct_type >= 26:
|
||||||
if ct_type < 8 or 16 <= ct_type < 25 or 26 <= ct_type :
|
|
||||||
assert gg.width == 250, msg
|
assert gg.width == 250, msg
|
||||||
assert gg.height == 100, msg
|
assert gg.height == 100, msg
|
||||||
else:
|
else:
|
||||||
@ -160,9 +152,9 @@ def test_file_1() -> None:
|
|||||||
assert geometry[55].repetition.b_vector == [0, 300]
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
# type: ignore
|
from typing import IO
|
||||||
|
from io import BytesIO
|
||||||
from typing import List, Tuple, Iterable
|
|
||||||
from itertools import chain
|
|
||||||
from io import BytesIO, BufferedIOBase
|
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
import pytest # type: ignore
|
|
||||||
|
|
||||||
from .utils import MAGIC_BYTES, FOOTER
|
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
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -26,12 +21,12 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.layers
|
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.
|
File contains one PAD record.
|
||||||
1000 units/micron
|
1000 units/micron
|
||||||
Offset table inside START.
|
Offset table inside START.
|
||||||
'''
|
"""
|
||||||
buf.write(MAGIC_BYTES)
|
buf.write(MAGIC_BYTES)
|
||||||
|
|
||||||
write_uint(buf, 1) # START record
|
write_uint(buf, 1) # START record
|
||||||
@ -59,13 +54,12 @@ def test_file_1() -> None:
|
|||||||
assert layout.unit == 1000
|
assert layout.unit == 1000
|
||||||
|
|
||||||
|
|
||||||
|
def write_file_2(buf: IO[bytes]) -> IO[bytes]:
|
||||||
def write_file_2(buf: BufferedIOBase) -> BufferedIOBase:
|
"""
|
||||||
'''
|
|
||||||
File contains no records.
|
File contains no records.
|
||||||
1/2 unit/micron
|
1/2 unit/micron
|
||||||
Offset table inside START.
|
Offset table inside START.
|
||||||
'''
|
"""
|
||||||
buf.write(MAGIC_BYTES)
|
buf.write(MAGIC_BYTES)
|
||||||
|
|
||||||
write_uint(buf, 1) # START record
|
write_uint(buf, 1) # START record
|
||||||
@ -91,12 +85,12 @@ def test_file_2() -> None:
|
|||||||
assert layout.unit == 0.5
|
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.
|
File contains no records.
|
||||||
10/4 unit/micron
|
10/4 unit/micron
|
||||||
Offset table inside START.
|
Offset table inside START.
|
||||||
'''
|
"""
|
||||||
buf.write(MAGIC_BYTES)
|
buf.write(MAGIC_BYTES)
|
||||||
|
|
||||||
write_uint(buf, 1) # START record
|
write_uint(buf, 1) # START record
|
||||||
@ -123,12 +117,12 @@ def test_file_3() -> None:
|
|||||||
assert layout.unit == 10 / 4
|
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.
|
File contains no records.
|
||||||
12.5 unit/micron (float32)
|
12.5 unit/micron (float32)
|
||||||
Offset table inside START.
|
Offset table inside START.
|
||||||
'''
|
"""
|
||||||
buf.write(MAGIC_BYTES)
|
buf.write(MAGIC_BYTES)
|
||||||
|
|
||||||
write_uint(buf, 1) # START record
|
write_uint(buf, 1) # START record
|
||||||
@ -154,12 +148,12 @@ def test_file_4() -> None:
|
|||||||
assert layout.unit == 12.5
|
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.
|
File contains no records.
|
||||||
12.5 unit/micron (float64)
|
12.5 unit/micron (float64)
|
||||||
Offset table inside START.
|
Offset table inside START.
|
||||||
'''
|
"""
|
||||||
buf.write(MAGIC_BYTES)
|
buf.write(MAGIC_BYTES)
|
||||||
|
|
||||||
write_uint(buf, 1) # START record
|
write_uint(buf, 1) # START record
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
# type: ignore
|
from typing import IO
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
from typing import List, Tuple, Iterable, Sequence
|
from io import BytesIO
|
||||||
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 .utils import HEADER, FOOTER
|
||||||
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
|
from ..basic import write_uint, write_sint, write_bstring, write_byte
|
||||||
from ..basic import InvalidRecordError, InvalidDataError
|
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
LAYERS = [(1, 2), (1, 5), (1, 6), (1, 8),
|
LAYERS = [
|
||||||
|
(1, 2), (1, 5), (1, 6), (1, 8),
|
||||||
(5, 2), (5, 5), (5, 6), (5, 8),
|
(5, 2), (5, 5), (5, 6), (5, 8),
|
||||||
(6, 2), (6, 5), (6, 6), (6, 8),
|
(6, 2), (6, 5), (6, 6), (6, 8),
|
||||||
(7, 2), (7, 5), (7, 6), (7, 8),
|
(7, 2), (7, 5), (7, 6), (7, 8),
|
||||||
@ -32,11 +27,11 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.cellnames
|
assert not layout.cellnames
|
||||||
|
|
||||||
assert len(layout.cells) == 1
|
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
|
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_uint(buf, 11) # LAYERNAME record (geometry)
|
||||||
write_bstring(buf, b'AA') # name
|
write_bstring(buf, b'AA') # name
|
||||||
write_uint(buf, 0) # all layers
|
write_uint(buf, 0) # all layers
|
||||||
@ -102,7 +97,7 @@ def write_names_geom(buf: BufferedIOBase, short: bool = False) -> BufferedIOBase
|
|||||||
return buf
|
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_uint(buf, 12) # LAYERNAME record (geometry)
|
||||||
write_bstring(buf, prefix + b'AA') # name
|
write_bstring(buf, prefix + b'AA') # name
|
||||||
write_uint(buf, 0) # all layers
|
write_uint(buf, 0) # all layers
|
||||||
@ -134,7 +129,7 @@ def write_names_text(buf: BufferedIOBase, prefix: bytes = b'') -> BufferedIOBase
|
|||||||
write_uint(buf, 0) # all datatypes
|
write_uint(buf, 0) # all datatypes
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def write_geom(buf: BufferedIOBase) -> BufferedIOBase:
|
def write_geom(buf: IO[bytes]) -> IO[bytes]:
|
||||||
for ll, dt in LAYERS:
|
for ll, dt in LAYERS:
|
||||||
write_uint(buf, 27) # CIRCLE record
|
write_uint(buf, 27) # CIRCLE record
|
||||||
write_byte(buf, 0b0011_1011) # 00rX_YRDL
|
write_byte(buf, 0b0011_1011) # 00rX_YRDL
|
||||||
@ -146,7 +141,7 @@ def write_geom(buf: BufferedIOBase) -> BufferedIOBase:
|
|||||||
return buf
|
return buf
|
||||||
|
|
||||||
|
|
||||||
def write_text(buf: BufferedIOBase) -> BufferedIOBase:
|
def write_text(buf: IO[bytes]) -> IO[bytes]:
|
||||||
for ll, dt in LAYERS:
|
for ll, dt in LAYERS:
|
||||||
write_uint(buf, 19) # TEXT record
|
write_uint(buf, 19) # TEXT record
|
||||||
write_byte(buf, 0b0101_1011) # 0CNX_YRTL
|
write_byte(buf, 0b0101_1011) # 0CNX_YRTL
|
||||||
@ -160,7 +155,8 @@ def write_text(buf: BufferedIOBase) -> BufferedIOBase:
|
|||||||
|
|
||||||
def name_test(layers: Sequence, is_textlayer: bool) -> None:
|
def name_test(layers: Sequence, is_textlayer: bool) -> None:
|
||||||
for ii, nn in enumerate(layers):
|
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',
|
assert nn.nstring.string == ['AA', 'L5A', 'H5A', 'E5A', 'I56A',
|
||||||
'E5L4', 'E5H4', 'E5E4', 'E5I47'][ii], msg
|
'E5L4', 'E5H4', 'E5E4', 'E5I47'][ii], msg
|
||||||
@ -172,7 +168,8 @@ def name_test(layers: Sequence, is_textlayer: bool) -> None:
|
|||||||
|
|
||||||
def name_test_text(layers: Sequence) -> None:
|
def name_test_text(layers: Sequence) -> None:
|
||||||
for ii, nn in enumerate(layers):
|
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.nstring.string == ['TAA', 'TL5A', 'TH5A', 'TE5A', 'TI56A'][ii], msg
|
||||||
assert nn.layer_interval[0] == [None, None, 5, 5, 5][ii], msg
|
assert nn.layer_interval[0] == [None, None, 5, 5, 5][ii], msg
|
||||||
@ -209,9 +206,9 @@ def elem_test_text(geometry: Sequence) -> None:
|
|||||||
assert not gg.properties, msg
|
assert not gg.properties, msg
|
||||||
|
|
||||||
|
|
||||||
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
|
def write_file_1(buf: IO[bytes]) -> IO[bytes]:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
write_names_geom(buf)
|
write_names_geom(buf)
|
||||||
|
|
||||||
@ -239,9 +236,9 @@ def test_file_1() -> None:
|
|||||||
name_test(layout.layers, is_textlayer=False)
|
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)
|
buf.write(HEADER)
|
||||||
write_names_text(buf)
|
write_names_text(buf)
|
||||||
|
|
||||||
@ -269,9 +266,9 @@ def test_file_2() -> None:
|
|||||||
name_test(layout.layers, is_textlayer=True)
|
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)
|
buf.write(HEADER)
|
||||||
write_names_text(buf, prefix=b'T')
|
write_names_text(buf, prefix=b'T')
|
||||||
write_names_geom(buf, short=True)
|
write_names_geom(buf, short=True)
|
||||||
@ -285,9 +282,9 @@ def write_file_3(buf: BufferedIOBase) -> BufferedIOBase:
|
|||||||
return buf
|
return buf
|
||||||
|
|
||||||
|
|
||||||
def write_file_4(buf: BufferedIOBase) -> BufferedIOBase:
|
def write_file_4(buf: IO[bytes]) -> IO[bytes]:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr"
|
||||||
|
from typing import IO
|
||||||
from typing import List, Tuple, Iterable
|
from io import BytesIO
|
||||||
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 .utils import HEADER, FOOTER
|
||||||
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
|
from ..basic import write_uint, write_sint, write_bstring, write_byte
|
||||||
from ..basic import InvalidRecordError, InvalidDataError
|
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -28,9 +20,9 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.layers
|
assert not layout.layers
|
||||||
|
|
||||||
|
|
||||||
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
|
def write_file_1(buf: IO[bytes]) -> IO[bytes]:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
|
@ -1,17 +1,11 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr"
|
||||||
|
from typing import IO
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
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 numpy.testing import assert_equal
|
||||||
|
|
||||||
from .utils import HEADER, FOOTER
|
from .utils import HEADER, FOOTER
|
||||||
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
|
from ..basic import write_uint, write_sint, write_bstring, write_byte, PathExtensionScheme
|
||||||
from ..basic import InvalidRecordError, InvalidDataError
|
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -32,9 +26,9 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.cells[0].properties
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
@ -188,7 +182,7 @@ def test_file_1() -> None:
|
|||||||
else:
|
else:
|
||||||
assert gg.half_width == 12, msg
|
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)
|
assert_equal(gg.point_list, [[150, 0], [0, 50], [-50, 0]], err_msg=msg)
|
||||||
|
|
||||||
if ii >= 4:
|
if ii >= 4:
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr"
|
||||||
|
from typing import IO, cast
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
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 numpy.testing import assert_equal
|
||||||
|
|
||||||
from .utils import HEADER, FOOTER
|
from .utils import HEADER, FOOTER
|
||||||
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
|
from ..basic import write_uint, write_sint, write_bstring, write_byte, write_float32, write_float64
|
||||||
from ..basic import InvalidRecordError, InvalidDataError, write_float32, write_float64
|
from ..records import Rectangle
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -27,7 +22,7 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.layers
|
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_uint(buf, 20) # RECTANGLE record
|
||||||
write_byte(buf, 0b0111_1011) # SWHX_YRDL
|
write_byte(buf, 0b0111_1011) # SWHX_YRDL
|
||||||
write_uint(buf, 1) # layer
|
write_uint(buf, 1) # layer
|
||||||
@ -38,9 +33,9 @@ def write_rectangle(buf: BufferedIOBase, pos: Tuple[int, int] = (300, -400)) ->
|
|||||||
write_sint(buf, pos[1]) # geometry-y (absolute)
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
@ -179,7 +174,7 @@ def test_file_1() -> None:
|
|||||||
assert not layout.cells[1].properties
|
assert not layout.cells[1].properties
|
||||||
assert not layout.cells[1].geometry
|
assert not layout.cells[1].geometry
|
||||||
|
|
||||||
geometry = layout.cells[0].geometry
|
geometry = cast(list[Rectangle], layout.cells[0].geometry)
|
||||||
assert len(geometry) == 1
|
assert len(geometry) == 1
|
||||||
assert geometry[0].layer == 1
|
assert geometry[0].layer == 1
|
||||||
assert geometry[0].datatype == 2
|
assert geometry[0].datatype == 2
|
||||||
@ -207,19 +202,19 @@ def test_file_1() -> None:
|
|||||||
|
|
||||||
if ii < 3:
|
if ii < 3:
|
||||||
assert pp.y == 400 * (ii + 1), msg
|
assert pp.y == 400 * (ii + 1), msg
|
||||||
elif 7 <= ii:
|
elif ii >= 7:
|
||||||
assert pp.y == 0, msg
|
assert pp.y == 0, msg
|
||||||
|
|
||||||
if ii < 4 or ii == 5:
|
if ii < 4 or ii == 5:
|
||||||
assert pp.flip == False, msg
|
assert not bool(pp.flip), msg
|
||||||
else:
|
else:
|
||||||
assert pp.flip == True, msg
|
assert bool(pp.flip), msg
|
||||||
|
|
||||||
if ii < 5:
|
if ii < 5:
|
||||||
assert pp.angle == 0, msg
|
assert pp.angle == 0, msg
|
||||||
elif ii in (5, 6):
|
elif ii in (5, 6):
|
||||||
assert pp.angle == 90, msg
|
assert pp.angle == 90, msg
|
||||||
elif 7 <= ii:
|
elif ii >= 7:
|
||||||
assert pp.angle == 270, msg
|
assert pp.angle == 270, msg
|
||||||
|
|
||||||
if ii < 7:
|
if ii < 7:
|
||||||
@ -254,9 +249,9 @@ def test_file_1() -> None:
|
|||||||
assert placements[12].repetition.b_vector == [-330, 330]
|
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!'
|
assert variant in (2, 3, 5, 7), 'Error in test definition!'
|
||||||
|
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
@ -502,9 +497,9 @@ def common_tests(layout: OasisLayout, variant: int) -> None:
|
|||||||
assert pp.y == 400 * (ii + 1), msg
|
assert pp.y == 400 * (ii + 1), msg
|
||||||
|
|
||||||
if ii in (4, 6):
|
if ii in (4, 6):
|
||||||
assert pp.flip == True, msg
|
assert bool(pp.flip), msg
|
||||||
else:
|
else:
|
||||||
assert pp.flip == False, msg
|
assert not bool(pp.flip), msg
|
||||||
|
|
||||||
if ii in (5, 6):
|
if ii in (5, 6):
|
||||||
assert pp.angle == 90, msg
|
assert pp.angle == 90, msg
|
||||||
@ -520,9 +515,9 @@ def common_tests(layout: OasisLayout, variant: int) -> None:
|
|||||||
assert placements[6].y == 2400
|
assert placements[6].y == 2400
|
||||||
|
|
||||||
|
|
||||||
def write_file_4(buf: BufferedIOBase) -> BufferedIOBase:
|
def write_file_4(buf: IO[bytes]) -> IO[bytes]:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 3) # CELLNAME record (implicit id 0)
|
write_uint(buf, 3) # CELLNAME record (implicit id 0)
|
||||||
@ -599,9 +594,9 @@ def write_file_4(buf: BufferedIOBase) -> BufferedIOBase:
|
|||||||
return buf
|
return buf
|
||||||
|
|
||||||
|
|
||||||
def write_file_6(buf: BufferedIOBase) -> BufferedIOBase:
|
def write_file_6(buf: IO[bytes]) -> IO[bytes]:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
@ -752,9 +747,9 @@ def test_file_6() -> None:
|
|||||||
assert pp.y == [0, 1000][ii], msg
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
@ -848,7 +843,7 @@ def test_file_8() -> None:
|
|||||||
assert not layout.cells[2].properties
|
assert not layout.cells[2].properties
|
||||||
assert not layout.cells[2].placements
|
assert not layout.cells[2].placements
|
||||||
|
|
||||||
geometry = layout.cells[2].geometry
|
geometry = cast(list[Rectangle], layout.cells[2].geometry)
|
||||||
assert len(geometry) == 1
|
assert len(geometry) == 1
|
||||||
assert geometry[0].layer == 1
|
assert geometry[0].layer == 1
|
||||||
assert geometry[0].datatype == 2
|
assert geometry[0].datatype == 2
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr, arg-type"
|
||||||
|
from typing import IO
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
from typing import List, Tuple, Iterable
|
|
||||||
from itertools import chain
|
|
||||||
from io import BytesIO, BufferedIOBase
|
|
||||||
import struct
|
|
||||||
|
|
||||||
import pytest # type: ignore
|
|
||||||
import numpy
|
import numpy
|
||||||
from numpy.testing import assert_equal
|
from numpy.testing import assert_equal
|
||||||
|
|
||||||
from .utils import HEADER, FOOTER
|
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 ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -85,8 +80,11 @@ def common_tests(layout: OasisLayout) -> None:
|
|||||||
for ii in range(4):
|
for ii in range(4):
|
||||||
msg = f'Fail on poly {ii}'
|
msg = f'Fail on poly {ii}'
|
||||||
assert len(geometry[0].point_list) == 6, msg
|
assert len(geometry[0].point_list) == 6, msg
|
||||||
assert_equal(geometry[0].point_list, [[150, 0], [0, 50], [-50, 0], [0, 50],
|
assert_equal(
|
||||||
[-100, 0], [0, -100]], err_msg=msg)
|
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 len(geometry[4].point_list) == 6
|
||||||
assert_equal(geometry[4].point_list, [[0, 150], [50, 0], [0, -50], [50, 0], [0, -100], [-100, 0]])
|
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 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_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 len(geometry[8].point_list) == 9
|
||||||
assert_equal(geometry[8].point_list,
|
assert_equal(
|
||||||
numpy.cumsum([[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25], [45, -575]], axis=0))
|
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):
|
for ii in range(9, 12):
|
||||||
msg = f'Fail on poly {ii}'
|
msg = f'Fail on poly {ii}'
|
||||||
@ -106,9 +106,9 @@ 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)
|
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!!'
|
assert variant in (1, 3), 'Error in test!!'
|
||||||
|
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
@ -375,9 +375,9 @@ def test_file_1() -> None:
|
|||||||
assert not gg.properties, f'Fail on polygon {ii}'
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
@ -425,7 +425,8 @@ def test_file_2() -> None:
|
|||||||
assert_equal(poly.point_list,
|
assert_equal(poly.point_list,
|
||||||
([[-1000, 0]]
|
([[-1000, 0]]
|
||||||
+ [[(-1) ** nn * 10, 20] for nn in range(8000)]
|
+ [[(-1) ** nn * 10, 20] for nn in range(8000)]
|
||||||
+ [[1000, 0], [0, -20 * 8000]]))
|
+ [[1000, 0], [0, -20 * 8000]]),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_file_3() -> None:
|
def test_file_3() -> None:
|
||||||
@ -444,7 +445,7 @@ def test_file_3() -> None:
|
|||||||
for ii, gg in enumerate(geometry):
|
for ii, gg in enumerate(geometry):
|
||||||
msg = f'Fail on polygon {ii}'
|
msg = f'Fail on polygon {ii}'
|
||||||
assert len(gg.properties) == 1, msg
|
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 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
|
||||||
|
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr, index, arg-type"
|
||||||
|
from typing import IO
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
from typing import List, Tuple, Iterable
|
import pytest
|
||||||
from itertools import chain
|
|
||||||
from io import BytesIO, BufferedIOBase
|
|
||||||
import struct
|
|
||||||
|
|
||||||
import pytest # type: ignore
|
|
||||||
import numpy
|
|
||||||
from numpy.testing import assert_equal
|
from numpy.testing import assert_equal
|
||||||
|
|
||||||
from .utils import HEADER, FOOTER
|
from .utils import HEADER, FOOTER
|
||||||
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
|
from ..basic import write_uint, write_sint, write_bstring, write_byte
|
||||||
from ..basic import InvalidRecordError, InvalidDataError
|
from ..basic import InvalidDataError
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -27,12 +23,12 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.layers
|
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)
|
include_repetitions = variant in (2, 5)
|
||||||
|
|
||||||
def var_byte(buf, byte):
|
def var_byte(buf: IO[bytes], byte: int) -> None:
|
||||||
if include_repetitions:
|
if include_repetitions:
|
||||||
byte |= 0b0100
|
byte |= 0b0100
|
||||||
write_byte(buf, byte)
|
write_byte(buf, byte)
|
||||||
@ -54,7 +50,6 @@ def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
|
|||||||
write_uint(buf, 7) # PROPNAME record (implicit id 1)
|
write_uint(buf, 7) # PROPNAME record (implicit id 1)
|
||||||
write_bstring(buf, b'PROP1')
|
write_bstring(buf, b'PROP1')
|
||||||
|
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
write_bstring(buf, b'A') # Cell name
|
write_bstring(buf, b'A') # Cell name
|
||||||
|
|
||||||
@ -359,9 +354,9 @@ def test_file_5() -> None:
|
|||||||
assert gg.repetition.b_vector == [0, 320], msg
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 10) # PROPSTRING (explicit id)
|
write_uint(buf, 10) # PROPSTRING (explicit id)
|
||||||
@ -375,7 +370,7 @@ def write_file_3(buf: BufferedIOBase) -> BufferedIOBase:
|
|||||||
write_uint(buf, 7) # PROPNAME record (implicit id 0)
|
write_uint(buf, 7) # PROPNAME record (implicit id 0)
|
||||||
write_bstring(buf, b'S_GDS_PROPERTY')
|
write_bstring(buf, b'S_GDS_PROPERTY')
|
||||||
|
|
||||||
|
# ** CELL **
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
write_bstring(buf, b'A') # Cell name
|
write_bstring(buf, b'A') # Cell name
|
||||||
|
|
||||||
@ -584,9 +579,9 @@ def test_file_3() -> None:
|
|||||||
assert geometry[ii].properties[0].values[1].string == 'PROP_VALUE2', msg
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 10) # PROPSTRING (explicit id)
|
write_uint(buf, 10) # PROPSTRING (explicit id)
|
||||||
@ -614,7 +609,7 @@ def write_file_4_6(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
|
|||||||
write_sint(buf, 300) # geometry-x (relative)
|
write_sint(buf, 300) # geometry-x (relative)
|
||||||
write_sint(buf, -400) # geometry-y (relative)
|
write_sint(buf, -400) # geometry-y (relative)
|
||||||
|
|
||||||
|
# ** CELL **
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
write_bstring(buf, b'TOP') # Cell name
|
write_bstring(buf, b'TOP') # Cell name
|
||||||
|
|
||||||
@ -791,8 +786,8 @@ def write_file_4_6(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
|
|||||||
|
|
||||||
|
|
||||||
def test_file_4() -> None:
|
def test_file_4() -> None:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
buf = write_file_4_6(BytesIO(), 4)
|
buf = write_file_4_6(BytesIO(), 4)
|
||||||
|
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
@ -828,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.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
|
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
|
assert pp.flip, msg
|
||||||
else:
|
else:
|
||||||
assert not pp.flip, msg
|
assert not pp.flip, msg
|
||||||
@ -860,8 +855,8 @@ def test_file_4() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_file_6() -> None:
|
def test_file_6() -> None:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
buf = write_file_4_6(BytesIO(), 6)
|
buf = write_file_4_6(BytesIO(), 6)
|
||||||
|
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
@ -897,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.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
|
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
|
assert pp.flip, msg
|
||||||
else:
|
else:
|
||||||
assert not pp.flip, msg
|
assert not pp.flip, msg
|
||||||
@ -932,9 +927,9 @@ def test_file_6() -> None:
|
|||||||
assert placements[ii].properties[0].values[1].string == 'PROP_VALUE2', msg
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 28) # PROPERTY record
|
write_uint(buf, 28) # PROPERTY record
|
||||||
@ -991,7 +986,7 @@ def write_file_7_8_9(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
|
|||||||
write_uint(buf, 10) # prop-value 0 (a-string)
|
write_uint(buf, 10) # prop-value 0 (a-string)
|
||||||
write_bstring(buf, b'CPValue0')
|
write_bstring(buf, b'CPValue0')
|
||||||
|
|
||||||
|
# ** CELL **
|
||||||
write_uint(buf, 13) # CELL record (name ref.)
|
write_uint(buf, 13) # CELL record (name ref.)
|
||||||
write_uint(buf, 0) # Cell name 0 (XYZ)
|
write_uint(buf, 0) # Cell name 0 (XYZ)
|
||||||
|
|
||||||
@ -1020,7 +1015,6 @@ def write_file_7_8_9(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
|
|||||||
return buf
|
return buf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_file_7() -> None:
|
def test_file_7() -> None:
|
||||||
buf = write_file_7_8_9(BytesIO(), 7)
|
buf = write_file_7_8_9(BytesIO(), 7)
|
||||||
|
|
||||||
@ -1065,20 +1059,20 @@ def test_file_7() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_file_8() -> None:
|
def test_file_8() -> None:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
buf = write_file_7_8_9(BytesIO(), 8)
|
buf = write_file_7_8_9(BytesIO(), 8)
|
||||||
|
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
with pytest.raises(InvalidDataError):
|
with pytest.raises(InvalidDataError):
|
||||||
layout = OasisLayout.read(buf)
|
_layout = OasisLayout.read(buf)
|
||||||
|
|
||||||
|
|
||||||
def test_file_9() -> None:
|
def test_file_9() -> None:
|
||||||
'''
|
"""
|
||||||
'''
|
"""
|
||||||
buf = write_file_7_8_9(BytesIO(), 9)
|
buf = write_file_7_8_9(BytesIO(), 9)
|
||||||
|
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
with pytest.raises(InvalidDataError):
|
with pytest.raises(InvalidDataError):
|
||||||
layout = OasisLayout.read(buf)
|
_layout = OasisLayout.read(buf)
|
||||||
|
@ -1,15 +1,9 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr"
|
||||||
|
from typing import IO
|
||||||
from typing import List, Tuple, Iterable
|
from io import BytesIO
|
||||||
from itertools import chain
|
|
||||||
from io import BytesIO, BufferedIOBase
|
|
||||||
import struct
|
|
||||||
|
|
||||||
import pytest # type: ignore
|
|
||||||
|
|
||||||
from .utils import HEADER, FOOTER
|
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 ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -80,9 +74,9 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert geometry[10].repetition.x_displacements == [200, 300]
|
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!!'
|
assert variant in (1, 2), 'Error in test!!'
|
||||||
|
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
@ -273,7 +267,7 @@ def test_file_2() -> None:
|
|||||||
prop = gg.properties[0]
|
prop = gg.properties[0]
|
||||||
|
|
||||||
assert prop.name == 0, msg
|
assert prop.name == 0, msg
|
||||||
assert len(prop.values) == 1, msg
|
assert len(prop.values) == 1, msg # type: ignore
|
||||||
assert prop.values[0].numerator == 1, msg
|
assert prop.values[0].numerator == 1, msg # type: ignore
|
||||||
assert prop.values[0].denominator == 5, msg
|
assert prop.values[0].denominator == 5, msg # type: ignore
|
||||||
|
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr, index"
|
||||||
|
from typing import IO
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
from typing import List, Tuple, Iterable
|
import pytest
|
||||||
from itertools import chain
|
|
||||||
from io import BytesIO, BufferedIOBase
|
|
||||||
import struct
|
|
||||||
|
|
||||||
import pytest # type: ignore
|
|
||||||
|
|
||||||
from .utils import HEADER, FOOTER
|
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 InvalidRecordError, InvalidDataError
|
||||||
from ..basic import GridRepetition, ArbitraryRepetition
|
from ..basic import GridRepetition, ArbitraryRepetition
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
@ -33,8 +30,8 @@ def common_tests(layout: OasisLayout) -> None:
|
|||||||
|
|
||||||
geometry = layout.cells[0].geometry
|
geometry = layout.cells[0].geometry
|
||||||
|
|
||||||
geometry[0].layer == 1
|
assert geometry[0].layer == 1
|
||||||
geometry[0].datatype == 2
|
assert geometry[0].datatype == 2
|
||||||
for ii, gg in enumerate(geometry[1:]):
|
for ii, gg in enumerate(geometry[1:]):
|
||||||
assert gg.layer == 2, f'textstring #{ii + 1}'
|
assert gg.layer == 2, f'textstring #{ii + 1}'
|
||||||
assert gg.datatype == 1, f'textstring #{ii + 1}'
|
assert gg.datatype == 1, f'textstring #{ii + 1}'
|
||||||
@ -86,12 +83,12 @@ def common_tests(layout: OasisLayout) -> None:
|
|||||||
assert geometry[13].repetition.b_vector == [-10, 10]
|
assert geometry[13].repetition.b_vector == [-10, 10]
|
||||||
|
|
||||||
assert geometry[14].repetition.a_count == 3
|
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.a_vector == [11, 12]
|
||||||
assert geometry[14].repetition.b_vector is None
|
assert geometry[14].repetition.b_vector is None
|
||||||
|
|
||||||
assert geometry[15].repetition.a_count == 4
|
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.a_vector == [-10, 10]
|
||||||
assert geometry[15].repetition.b_vector is None
|
assert geometry[15].repetition.b_vector is None
|
||||||
|
|
||||||
@ -102,10 +99,10 @@ def common_tests(layout: OasisLayout) -> None:
|
|||||||
assert geometry[19].repetition.y_displacements == [12, -9]
|
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'
|
Single cell with explicit name 'XYZ'
|
||||||
'''
|
"""
|
||||||
assert variant in (1, 2, 5, 12), 'Error in test!!'
|
assert variant in (1, 2, 5, 12), 'Error in test!!'
|
||||||
|
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
@ -463,11 +460,11 @@ def test_file_12() -> None:
|
|||||||
assert layout.textstrings[2].string == 'B'
|
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.
|
File with one textstring with explicit id, and one with an implicit id.
|
||||||
Should fail.
|
Should fail.
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 6) # TEXTSTRING record (explicit id)
|
write_uint(buf, 6) # TEXTSTRING record (explicit id)
|
||||||
@ -497,15 +494,15 @@ def test_file_3() -> None:
|
|||||||
|
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
with pytest.raises(InvalidRecordError):
|
with pytest.raises(InvalidRecordError):
|
||||||
layout = OasisLayout.read(buf)
|
_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
|
File with a TEXT record that references a non-existent TEXTSTRING
|
||||||
|
|
||||||
TODO add an optional check for valid references
|
TODO add an optional check for valid references
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
||||||
@ -540,10 +537,10 @@ def test_file_4() -> None:
|
|||||||
base_tests(layout)
|
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
|
File with TEXT record that uses an un-filled modal for the repetition
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
||||||
@ -570,13 +567,13 @@ def test_file_6() -> None:
|
|||||||
|
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
with pytest.raises(InvalidDataError):
|
with pytest.raises(InvalidDataError):
|
||||||
layout = OasisLayout.read(buf)
|
_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
|
File with TEXT record that uses an un-filled modal for the layer
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
||||||
@ -601,13 +598,13 @@ def test_file_7() -> None:
|
|||||||
|
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
with pytest.raises(InvalidDataError):
|
with pytest.raises(InvalidDataError):
|
||||||
layout = OasisLayout.read(buf)
|
_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
|
File with TEXT record that uses an un-filled modal for the datatype
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
||||||
@ -632,13 +629,13 @@ def test_file_8() -> None:
|
|||||||
|
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
with pytest.raises(InvalidDataError):
|
with pytest.raises(InvalidDataError):
|
||||||
layout = OasisLayout.read(buf)
|
_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
|
File with TEXT record that uses a default modal for the x coordinate
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
||||||
@ -671,10 +668,10 @@ def test_file_9() -> None:
|
|||||||
assert text.y == -200
|
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
|
File with TEXT record that uses a default modal for the y coordinate
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
||||||
@ -707,10 +704,10 @@ def test_file_10() -> None:
|
|||||||
assert text.x == 100
|
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
|
File with TEXT record that uses an un-filled modal for the text string
|
||||||
'''
|
"""
|
||||||
buf.write(HEADER)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
|
||||||
@ -735,4 +732,4 @@ def test_file_11() -> None:
|
|||||||
|
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
with pytest.raises(InvalidDataError):
|
with pytest.raises(InvalidDataError):
|
||||||
layout = OasisLayout.read(buf)
|
_layout = OasisLayout.read(buf)
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
# type: ignore
|
# mypy: disable-error-code="union-attr"
|
||||||
|
from typing import IO
|
||||||
from typing import List, Tuple, Iterable
|
from io import BytesIO
|
||||||
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 .utils import HEADER, FOOTER
|
||||||
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
|
from ..basic import write_uint, write_sint, write_bstring, write_byte
|
||||||
from ..basic import InvalidRecordError, InvalidDataError
|
|
||||||
from ..main import OasisLayout
|
from ..main import OasisLayout
|
||||||
|
|
||||||
|
|
||||||
@ -32,9 +24,9 @@ def base_tests(layout: OasisLayout) -> None:
|
|||||||
assert not layout.cells[0].properties
|
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)
|
buf.write(HEADER)
|
||||||
|
|
||||||
write_uint(buf, 14) # CELL record (explicit)
|
write_uint(buf, 14) # CELL record (explicit)
|
||||||
@ -217,7 +209,7 @@ def test_file_1() -> None:
|
|||||||
|
|
||||||
if ii in (0, 4):
|
if ii in (0, 4):
|
||||||
assert gg.delta_a == -20, msg
|
assert gg.delta_a == -20, msg
|
||||||
elif 8 <= ii:
|
elif ii >= 8:
|
||||||
assert gg.delta_a == 0, msg
|
assert gg.delta_a == 0, msg
|
||||||
else:
|
else:
|
||||||
assert gg.delta_a == 20, msg
|
assert gg.delta_a == 20, msg
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
from typing import List, Tuple, Iterable
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import pytest # type: ignore
|
|
||||||
|
|
||||||
from ..basic import read_uint, read_sint, write_uint, write_sint
|
from ..basic import read_uint, read_sint, write_uint, write_sint
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
from typing import List, Tuple, Iterable
|
from io import BytesIO
|
||||||
from itertools import chain
|
|
||||||
from io import BytesIO, BufferedIOBase
|
|
||||||
import struct
|
|
||||||
|
|
||||||
import pytest # type: ignore
|
from ..basic import write_uint, write_bstring, write_byte
|
||||||
|
|
||||||
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte
|
|
||||||
from ..main import OasisLayout
|
|
||||||
|
|
||||||
|
|
||||||
MAGIC_BYTES = b'%SEMI-OASIS\r\n'
|
MAGIC_BYTES = b'%SEMI-OASIS\r\n'
|
||||||
|
@ -44,7 +44,7 @@ classifiers = [
|
|||||||
"Topic :: Scientific/Engineering",
|
"Topic :: Scientific/Engineering",
|
||||||
"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
|
"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
|
||||||
]
|
]
|
||||||
requires-python = ">=3.8"
|
requires-python = ">=3.11"
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
]
|
]
|
||||||
@ -53,4 +53,38 @@ dependencies = [
|
|||||||
path = "fatamorgana/__init__.py"
|
path = "fatamorgana/__init__.py"
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
numpy = ["numpy~=1.21"]
|
numpy = ["numpy>=1.26"]
|
||||||
|
|
||||||
|
|
||||||
|
[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
|
||||||
|
]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user