forked from jan/fatamorgana
Modernize type annotations
This commit is contained in:
parent
d61bbc530f
commit
a4c1e52ff8
@ -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
|
||||
|
||||
|
||||
|
@ -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,10 +891,13 @@ class ManhattanDelta:
|
||||
class OctangularDelta:
|
||||
"""
|
||||
Class representing an axis-aligned or 45-degree ("Octangular") vector.
|
||||
"""
|
||||
proj_mag: int
|
||||
"""projection of the vector onto the x or y axis (non-zero)"""
|
||||
|
||||
Attributes:
|
||||
proj_mag (int): projection of the vector onto the x or y axis (non-zero)
|
||||
octangle (int): bitfield:
|
||||
octangle: int
|
||||
"""
|
||||
bitfield:
|
||||
bit 2: 1 if non-axis-aligned (non-Manhattan)
|
||||
if Manhattan:
|
||||
bit 1: 1 if direction is negative
|
||||
@ -909,8 +911,6 @@ class OctangularDelta:
|
||||
4: +x+y, 5: -x+y,
|
||||
6: +x-y, 7: -x-y
|
||||
"""
|
||||
proj_mag: int
|
||||
octangle: int
|
||||
|
||||
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.
|
||||
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
|
||||
a_vector: list[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,
|
||||
"""
|
||||
|
||||
b_vector: list[int] | None = None
|
||||
"""`(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
|
||||
"""
|
||||
|
||||
a_count: int
|
||||
"""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`.
|
||||
"""
|
||||
a_vector: List[int]
|
||||
b_vector: Optional[List[int]] = None
|
||||
a_count: int
|
||||
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):
|
||||
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)
|
||||
|
@ -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,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 = [
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user