flake8-aided fixes
This commit is contained in:
parent
db9b39dbc0
commit
6b01b43559
29 changed files with 241 additions and 349 deletions
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
DXF file format readers and writers
|
||||
"""
|
||||
from typing import List, Any, Dict, Tuple, Callable, Union, Sequence, Iterable, Mapping
|
||||
from typing import List, Any, Dict, Tuple, Callable, Union, Iterable, Mapping
|
||||
import re
|
||||
import io
|
||||
import base64
|
||||
|
|
@ -17,7 +17,6 @@ from .. import Pattern, Ref, PatternError, Label, Shape
|
|||
from ..shapes import Polygon, Path
|
||||
from ..repetition import Grid
|
||||
from ..utils import rotation_matrix_2d, layer_t
|
||||
from .gdsii import check_valid_names
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -52,8 +51,11 @@ def write(
|
|||
DXF does not support shape repetition (only block repeptition). Please call
|
||||
library.wrap_repeated_shapes() before writing to file.
|
||||
|
||||
If you want pattern polygonized with non-default arguments, just call `pattern.polygonize()`
|
||||
prior to calling this function.
|
||||
Other functions you may want to call:
|
||||
- `masque.file.oasis.check_valid_names(library.keys())` to check for invalid names
|
||||
- `library.dangling_references()` to check for references to missing patterns
|
||||
- `pattern.polygonize()` for any patterns with shapes other
|
||||
than `masque.shapes.Polygon` or `masque.shapes.Path`
|
||||
|
||||
Only `Grid` repetition objects with manhattan basis vectors are preserved as arrays. Since DXF
|
||||
rotations apply to basis vectors while `masque`'s rotations do not, the basis vectors of an
|
||||
|
|
@ -70,8 +72,6 @@ def write(
|
|||
"""
|
||||
#TODO consider supporting DXF arcs?
|
||||
|
||||
check_valid_names(library.keys())
|
||||
|
||||
pattern = library[top_name]
|
||||
|
||||
# Create library
|
||||
|
|
@ -83,7 +83,7 @@ def write(
|
|||
|
||||
# Now create a block for each referenced pattern, and add in any shapes
|
||||
for name, pat in library.items():
|
||||
assert(pat is not None)
|
||||
assert pat is not None
|
||||
block = lib.blocks.new(name=name)
|
||||
|
||||
_shapes_to_elements(block, pat.shapes)
|
||||
|
|
@ -173,8 +173,9 @@ def read(
|
|||
msp = lib.modelspace()
|
||||
|
||||
npat = _read_block(msp, clean_vertices)
|
||||
patterns_dict = dict([npat]
|
||||
+ [_read_block(bb, clean_vertices) for bb in lib.blocks if bb.name != '*Model_Space'])
|
||||
patterns_dict = dict(
|
||||
[npat] + [_read_block(bb, clean_vertices) for bb in lib.blocks if bb.name != '*Model_Space']
|
||||
)
|
||||
|
||||
library_info = {
|
||||
'layers': [ll.dxfattribs() for ll in lib.layers]
|
||||
|
|
@ -323,8 +324,10 @@ def _shapes_to_elements(
|
|||
# Could set do paths with width setting, but need to consider endcaps.
|
||||
for shape in shapes:
|
||||
if shape.repetition is not None:
|
||||
raise PatternError('Shape repetitions are not supported by DXF.'
|
||||
' Please call library.wrap_repeated_shapes() before writing to file.')
|
||||
raise PatternError(
|
||||
'Shape repetitions are not supported by DXF.'
|
||||
' Please call library.wrap_repeated_shapes() before writing to file.'
|
||||
)
|
||||
|
||||
attribs = {'layer': _mlayer2dxf(shape.layer)}
|
||||
for polygon in shape.to_polygons():
|
||||
|
|
|
|||
|
|
@ -18,14 +18,10 @@ Notes:
|
|||
* GDS does not support library- or structure-level annotations
|
||||
* Creation/modification/access times are set to 1900-01-01 for reproducibility.
|
||||
"""
|
||||
from typing import List, Any, Dict, Tuple, Callable, Union, Iterable, Optional
|
||||
from typing import Sequence, BinaryIO, Mapping, cast
|
||||
import re
|
||||
from typing import List, Any, Dict, Tuple, Callable, Union, Iterable
|
||||
from typing import BinaryIO, Mapping
|
||||
import io
|
||||
import mmap
|
||||
import copy
|
||||
import base64
|
||||
import struct
|
||||
import logging
|
||||
import pathlib
|
||||
import gzip
|
||||
|
|
@ -83,10 +79,13 @@ def write(
|
|||
otherwise `0`
|
||||
|
||||
GDS does not support shape repetition (only cell repeptition). Please call
|
||||
library.wrap_repeated_shapes() before writing to file.
|
||||
`library.wrap_repeated_shapes()` before writing to file.
|
||||
|
||||
If you want pattern polygonized with non-default arguments, just call `pattern.polygonize()`
|
||||
prior to calling this function.
|
||||
Other functions you may want to call:
|
||||
- `masque.file.gdsii.check_valid_names(library.keys())` to check for invalid names
|
||||
- `library.dangling_references()` to check for references to missing patterns
|
||||
- `pattern.polygonize()` for any patterns with shapes other
|
||||
than `masque.shapes.Polygon` or `masque.shapes.Path`
|
||||
|
||||
Args:
|
||||
library: A {name: Pattern} mapping of patterns to write.
|
||||
|
|
@ -98,10 +97,6 @@ def write(
|
|||
library_name: Library name written into the GDSII file.
|
||||
Default 'masque-klamath'.
|
||||
"""
|
||||
check_valid_names(library.keys())
|
||||
|
||||
# TODO check all hierarchy present
|
||||
|
||||
if not isinstance(library, MutableLibrary):
|
||||
if isinstance(library, dict):
|
||||
library = WrapLibrary(library)
|
||||
|
|
@ -433,7 +428,7 @@ def _shapes_to_elements(
|
|||
for shape in shapes:
|
||||
if shape.repetition is not None:
|
||||
raise PatternError('Shape repetitions are not supported by GDS.'
|
||||
' Please call library.wrap_repeated_shapes() before writing to file.')
|
||||
' Please call library.wrap_repeated_shapes() before writing to file.')
|
||||
|
||||
layer, data_type = _mlayer2gds(shape.layer)
|
||||
properties = _annotations_to_properties(shape.annotations, 128)
|
||||
|
|
@ -504,56 +499,6 @@ def _labels_to_texts(labels: List[Label]) -> List[klamath.elements.Text]:
|
|||
return texts
|
||||
|
||||
|
||||
def disambiguate_pattern_names(
|
||||
names: Iterable[str],
|
||||
max_name_length: int = 32,
|
||||
suffix_length: int = 6,
|
||||
) -> List[str]:
|
||||
"""
|
||||
Args:
|
||||
names: List of pattern names to disambiguate
|
||||
max_name_length: Names longer than this will be truncated
|
||||
suffix_length: Names which get truncated are truncated by this many extra characters. This is to
|
||||
leave room for a suffix if one is necessary.
|
||||
"""
|
||||
new_names = []
|
||||
for name in names:
|
||||
# Shorten names which already exceed max-length
|
||||
if len(name) > max_name_length:
|
||||
shortened_name = name[:max_name_length - suffix_length]
|
||||
logger.warning(f'Pattern name "{name}" is too long ({len(name)}/{max_name_length} chars),\n'
|
||||
+ f' shortening to "{shortened_name}" before generating suffix')
|
||||
else:
|
||||
shortened_name = name
|
||||
|
||||
# Remove invalid characters
|
||||
sanitized_name = re.compile(r'[^A-Za-z0-9_\?\$]').sub('_', shortened_name)
|
||||
|
||||
# Add a suffix that makes the name unique
|
||||
i = 0
|
||||
suffixed_name = sanitized_name
|
||||
while suffixed_name in new_names or suffixed_name == '':
|
||||
suffix = base64.b64encode(struct.pack('>Q', i), b'$?').decode('ASCII')
|
||||
|
||||
suffixed_name = sanitized_name + '$' + suffix[:-1].lstrip('A')
|
||||
i += 1
|
||||
|
||||
if sanitized_name == '':
|
||||
logger.warning(f'Empty pattern name saved as "{suffixed_name}"')
|
||||
|
||||
# Encode into a byte-string and perform some final checks
|
||||
encoded_name = suffixed_name.encode('ASCII')
|
||||
if len(encoded_name) == 0:
|
||||
# Should never happen since zero-length names are replaced
|
||||
raise PatternError(f'Zero-length name after sanitize+encode,\n originally "{name}"')
|
||||
if len(encoded_name) > max_name_length:
|
||||
raise PatternError(f'Pattern name "{encoded_name!r}" length > {max_name_length} after encode,\n'
|
||||
+ f' originally "{name}"')
|
||||
|
||||
new_names.append(suffixed_name)
|
||||
return new_names
|
||||
|
||||
|
||||
def load_library(
|
||||
stream: BinaryIO,
|
||||
*,
|
||||
|
|
|
|||
|
|
@ -12,11 +12,7 @@ Note that OASIS references follow the same convention as `masque`,
|
|||
vectors or offsets.
|
||||
"""
|
||||
from typing import List, Any, Dict, Tuple, Callable, Union, Sequence, Iterable, Mapping, Optional, cast
|
||||
import re
|
||||
import io
|
||||
import copy
|
||||
import base64
|
||||
import struct
|
||||
import logging
|
||||
import pathlib
|
||||
import gzip
|
||||
|
|
@ -77,8 +73,11 @@ def build(
|
|||
If a layer map is provided, layer strings will be converted
|
||||
automatically, and layer names will be written to the file.
|
||||
|
||||
If you want pattern polygonized with non-default arguments, just call `pattern.polygonize()`
|
||||
prior to calling this function.
|
||||
Other functions you may want to call:
|
||||
- `masque.file.oasis.check_valid_names(library.keys())` to check for invalid names
|
||||
- `library.dangling_references()` to check for references to missing patterns
|
||||
- `pattern.polygonize()` for any patterns with shapes other
|
||||
than `masque.shapes.Polygon`, `masque.shapes.Path`, or `masque.shapes.Circle`
|
||||
|
||||
Args:
|
||||
library: A {name: Pattern} mapping of patterns to write.
|
||||
|
|
@ -97,10 +96,6 @@ def build(
|
|||
Returns:
|
||||
`fatamorgana.OasisLayout`
|
||||
"""
|
||||
check_valid_names(library.keys())
|
||||
|
||||
# TODO check all hierarchy present
|
||||
|
||||
if not isinstance(library, MutableLibrary):
|
||||
if isinstance(library, dict):
|
||||
library = WrapLibrary(library)
|
||||
|
|
@ -130,7 +125,7 @@ def build(
|
|||
for tt in (True, False)]
|
||||
|
||||
def layer2oas(mlayer: layer_t) -> Tuple[int, int]:
|
||||
assert(layer_map is not None)
|
||||
assert layer_map is not None
|
||||
layer_num = layer_map[mlayer] if isinstance(mlayer, str) else mlayer
|
||||
return _mlayer2oas(layer_num)
|
||||
else:
|
||||
|
|
@ -270,7 +265,7 @@ def read(
|
|||
# note XELEMENT has no repetition
|
||||
continue
|
||||
|
||||
assert(not isinstance(element.repetition, fatamorgana.ReuseRepetition))
|
||||
assert not isinstance(element.repetition, fatamorgana.ReuseRepetition)
|
||||
repetition = repetition_fata2masq(element.repetition)
|
||||
|
||||
# Switch based on element type:
|
||||
|
|
@ -481,7 +476,7 @@ def _placement_to_ref(placement: fatrec.Placement, lib: fatamorgana.OasisLayout)
|
|||
"""
|
||||
Helper function to create a Ref from a placment. Sets ref.target to the placement name.
|
||||
"""
|
||||
assert(not isinstance(placement.repetition, fatamorgana.ReuseRepetition))
|
||||
assert not isinstance(placement.repetition, fatamorgana.ReuseRepetition)
|
||||
xy = numpy.array((placement.x, placement.y))
|
||||
mag = placement.magnification if placement.magnification is not None else 1
|
||||
|
||||
|
|
@ -659,7 +654,7 @@ def repetition_masq2fata(
|
|||
frep = fatamorgana.ArbitraryRepetition(diff_ints[:, 0], diff_ints[:, 1]) # type: ignore
|
||||
offset = rep.displacements[0, :]
|
||||
else:
|
||||
assert(rep is None)
|
||||
assert rep is None
|
||||
frep = None
|
||||
offset = (0, 0)
|
||||
return frep, offset
|
||||
|
|
@ -682,14 +677,14 @@ def properties_to_annotations(
|
|||
) -> annotations_t:
|
||||
annotations = {}
|
||||
for proprec in properties:
|
||||
assert(proprec.name is not None)
|
||||
assert proprec.name is not None
|
||||
if isinstance(proprec.name, int):
|
||||
key = propnames[proprec.name].string
|
||||
else:
|
||||
key = proprec.name.string
|
||||
values: List[Union[str, float, int]] = []
|
||||
|
||||
assert(proprec.values is not None)
|
||||
assert proprec.values is not None
|
||||
for value in proprec.values:
|
||||
if isinstance(value, (float, int)):
|
||||
values.append(value)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
SVG file format readers and writers
|
||||
"""
|
||||
from typing import Dict, Optional, Mapping
|
||||
from typing import Mapping
|
||||
import warnings
|
||||
|
||||
import numpy
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
"""
|
||||
Helper functions for file reading and writing
|
||||
"""
|
||||
from typing import Set, Tuple, List, Iterable, Mapping
|
||||
import re
|
||||
import copy
|
||||
import pathlib
|
||||
import logging
|
||||
|
||||
from .. import Pattern, PatternError
|
||||
from ..library import Library, WrapROLibrary
|
||||
from ..shapes import Polygon, Path
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue