reformat some multiline arg lists and add missing 'None' return types

nolock
jan 2 years ago
parent 250107e41b
commit 89f327ba37

@ -167,7 +167,8 @@ class Device(Copyable, Mirrorable):
_dead: bool _dead: bool
""" If True, plug()/place() are skipped (for debugging)""" """ If True, plug()/place() are skipped (for debugging)"""
def __init__(self, def __init__(
self,
pattern: Optional[Pattern] = None, pattern: Optional[Pattern] = None,
ports: Optional[Dict[str, Port]] = None, ports: Optional[Dict[str, Port]] = None,
*, *,
@ -218,7 +219,8 @@ class Device(Copyable, Mirrorable):
else: else:
return {k: self.ports[k] for k in key} return {k: self.ports[k] for k in key}
def rename_ports(self: D, def rename_ports(
self: D,
mapping: Dict[str, Optional[str]], mapping: Dict[str, Optional[str]],
overwrite: bool = False, overwrite: bool = False,
) -> D: ) -> D:
@ -248,7 +250,8 @@ class Device(Copyable, Mirrorable):
self.ports.update(renamed) # type: ignore self.ports.update(renamed) # type: ignore
return self return self
def check_ports(self: D, def check_ports(
self: D,
other_names: Iterable[str], other_names: Iterable[str],
map_in: Optional[Dict[str, str]] = None, map_in: Optional[Dict[str, str]] = None,
map_out: Optional[Dict[str, Optional[str]]] = None, map_out: Optional[Dict[str, Optional[str]]] = None,
@ -332,7 +335,8 @@ class Device(Copyable, Mirrorable):
new = Device(pat, ports=self.ports) new = Device(pat, ports=self.ports)
return new return new
def as_interface(self, def as_interface(
self,
name: str, name: str,
in_prefix: str = 'in_', in_prefix: str = 'in_',
out_prefix: str = '', out_prefix: str = '',
@ -406,7 +410,8 @@ class Device(Copyable, Mirrorable):
new = Device(name=name, ports={**ports_in, **ports_out}) new = Device(name=name, ports={**ports_in, **ports_out})
return new return new
def plug(self: D, def plug(
self: D,
other: O, other: O,
map_in: Dict[str, str], map_in: Dict[str, str],
map_out: Optional[Dict[str, Optional[str]]] = None, map_out: Optional[Dict[str, Optional[str]]] = None,
@ -495,7 +500,8 @@ class Device(Copyable, Mirrorable):
mirrored=mirrored, port_map=map_out, skip_port_check=True) mirrored=mirrored, port_map=map_out, skip_port_check=True)
return self return self
def place(self: D, def place(
self: D,
other: O, other: O,
*, *,
offset: vector2 = (0, 0), offset: vector2 = (0, 0),
@ -572,7 +578,8 @@ class Device(Copyable, Mirrorable):
self.pattern.subpatterns.append(sp) self.pattern.subpatterns.append(sp)
return self return self
def find_transform(self: D, def find_transform(
self: D,
other: O, other: O,
map_in: Dict[str, str], map_in: Dict[str, str],
*, *,
@ -745,7 +752,11 @@ class Device(Copyable, Mirrorable):
return s return s
def rotate_offsets_around(offsets: ArrayLike, pivot: ArrayLike, angle: float) -> numpy.ndarray: def rotate_offsets_around(
offsets: ArrayLike,
pivot: ArrayLike,
angle: float,
) -> numpy.ndarray:
offsets -= pivot offsets -= pivot
offsets[:] = (rotation_matrix_2d(angle) @ offsets.T).T offsets[:] = (rotation_matrix_2d(angle) @ offsets.T).T
offsets += pivot offsets += pivot

@ -9,7 +9,8 @@ from ..utils import rotation_matrix_2d, vector2
from ..error import BuildError from ..error import BuildError
def ell(ports: Dict[str, Port], def ell(
ports: Dict[str, Port],
ccw: Optional[bool], ccw: Optional[bool],
bound_type: str, bound_type: str,
bound: Union[float, vector2], bound: Union[float, vector2],

@ -28,7 +28,8 @@ logger.warning('DXF support is experimental and only slightly tested!')
DEFAULT_LAYER = 'DEFAULT' DEFAULT_LAYER = 'DEFAULT'
def write(pattern: Pattern, def write(
pattern: Pattern,
stream: io.TextIOBase, stream: io.TextIOBase,
*, *,
modify_originals: bool = False, modify_originals: bool = False,
@ -99,7 +100,8 @@ def write(pattern: Pattern,
lib.write(stream) lib.write(stream)
def writefile(pattern: Pattern, def writefile(
pattern: Pattern,
filename: Union[str, pathlib.Path], filename: Union[str, pathlib.Path],
*args, *args,
**kwargs, **kwargs,
@ -125,7 +127,8 @@ def writefile(pattern: Pattern,
write(pattern, stream, *args, **kwargs) write(pattern, stream, *args, **kwargs)
def readfile(filename: Union[str, pathlib.Path], def readfile(
filename: Union[str, pathlib.Path],
*args, *args,
**kwargs, **kwargs,
) -> Tuple[Pattern, Dict[str, Any]]: ) -> Tuple[Pattern, Dict[str, Any]]:
@ -150,7 +153,8 @@ def readfile(filename: Union[str, pathlib.Path],
return results return results
def read(stream: io.TextIOBase, def read(
stream: io.TextIOBase,
clean_vertices: bool = True, clean_vertices: bool = True,
) -> Tuple[Pattern, Dict[str, Any]]: ) -> Tuple[Pattern, Dict[str, Any]]:
""" """
@ -273,8 +277,10 @@ def _read_block(block, clean_vertices: bool) -> Pattern:
return pat return pat
def _subpatterns_to_refs(block: Union[ezdxf.layouts.BlockLayout, ezdxf.layouts.Modelspace], def _subpatterns_to_refs(
subpatterns: List[SubPattern]) -> None: block: Union[ezdxf.layouts.BlockLayout, ezdxf.layouts.Modelspace],
subpatterns: List[SubPattern],
) -> None:
for subpat in subpatterns: for subpat in subpatterns:
if subpat.pattern is None: if subpat.pattern is None:
continue continue
@ -318,9 +324,11 @@ def _subpatterns_to_refs(block: Union[ezdxf.layouts.BlockLayout, ezdxf.layouts.M
block.add_blockref(encoded_name, subpat.offset + dd, dxfattribs=attribs) block.add_blockref(encoded_name, subpat.offset + dd, dxfattribs=attribs)
def _shapes_to_elements(block: Union[ezdxf.layouts.BlockLayout, ezdxf.layouts.Modelspace], def _shapes_to_elements(
block: Union[ezdxf.layouts.BlockLayout, ezdxf.layouts.Modelspace],
shapes: List[Shape], shapes: List[Shape],
polygonize_paths: bool = False): polygonize_paths: bool = False,
) -> None:
# Add `LWPolyline`s for each shape. # Add `LWPolyline`s for each shape.
# Could set do paths with width setting, but need to consider endcaps. # Could set do paths with width setting, but need to consider endcaps.
for shape in shapes: for shape in shapes:
@ -331,8 +339,10 @@ def _shapes_to_elements(block: Union[ezdxf.layouts.BlockLayout, ezdxf.layouts.Mo
block.add_lwpolyline(xy_closed, dxfattribs=attribs) block.add_lwpolyline(xy_closed, dxfattribs=attribs)
def _labels_to_texts(block: Union[ezdxf.layouts.BlockLayout, ezdxf.layouts.Modelspace], def _labels_to_texts(
labels: List[Label]) -> None: block: Union[ezdxf.layouts.BlockLayout, ezdxf.layouts.Modelspace],
labels: List[Label],
) -> None:
for label in labels: for label in labels:
attribs = {'layer': _mlayer2dxf(label.layer)} attribs = {'layer': _mlayer2dxf(label.layer)}
xy = label.offset xy = label.offset
@ -349,7 +359,8 @@ def _mlayer2dxf(layer: layer_t) -> str:
raise PatternError(f'Unknown layer type: {layer} ({type(layer)})') raise PatternError(f'Unknown layer type: {layer} ({type(layer)})')
def disambiguate_pattern_names(patterns: Iterable[Pattern], def disambiguate_pattern_names(
patterns: Iterable[Pattern],
max_name_length: int = 32, max_name_length: int = 32,
suffix_length: int = 6, suffix_length: int = 6,
dup_warn_filter: Callable[[str], bool] = None, # If returns False, don't warn about this name dup_warn_filter: Callable[[str], bool] = None, # If returns False, don't warn about this name

@ -52,7 +52,8 @@ path_cap_map = {
} }
def write(patterns: Union[Pattern, Sequence[Pattern]], def write(
patterns: Union[Pattern, Sequence[Pattern]],
stream: BinaryIO, stream: BinaryIO,
meters_per_unit: float, meters_per_unit: float,
logical_units_per_unit: float = 1, logical_units_per_unit: float = 1,
@ -136,7 +137,8 @@ def write(patterns: Union[Pattern, Sequence[Pattern]],
records.ENDLIB.write(stream, None) records.ENDLIB.write(stream, None)
def writefile(patterns: Union[Sequence[Pattern], Pattern], def writefile(
patterns: Union[Sequence[Pattern], Pattern],
filename: Union[str, pathlib.Path], filename: Union[str, pathlib.Path],
*args, *args,
**kwargs, **kwargs,
@ -162,7 +164,8 @@ def writefile(patterns: Union[Sequence[Pattern], Pattern],
write(patterns, stream, *args, **kwargs) write(patterns, stream, *args, **kwargs)
def readfile(filename: Union[str, pathlib.Path], def readfile(
filename: Union[str, pathlib.Path],
*args, *args,
**kwargs, **kwargs,
) -> Tuple[Dict[str, Pattern], Dict[str, Any]]: ) -> Tuple[Dict[str, Pattern], Dict[str, Any]]:
@ -187,7 +190,8 @@ def readfile(filename: Union[str, pathlib.Path],
return results return results
def read(stream: BinaryIO, def read(
stream: BinaryIO,
raw_mode: bool = True, raw_mode: bool = True,
) -> Tuple[Dict[str, Pattern], Dict[str, Any]]: ) -> Tuple[Dict[str, Pattern], Dict[str, Any]]:
""" """
@ -243,7 +247,8 @@ def _read_header(stream: BinaryIO) -> Dict[str, Any]:
return library_info return library_info
def read_elements(stream: BinaryIO, def read_elements(
stream: BinaryIO,
name: str, name: str,
raw_mode: bool = True, raw_mode: bool = True,
) -> Pattern: ) -> Pattern:
@ -296,8 +301,7 @@ def _mlayer2gds(mlayer: layer_t) -> Tuple[int, int]:
return layer, data_type return layer, data_type
def _ref_to_subpat(ref: klamath.library.Reference, def _ref_to_subpat(ref: klamath.library.Reference) -> SubPattern:
) -> SubPattern:
""" """
Helper function to create a SubPattern from an SREF or AREF. Sets subpat.pattern to None Helper function to create a SubPattern from an SREF or AREF. Sets subpat.pattern to None
and sets the instance .identifier to (struct_name,). and sets the instance .identifier to (struct_name,).
@ -351,8 +355,7 @@ def _boundary_to_polygon(boundary: klamath.library.Boundary, raw_mode: bool) ->
) )
def _subpatterns_to_refs(subpatterns: List[SubPattern] def _subpatterns_to_refs(subpatterns: List[SubPattern]) -> List[klamath.library.Reference]:
) -> List[klamath.library.Reference]:
refs = [] refs = []
for subpat in subpatterns: for subpat in subpatterns:
if subpat.pattern is None: if subpat.pattern is None:
@ -427,8 +430,9 @@ def _annotations_to_properties(annotations: annotations_t, max_len: int = 126) -
return props return props
def _shapes_to_elements(shapes: List[Shape], def _shapes_to_elements(
polygonize_paths: bool = False shapes: List[Shape],
polygonize_paths: bool = False,
) -> List[klamath.elements.Element]: ) -> List[klamath.elements.Element]:
elements: List[klamath.elements.Element] = [] elements: List[klamath.elements.Element] = []
# Add a Boundary element for each shape, and Path elements if necessary # Add a Boundary element for each shape, and Path elements if necessary
@ -492,11 +496,12 @@ def _labels_to_texts(labels: List[Label]) -> List[klamath.elements.Text]:
return texts return texts
def disambiguate_pattern_names(patterns: Sequence[Pattern], def disambiguate_pattern_names(
patterns: Sequence[Pattern],
max_name_length: int = 32, max_name_length: int = 32,
suffix_length: int = 6, suffix_length: int = 6,
dup_warn_filter: Optional[Callable[[str], bool]] = None, dup_warn_filter: Optional[Callable[[str], bool]] = None,
): ) -> None:
""" """
Args: Args:
patterns: List of patterns to disambiguate patterns: List of patterns to disambiguate
@ -549,7 +554,8 @@ def disambiguate_pattern_names(patterns: Sequence[Pattern],
used_names.append(suffixed_name) used_names.append(suffixed_name)
def load_library(stream: BinaryIO, def load_library(
stream: BinaryIO,
tag: str, tag: str,
is_secondary: Optional[Callable[[str], bool]] = None, is_secondary: Optional[Callable[[str], bool]] = None,
*, *,
@ -581,7 +587,7 @@ def load_library(stream: BinaryIO,
Additional library info (dict, same format as from `read`). Additional library info (dict, same format as from `read`).
""" """
if is_secondary is None: if is_secondary is None:
def is_secondary(k: str): def is_secondary(k: str) -> bool:
return False return False
assert(is_secondary is not None) assert(is_secondary is not None)
@ -611,7 +617,8 @@ def load_library(stream: BinaryIO,
return lib, library_info return lib, library_info
def load_libraryfile(filename: Union[str, pathlib.Path], def load_libraryfile(
filename: Union[str, pathlib.Path],
tag: str, tag: str,
is_secondary: Optional[Callable[[str], bool]] = None, is_secondary: Optional[Callable[[str], bool]] = None,
*, *,

@ -47,13 +47,14 @@ path_cap_map = {
#TODO implement more shape types? #TODO implement more shape types?
def build(patterns: Union[Pattern, Sequence[Pattern]], def build(
patterns: Union[Pattern, Sequence[Pattern]],
units_per_micron: int, units_per_micron: int,
layer_map: Optional[Dict[str, Union[int, Tuple[int, int]]]] = None, layer_map: Optional[Dict[str, Union[int, Tuple[int, int]]]] = None,
*, *,
modify_originals: bool = False, modify_originals: bool = False,
disambiguate_func: Optional[Callable[[Iterable[Pattern]], None]] = None, disambiguate_func: Optional[Callable[[Iterable[Pattern]], None]] = None,
annotations: Optional[annotations_t] = None annotations: Optional[annotations_t] = None,
) -> fatamorgana.OasisLayout: ) -> fatamorgana.OasisLayout:
""" """
Convert a `Pattern` or list of patterns to an OASIS stream, writing patterns Convert a `Pattern` or list of patterns to an OASIS stream, writing patterns
@ -153,10 +154,12 @@ def build(patterns: Union[Pattern, Sequence[Pattern]],
return lib return lib
def write(patterns: Union[Sequence[Pattern], Pattern], def write(
patterns: Union[Sequence[Pattern], Pattern],
stream: io.BufferedIOBase, stream: io.BufferedIOBase,
*args, *args,
**kwargs): **kwargs,
) -> None:
""" """
Write a `Pattern` or list of patterns to a OASIS file. See `oasis.build()` Write a `Pattern` or list of patterns to a OASIS file. See `oasis.build()`
for details. for details.
@ -171,11 +174,12 @@ def write(patterns: Union[Sequence[Pattern], Pattern],
lib.write(stream) lib.write(stream)
def writefile(patterns: Union[Sequence[Pattern], Pattern], def writefile(
patterns: Union[Sequence[Pattern], Pattern],
filename: Union[str, pathlib.Path], filename: Union[str, pathlib.Path],
*args, *args,
**kwargs, **kwargs,
): ) -> None:
""" """
Wrapper for `oasis.write()` that takes a filename or path instead of a stream. Wrapper for `oasis.write()` that takes a filename or path instead of a stream.
@ -198,7 +202,8 @@ def writefile(patterns: Union[Sequence[Pattern], Pattern],
return results return results
def readfile(filename: Union[str, pathlib.Path], def readfile(
filename: Union[str, pathlib.Path],
*args, *args,
**kwargs, **kwargs,
) -> Tuple[Dict[str, Pattern], Dict[str, Any]]: ) -> Tuple[Dict[str, Pattern], Dict[str, Any]]:
@ -223,7 +228,8 @@ def readfile(filename: Union[str, pathlib.Path],
return results return results
def read(stream: io.BufferedIOBase, def read(
stream: io.BufferedIOBase,
clean_vertices: bool = True, clean_vertices: bool = True,
) -> Tuple[Dict[str, Pattern], Dict[str, Any]]: ) -> Tuple[Dict[str, Pattern], Dict[str, Any]]:
""" """
@ -496,7 +502,8 @@ def _placement_to_subpat(placement: fatrec.Placement, lib: fatamorgana.OasisLayo
return subpat return subpat
def _subpatterns_to_placements(subpatterns: List[SubPattern] def _subpatterns_to_placements(
subpatterns: List[SubPattern],
) -> List[fatrec.Placement]: ) -> List[fatrec.Placement]:
refs = [] refs = []
for subpat in subpatterns: for subpat in subpatterns:
@ -523,7 +530,8 @@ def _subpatterns_to_placements(subpatterns: List[SubPattern]
return refs return refs
def _shapes_to_elements(shapes: List[Shape], def _shapes_to_elements(
shapes: List[Shape],
layer2oas: Callable[[layer_t], Tuple[int, int]], layer2oas: Callable[[layer_t], Tuple[int, int]],
) -> List[Union[fatrec.Polygon, fatrec.Path, fatrec.Circle]]: ) -> List[Union[fatrec.Polygon, fatrec.Path, fatrec.Circle]]:
# Add a Polygon record for each shape, and Path elements if necessary # Add a Polygon record for each shape, and Path elements if necessary
@ -576,7 +584,8 @@ def _shapes_to_elements(shapes: List[Shape],
return elements return elements
def _labels_to_texts(labels: List[Label], def _labels_to_texts(
labels: List[Label],
layer2oas: Callable[[layer_t], Tuple[int, int]], layer2oas: Callable[[layer_t], Tuple[int, int]],
) -> List[fatrec.Text]: ) -> List[fatrec.Text]:
texts = [] texts = []
@ -595,9 +604,10 @@ def _labels_to_texts(labels: List[Label],
return texts return texts
def disambiguate_pattern_names(patterns, def disambiguate_pattern_names(
patterns,
dup_warn_filter: Callable[[str], bool] = None, # If returns False, don't warn about this name dup_warn_filter: Callable[[str], bool] = None, # If returns False, don't warn about this name
): ) -> None:
used_names = [] used_names = []
for pat in patterns: for pat in patterns:
sanitized_name = re.compile(r'[^A-Za-z0-9_\?\$]').sub('_', pat.name) sanitized_name = re.compile(r'[^A-Za-z0-9_\?\$]').sub('_', pat.name)
@ -625,7 +635,8 @@ def disambiguate_pattern_names(patterns,
used_names.append(suffixed_name) used_names.append(suffixed_name)
def repetition_fata2masq(rep: Union[fatamorgana.GridRepetition, fatamorgana.ArbitraryRepetition, None] def repetition_fata2masq(
rep: Union[fatamorgana.GridRepetition, fatamorgana.ArbitraryRepetition, None],
) -> Optional[Repetition]: ) -> Optional[Repetition]:
mrep: Optional[Repetition] mrep: Optional[Repetition]
if isinstance(rep, fatamorgana.GridRepetition): if isinstance(rep, fatamorgana.GridRepetition):
@ -643,7 +654,8 @@ def repetition_fata2masq(rep: Union[fatamorgana.GridRepetition, fatamorgana.Arbi
return mrep return mrep
def repetition_masq2fata(rep: Optional[Repetition] def repetition_masq2fata(
rep: Optional[Repetition],
) -> Tuple[Union[fatamorgana.GridRepetition, ) -> Tuple[Union[fatamorgana.GridRepetition,
fatamorgana.ArbitraryRepetition, fatamorgana.ArbitraryRepetition,
None], None],
@ -678,7 +690,8 @@ def annotations_to_properties(annotations: annotations_t) -> List[fatrec.Propert
return properties return properties
def properties_to_annotations(properties: List[fatrec.Property], def properties_to_annotations(
properties: List[fatrec.Property],
propnames: Dict[int, NString], propnames: Dict[int, NString],
propstrings: Dict[int, AString], propstrings: Dict[int, AString],
) -> annotations_t: ) -> annotations_t:

@ -53,7 +53,8 @@ path_cap_map = {
} }
def build(patterns: Union[Pattern, Sequence[Pattern]], def build(
patterns: Union[Pattern, Sequence[Pattern]],
meters_per_unit: float, meters_per_unit: float,
logical_units_per_unit: float = 1, logical_units_per_unit: float = 1,
library_name: str = 'masque-gdsii-write', library_name: str = 'masque-gdsii-write',
@ -137,10 +138,12 @@ def build(patterns: Union[Pattern, Sequence[Pattern]],
return lib return lib
def write(patterns: Union[Pattern, Sequence[Pattern]], def write(
patterns: Union[Pattern, Sequence[Pattern]],
stream: io.BufferedIOBase, stream: io.BufferedIOBase,
*args, *args,
**kwargs): **kwargs,
) -> None:
""" """
Write a `Pattern` or list of patterns to a GDSII file. Write a `Pattern` or list of patterns to a GDSII file.
See `masque.file.gdsii.build()` for details. See `masque.file.gdsii.build()` for details.
@ -155,11 +158,12 @@ def write(patterns: Union[Pattern, Sequence[Pattern]],
lib.save(stream) lib.save(stream)
return return
def writefile(patterns: Union[Sequence[Pattern], Pattern], def writefile(
patterns: Union[Sequence[Pattern], Pattern],
filename: Union[str, pathlib.Path], filename: Union[str, pathlib.Path],
*args, *args,
**kwargs, **kwargs,
): ) -> None:
""" """
Wrapper for `masque.file.gdsii.write()` that takes a filename or path instead of a stream. Wrapper for `masque.file.gdsii.write()` that takes a filename or path instead of a stream.
@ -182,7 +186,8 @@ def writefile(patterns: Union[Sequence[Pattern], Pattern],
return results return results
def readfile(filename: Union[str, pathlib.Path], def readfile(
filename: Union[str, pathlib.Path],
*args, *args,
**kwargs, **kwargs,
) -> Tuple[Dict[str, Pattern], Dict[str, Any]]: ) -> Tuple[Dict[str, Pattern], Dict[str, Any]]:
@ -207,7 +212,8 @@ def readfile(filename: Union[str, pathlib.Path],
return results return results
def read(stream: io.BufferedIOBase, def read(
stream: io.BufferedIOBase,
clean_vertices: bool = True, clean_vertices: bool = True,
) -> Tuple[Dict[str, Pattern], Dict[str, Any]]: ) -> Tuple[Dict[str, Pattern], Dict[str, Any]]:
""" """
@ -294,7 +300,8 @@ def _mlayer2gds(mlayer: layer_t) -> Tuple[int, int]:
return layer, data_type return layer, data_type
def _ref_to_subpat(element: Union[gdsii.elements.SRef, def _ref_to_subpat(
element: Union[gdsii.elements.SRef,
gdsii.elements.ARef] gdsii.elements.ARef]
) -> SubPattern: ) -> SubPattern:
""" """
@ -379,7 +386,8 @@ def _boundary_to_polygon(element: gdsii.elements.Boundary, raw_mode: bool) -> Po
return Polygon(**args) return Polygon(**args)
def _subpatterns_to_refs(subpatterns: List[SubPattern] def _subpatterns_to_refs(
subpatterns: List[SubPattern],
) -> List[Union[gdsii.elements.ARef, gdsii.elements.SRef]]: ) -> List[Union[gdsii.elements.ARef, gdsii.elements.SRef]]:
refs = [] refs = []
for subpat in subpatterns: for subpat in subpatterns:
@ -450,8 +458,9 @@ def _annotations_to_properties(annotations: annotations_t, max_len: int = 126) -
return props return props
def _shapes_to_elements(shapes: List[Shape], def _shapes_to_elements(
polygonize_paths: bool = False shapes: List[Shape],
polygonize_paths: bool = False,
) -> List[Union[gdsii.elements.Boundary, gdsii.elements.Path]]: ) -> List[Union[gdsii.elements.Boundary, gdsii.elements.Path]]:
elements: List[Union[gdsii.elements.Boundary, gdsii.elements.Path]] = [] elements: List[Union[gdsii.elements.Boundary, gdsii.elements.Path]] = []
# Add a Boundary element for each shape, and Path elements if necessary # Add a Boundary element for each shape, and Path elements if necessary
@ -496,11 +505,12 @@ def _labels_to_texts(labels: List[Label]) -> List[gdsii.elements.Text]:
return texts return texts
def disambiguate_pattern_names(patterns: Sequence[Pattern], def disambiguate_pattern_names(
patterns: Sequence[Pattern],
max_name_length: int = 32, max_name_length: int = 32,
suffix_length: int = 6, suffix_length: int = 6,
dup_warn_filter: Optional[Callable[[str], bool]] = None, dup_warn_filter: Optional[Callable[[str], bool]] = None,
): ) -> None:
""" """
Args: Args:
patterns: List of patterns to disambiguate patterns: List of patterns to disambiguate

@ -11,7 +11,8 @@ from .utils import mangle_name
from .. import Pattern from .. import Pattern
def writefile(pattern: Pattern, def writefile(
pattern: Pattern,
filename: str, filename: str,
custom_attributes: bool = False, custom_attributes: bool = False,
) -> None: ) -> None:

@ -95,7 +95,8 @@ def dtype2dose(pattern: Pattern) -> Pattern:
return pattern return pattern
def dose2dtype(patterns: List[Pattern], def dose2dtype(
patterns: List[Pattern],
) -> Tuple[List[Pattern], List[float]]: ) -> Tuple[List[Pattern], List[float]]:
""" """
For each shape in each pattern, set shape.layer to the tuple For each shape in each pattern, set shape.layer to the tuple

@ -36,10 +36,11 @@ class Label(PositionableImpl, LayerableImpl, LockableImpl, RepeatableImpl, Annot
return self._string return self._string
@string.setter @string.setter
def string(self, val: str): def string(self, val: str) -> None:
self._string = val self._string = val
def __init__(self, def __init__(
self,
string: str, string: str,
*, *,
offset: vector2 = (0.0, 0.0), offset: vector2 = (0.0, 0.0),

@ -143,7 +143,13 @@ class Library:
def __repr__(self) -> str: def __repr__(self) -> str:
return '<Library with keys ' + repr(list(self.primary.keys())) + '>' return '<Library with keys ' + repr(list(self.primary.keys())) + '>'
def set_const(self, key: str, tag: Any, const: 'Pattern', secondary: bool = False) -> None: def set_const(
self,
key: str,
tag: Any,
const: 'Pattern',
secondary: bool = False,
) -> None:
""" """
Convenience function to avoid having to manually wrap Convenience function to avoid having to manually wrap
constant values into callables. constant values into callables.
@ -162,7 +168,13 @@ class Library:
else: else:
self.primary[key] = pg self.primary[key] = pg
def set_value(self, key: str, tag: str, value: Callable[[], 'Pattern'], secondary: bool = False) -> None: def set_value(
self,
key: str,
tag: str,
value: Callable[[], 'Pattern'],
secondary: bool = False,
) -> None:
""" """
Convenience function to automatically build a PatternGenerator. Convenience function to automatically build a PatternGenerator.

@ -53,7 +53,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
name: str name: str
""" A name for this pattern """ """ A name for this pattern """
def __init__(self, def __init__(
self,
name: str = '', name: str = '',
*, *,
shapes: Sequence[Shape] = (), shapes: Sequence[Shape] = (),
@ -141,7 +142,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
self.labels += other_pattern.labels self.labels += other_pattern.labels
return self return self
def subset(self, def subset(
self,
shapes_func: Callable[[Shape], bool] = None, shapes_func: Callable[[Shape], bool] = None,
labels_func: Callable[[Label], bool] = None, labels_func: Callable[[Label], bool] = None,
subpatterns_func: Callable[[SubPattern], bool] = None, subpatterns_func: Callable[[SubPattern], bool] = None,
@ -186,7 +188,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
assert(pat is not None) assert(pat is not None)
return pat return pat
def apply(self, def apply(
self,
func: Callable[[Optional['Pattern']], Optional['Pattern']], func: Callable[[Optional['Pattern']], Optional['Pattern']],
memo: Optional[Dict[int, Optional['Pattern']]] = None, memo: Optional[Dict[int, Optional['Pattern']]] = None,
) -> Optional['Pattern']: ) -> Optional['Pattern']:
@ -229,7 +232,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
pat = memo[pat_id] pat = memo[pat_id]
return pat return pat
def dfs(self: P, def dfs(
self: P,
visit_before: visitor_function_t = None, visit_before: visitor_function_t = None,
visit_after: visitor_function_t = None, visit_after: visitor_function_t = None,
transform: Union[numpy.ndarray, bool, None] = False, transform: Union[numpy.ndarray, bool, None] = False,
@ -237,7 +241,7 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
hierarchy: Tuple[P, ...] = (), hierarchy: Tuple[P, ...] = (),
) -> P: ) -> P:
""" """
Experimental convenience function. Convenience function.
Performs a depth-first traversal of this pattern and its subpatterns. Performs a depth-first traversal of this pattern and its subpatterns.
At each pattern in the tree, the following sequence is called: At each pattern in the tree, the following sequence is called:
``` ```
@ -314,7 +318,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
pat = visit_after(pat, hierarchy=hierarchy, memo=memo, transform=transform) # type: ignore pat = visit_after(pat, hierarchy=hierarchy, memo=memo, transform=transform) # type: ignore
return pat return pat
def polygonize(self: P, def polygonize(
self: P,
poly_num_points: Optional[int] = None, poly_num_points: Optional[int] = None,
poly_max_arclen: Optional[float] = None, poly_max_arclen: Optional[float] = None,
) -> P: ) -> P:
@ -342,7 +347,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
subpat.pattern.polygonize(poly_num_points, poly_max_arclen) subpat.pattern.polygonize(poly_num_points, poly_max_arclen)
return self return self
def manhattanize(self: P, def manhattanize(
self: P,
grid_x: ArrayLike, grid_x: ArrayLike,
grid_y: ArrayLike, grid_y: ArrayLike,
) -> P: ) -> P:
@ -364,7 +370,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
(shape.manhattanize(grid_x, grid_y) for shape in old_shapes))) (shape.manhattanize(grid_x, grid_y) for shape in old_shapes)))
return self return self
def subpatternize(self: P, def subpatternize(
self: P,
recursive: bool = True, recursive: bool = True,
norm_value: int = int(1e6), norm_value: int = int(1e6),
exclude_types: Tuple[Type] = (Polygon,) exclude_types: Tuple[Type] = (Polygon,)
@ -456,7 +463,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
def referenced_patterns_by_id(self, include_none: bool) -> Dict[int, Optional['Pattern']]: def referenced_patterns_by_id(self, include_none: bool) -> Dict[int, Optional['Pattern']]:
pass pass
def referenced_patterns_by_id(self, def referenced_patterns_by_id(
self,
include_none: bool = False, include_none: bool = False,
recursive: bool = True, recursive: bool = True,
) -> Union[Dict[int, Optional['Pattern']], ) -> Union[Dict[int, Optional['Pattern']],
@ -484,7 +492,10 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
ids.update(pat.referenced_patterns_by_id()) ids.update(pat.referenced_patterns_by_id())
return ids return ids
def referenced_patterns_by_name(self, **kwargs: Any) -> List[Tuple[Optional[str], Optional['Pattern']]]: def referenced_patterns_by_name(
self,
**kwargs: Any,
) -> List[Tuple[Optional[str], Optional['Pattern']]]:
""" """
Create a list of `(pat.name, pat)` tuples for all Pattern objects referenced by this Create a list of `(pat.name, pat)` tuples for all Pattern objects referenced by this
Pattern (operates recursively on all referenced Patterns as well). Pattern (operates recursively on all referenced Patterns as well).
@ -502,7 +513,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
pat_list = [(p.name if p is not None else None, p) for p in pats_by_id.values()] pat_list = [(p.name if p is not None else None, p) for p in pats_by_id.values()]
return pat_list return pat_list
def subpatterns_by_id(self, def subpatterns_by_id(
self,
include_none: bool = False, include_none: bool = False,
recursive: bool = True, recursive: bool = True,
) -> Dict[int, List[SubPattern]]: ) -> Dict[int, List[SubPattern]]:
@ -593,7 +605,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
flatten_single(self, set()) flatten_single(self, set())
return self return self
def wrap_repeated_shapes(self: P, def wrap_repeated_shapes(
self: P,
name_func: Callable[['Pattern', Union[Shape, Label]], str] = lambda p, s: '_repetition', name_func: Callable[['Pattern', Union[Shape, Label]], str] = lambda p, s: '_repetition',
recursive: bool = True, recursive: bool = True,
) -> P: ) -> P:
@ -930,7 +943,8 @@ class Pattern(LockableImpl, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
pickle.dump(self, f, protocol=pickle.HIGHEST_PROTOCOL) pickle.dump(self, f, protocol=pickle.HIGHEST_PROTOCOL)
return self return self
def visualize(self, def visualize(
self,
offset: vector2 = (0., 0.), offset: vector2 = (0., 0.),
line_color: str = 'k', line_color: str = 'k',
fill_color: str = 'none', fill_color: str = 'none',

@ -61,12 +61,14 @@ class Grid(LockableImpl, Repetition, metaclass=AutoSlots):
_b_count: int _b_count: int
""" Number of instances along the direction specified by the `b_vector` """ """ Number of instances along the direction specified by the `b_vector` """
def __init__(self, def __init__(
self,
a_vector: ArrayLike, a_vector: ArrayLike,
a_count: int, a_count: int,
b_vector: Optional[ArrayLike] = None, b_vector: Optional[ArrayLike] = None,
b_count: Optional[int] = 1, b_count: Optional[int] = 1,
locked: bool = False,): locked: bool = False,
) -> None:
""" """
Args: Args:
a_vector: First lattice vector, of the form `[x, y]`. a_vector: First lattice vector, of the form `[x, y]`.

@ -51,7 +51,7 @@ class Arc(Shape, metaclass=AutoSlots):
return self._radii return self._radii
@radii.setter @radii.setter
def radii(self, val: vector2): def radii(self, val: vector2) -> None:
val = numpy.array(val, dtype=float).flatten() val = numpy.array(val, dtype=float).flatten()
if not val.size == 2: if not val.size == 2:
raise PatternError('Radii must have length 2') raise PatternError('Radii must have length 2')
@ -64,7 +64,7 @@ class Arc(Shape, metaclass=AutoSlots):
return self._radii[0] return self._radii[0]
@radius_x.setter @radius_x.setter
def radius_x(self, val: float): def radius_x(self, val: float) -> None:
if not val >= 0: if not val >= 0:
raise PatternError('Radius must be non-negative') raise PatternError('Radius must be non-negative')
self._radii[0] = val self._radii[0] = val
@ -74,7 +74,7 @@ class Arc(Shape, metaclass=AutoSlots):
return self._radii[1] return self._radii[1]
@radius_y.setter @radius_y.setter
def radius_y(self, val: float): def radius_y(self, val: float) -> None:
if not val >= 0: if not val >= 0:
raise PatternError('Radius must be non-negative') raise PatternError('Radius must be non-negative')
self._radii[1] = val self._radii[1] = val
@ -92,7 +92,7 @@ class Arc(Shape, metaclass=AutoSlots):
return self._angles return self._angles
@angles.setter @angles.setter
def angles(self, val: vector2): def angles(self, val: vector2) -> None:
val = numpy.array(val, dtype=float).flatten() val = numpy.array(val, dtype=float).flatten()
if not val.size == 2: if not val.size == 2:
raise PatternError('Angles must have length 2') raise PatternError('Angles must have length 2')
@ -103,7 +103,7 @@ class Arc(Shape, metaclass=AutoSlots):
return self.angles[0] return self.angles[0]
@start_angle.setter @start_angle.setter
def start_angle(self, val: float): def start_angle(self, val: float) -> None:
self.angles = (val, self.angles[1]) self.angles = (val, self.angles[1])
@property @property
@ -111,7 +111,7 @@ class Arc(Shape, metaclass=AutoSlots):
return self.angles[1] return self.angles[1]
@stop_angle.setter @stop_angle.setter
def stop_angle(self, val: float): def stop_angle(self, val: float) -> None:
self.angles = (self.angles[0], val) self.angles = (self.angles[0], val)
# Rotation property # Rotation property
@ -126,7 +126,7 @@ class Arc(Shape, metaclass=AutoSlots):
return self._rotation return self._rotation
@rotation.setter @rotation.setter
def rotation(self, val: float): def rotation(self, val: float) -> None:
if not is_scalar(val): if not is_scalar(val):
raise PatternError('Rotation must be a scalar') raise PatternError('Rotation must be a scalar')
self._rotation = val % (2 * pi) self._rotation = val % (2 * pi)
@ -143,14 +143,15 @@ class Arc(Shape, metaclass=AutoSlots):
return self._width return self._width
@width.setter @width.setter
def width(self, val: float): def width(self, val: float) -> None:
if not is_scalar(val): if not is_scalar(val):
raise PatternError('Width must be a scalar') raise PatternError('Width must be a scalar')
if not val > 0: if not val > 0:
raise PatternError('Width must be positive') raise PatternError('Width must be positive')
self._width = val self._width = val
def __init__(self, def __init__(
self,
radii: vector2, radii: vector2,
angles: vector2, angles: vector2,
width: float, width: float,
@ -166,7 +167,7 @@ class Arc(Shape, metaclass=AutoSlots):
annotations: Optional[annotations_t] = None, annotations: Optional[annotations_t] = None,
locked: bool = False, locked: bool = False,
raw: bool = False, raw: bool = False,
): ) -> None:
LockableImpl.unlock(self) LockableImpl.unlock(self)
self.identifier = () self.identifier = ()
if raw: if raw:
@ -204,7 +205,8 @@ class Arc(Shape, metaclass=AutoSlots):
new.set_locked(self.locked) new.set_locked(self.locked)
return new return new
def to_polygons(self, def to_polygons(
self,
poly_num_points: Optional[int] = None, poly_num_points: Optional[int] = None,
poly_max_arclen: Optional[float] = None, poly_max_arclen: Optional[float] = None,
) -> List[Polygon]: ) -> List[Polygon]:

@ -35,14 +35,15 @@ class Circle(Shape, metaclass=AutoSlots):
return self._radius return self._radius
@radius.setter @radius.setter
def radius(self, val: float): def radius(self, val: float) -> None:
if not is_scalar(val): if not is_scalar(val):
raise PatternError('Radius must be a scalar') raise PatternError('Radius must be a scalar')
if not val >= 0: if not val >= 0:
raise PatternError('Radius must be non-negative') raise PatternError('Radius must be non-negative')
self._radius = val self._radius = val
def __init__(self, def __init__(
self,
radius: float, radius: float,
*, *,
poly_num_points: Optional[int] = DEFAULT_POLY_NUM_POINTS, poly_num_points: Optional[int] = DEFAULT_POLY_NUM_POINTS,
@ -54,7 +55,7 @@ class Circle(Shape, metaclass=AutoSlots):
annotations: Optional[annotations_t] = None, annotations: Optional[annotations_t] = None,
locked: bool = False, locked: bool = False,
raw: bool = False, raw: bool = False,
): ) -> None:
LockableImpl.unlock(self) LockableImpl.unlock(self)
self.identifier = () self.identifier = ()
if raw: if raw:
@ -83,7 +84,8 @@ class Circle(Shape, metaclass=AutoSlots):
new.set_locked(self.locked) new.set_locked(self.locked)
return new return new
def to_polygons(self, def to_polygons(
self,
poly_num_points: Optional[int] = None, poly_num_points: Optional[int] = None,
poly_max_arclen: Optional[float] = None, poly_max_arclen: Optional[float] = None,
) -> List[Polygon]: ) -> List[Polygon]:

@ -41,7 +41,7 @@ class Ellipse(Shape, metaclass=AutoSlots):
return self._radii return self._radii
@radii.setter @radii.setter
def radii(self, val: vector2): def radii(self, val: vector2) -> None:
val = numpy.array(val).flatten() val = numpy.array(val).flatten()
if not val.size == 2: if not val.size == 2:
raise PatternError('Radii must have length 2') raise PatternError('Radii must have length 2')
@ -54,7 +54,7 @@ class Ellipse(Shape, metaclass=AutoSlots):
return self.radii[0] return self.radii[0]
@radius_x.setter @radius_x.setter
def radius_x(self, val: float): def radius_x(self, val: float) -> None:
if not val >= 0: if not val >= 0:
raise PatternError('Radius must be non-negative') raise PatternError('Radius must be non-negative')
self.radii[0] = val self.radii[0] = val
@ -64,7 +64,7 @@ class Ellipse(Shape, metaclass=AutoSlots):
return self.radii[1] return self.radii[1]
@radius_y.setter @radius_y.setter
def radius_y(self, val: float): def radius_y(self, val: float) -> None:
if not val >= 0: if not val >= 0:
raise PatternError('Radius must be non-negative') raise PatternError('Radius must be non-negative')
self.radii[1] = val self.radii[1] = val
@ -82,12 +82,13 @@ class Ellipse(Shape, metaclass=AutoSlots):
return self._rotation return self._rotation
@rotation.setter @rotation.setter
def rotation(self, val: float): def rotation(self, val: float) -> None:
if not is_scalar(val): if not is_scalar(val):
raise PatternError('Rotation must be a scalar') raise PatternError('Rotation must be a scalar')
self._rotation = val % pi self._rotation = val % pi
def __init__(self, def __init__(
self,
radii: vector2, radii: vector2,
*, *,
poly_num_points: Optional[int] = DEFAULT_POLY_NUM_POINTS, poly_num_points: Optional[int] = DEFAULT_POLY_NUM_POINTS,
@ -101,7 +102,7 @@ class Ellipse(Shape, metaclass=AutoSlots):
annotations: Optional[annotations_t] = None, annotations: Optional[annotations_t] = None,
locked: bool = False, locked: bool = False,
raw: bool = False, raw: bool = False,
): ) -> None:
LockableImpl.unlock(self) LockableImpl.unlock(self)
self.identifier = () self.identifier = ()
if raw: if raw:
@ -134,7 +135,8 @@ class Ellipse(Shape, metaclass=AutoSlots):
new.set_locked(self.locked) new.set_locked(self.locked)
return new return new
def to_polygons(self, def to_polygons(
self,
poly_num_points: Optional[int] = None, poly_num_points: Optional[int] = None,
poly_max_arclen: Optional[float] = None, poly_max_arclen: Optional[float] = None,
) -> List[Polygon]: ) -> List[Polygon]:

@ -46,7 +46,7 @@ class Path(Shape, metaclass=AutoSlots):
return self._width return self._width
@width.setter @width.setter
def width(self, val: float): def width(self, val: float) -> None:
if not is_scalar(val): if not is_scalar(val):
raise PatternError('Width must be a scalar') raise PatternError('Width must be a scalar')
if not val >= 0: if not val >= 0:
@ -62,7 +62,7 @@ class Path(Shape, metaclass=AutoSlots):
return self._cap return self._cap
@cap.setter @cap.setter
def cap(self, val: PathCap): def cap(self, val: PathCap) -> None:
# TODO: Document that setting cap can change cap_extensions # TODO: Document that setting cap can change cap_extensions
self._cap = PathCap(val) self._cap = PathCap(val)
if self.cap != PathCap.SquareCustom: if self.cap != PathCap.SquareCustom:
@ -83,7 +83,7 @@ class Path(Shape, metaclass=AutoSlots):
return self._cap_extensions return self._cap_extensions
@cap_extensions.setter @cap_extensions.setter
def cap_extensions(self, vals: Optional[numpy.ndarray]): def cap_extensions(self, vals: Optional[numpy.ndarray]) -> None:
custom_caps = (PathCap.SquareCustom,) custom_caps = (PathCap.SquareCustom,)
if self.cap in custom_caps: if self.cap in custom_caps:
if vals is None: if vals is None:
@ -103,7 +103,7 @@ class Path(Shape, metaclass=AutoSlots):
return self._vertices return self._vertices
@vertices.setter @vertices.setter
def vertices(self, val: ArrayLike): def vertices(self, val: ArrayLike) -> None:
val = numpy.array(val, dtype=float) # TODO document that these might not be copied val = numpy.array(val, dtype=float) # TODO document that these might not be copied
if len(val.shape) < 2 or val.shape[1] != 2: if len(val.shape) < 2 or val.shape[1] != 2:
raise PatternError('Vertices must be an Nx2 array') raise PatternError('Vertices must be an Nx2 array')
@ -120,7 +120,7 @@ class Path(Shape, metaclass=AutoSlots):
return self.vertices[:, 0] return self.vertices[:, 0]
@xs.setter @xs.setter
def xs(self, val: ArrayLike): def xs(self, val: ArrayLike) -> None:
val = numpy.array(val, dtype=float).flatten() val = numpy.array(val, dtype=float).flatten()
if val.size != self.vertices.shape[0]: if val.size != self.vertices.shape[0]:
raise PatternError('Wrong number of vertices') raise PatternError('Wrong number of vertices')
@ -135,13 +135,14 @@ class Path(Shape, metaclass=AutoSlots):
return self.vertices[:, 1] return self.vertices[:, 1]
@ys.setter @ys.setter
def ys(self, val: ArrayLike): def ys(self, val: ArrayLike) -> None:
val = numpy.array(val, dtype=float).flatten() val = numpy.array(val, dtype=float).flatten()
if val.size != self.vertices.shape[0]: if val.size != self.vertices.shape[0]:
raise PatternError('Wrong number of vertices') raise PatternError('Wrong number of vertices')
self.vertices[:, 1] = val self.vertices[:, 1] = val
def __init__(self, def __init__(
self,
vertices: ArrayLike, vertices: ArrayLike,
width: float = 0.0, width: float = 0.0,
*, *,
@ -156,7 +157,7 @@ class Path(Shape, metaclass=AutoSlots):
annotations: Optional[annotations_t] = None, annotations: Optional[annotations_t] = None,
locked: bool = False, locked: bool = False,
raw: bool = False, raw: bool = False,
): ) -> None:
LockableImpl.unlock(self) LockableImpl.unlock(self)
self._cap_extensions = None # Since .cap setter might access it self._cap_extensions = None # Since .cap setter might access it
@ -197,7 +198,8 @@ class Path(Shape, metaclass=AutoSlots):
return new return new
@staticmethod @staticmethod
def travel(travel_pairs: Tuple[Tuple[float, float]], def travel(
travel_pairs: Tuple[Tuple[float, float]],
width: float = 0.0, width: float = 0.0,
cap: PathCap = PathCap.Flush, cap: PathCap = PathCap.Flush,
cap_extensions: Optional[Tuple[float, float]] = None, cap_extensions: Optional[Tuple[float, float]] = None,
@ -243,7 +245,8 @@ class Path(Shape, metaclass=AutoSlots):
offset=offset, rotation=rotation, mirrored=mirrored, offset=offset, rotation=rotation, mirrored=mirrored,
layer=layer, dose=dose) layer=layer, dose=dose)
def to_polygons(self, def to_polygons(
self,
poly_num_points: int = None, poly_num_points: int = None,
poly_max_arclen: float = None, poly_max_arclen: float = None,
) -> List['Polygon']: ) -> List['Polygon']:

@ -34,7 +34,7 @@ class Polygon(Shape, metaclass=AutoSlots):
return self._vertices return self._vertices
@vertices.setter @vertices.setter
def vertices(self, val: ArrayLike): def vertices(self, val: ArrayLike) -> None:
val = numpy.array(val, dtype=float) # TODO document that these might not be copied val = numpy.array(val, dtype=float) # TODO document that these might not be copied
if len(val.shape) < 2 or val.shape[1] != 2: if len(val.shape) < 2 or val.shape[1] != 2:
raise PatternError('Vertices must be an Nx2 array') raise PatternError('Vertices must be an Nx2 array')
@ -51,7 +51,7 @@ class Polygon(Shape, metaclass=AutoSlots):
return self.vertices[:, 0] return self.vertices[:, 0]
@xs.setter @xs.setter
def xs(self, val: ArrayLike): def xs(self, val: ArrayLike) -> None:
val = numpy.array(val, dtype=float).flatten() val = numpy.array(val, dtype=float).flatten()
if val.size != self.vertices.shape[0]: if val.size != self.vertices.shape[0]:
raise PatternError('Wrong number of vertices') raise PatternError('Wrong number of vertices')
@ -66,13 +66,14 @@ class Polygon(Shape, metaclass=AutoSlots):
return self.vertices[:, 1] return self.vertices[:, 1]
@ys.setter @ys.setter
def ys(self, val: ArrayLike): def ys(self, val: ArrayLike) -> None:
val = numpy.array(val, dtype=float).flatten() val = numpy.array(val, dtype=float).flatten()
if val.size != self.vertices.shape[0]: if val.size != self.vertices.shape[0]:
raise PatternError('Wrong number of vertices') raise PatternError('Wrong number of vertices')
self.vertices[:, 1] = val self.vertices[:, 1] = val
def __init__(self, def __init__(
self,
vertices: ArrayLike, vertices: ArrayLike,
*, *,
offset: vector2 = (0.0, 0.0), offset: vector2 = (0.0, 0.0),
@ -84,7 +85,7 @@ class Polygon(Shape, metaclass=AutoSlots):
annotations: Optional[annotations_t] = None, annotations: Optional[annotations_t] = None,
locked: bool = False, locked: bool = False,
raw: bool = False, raw: bool = False,
): ) -> None:
LockableImpl.unlock(self) LockableImpl.unlock(self)
self.identifier = () self.identifier = ()
if raw: if raw:
@ -115,7 +116,8 @@ class Polygon(Shape, metaclass=AutoSlots):
return new return new
@staticmethod @staticmethod
def square(side_length: float, def square(
side_length: float,
*, *,
rotation: float = 0.0, rotation: float = 0.0,
offset: vector2 = (0.0, 0.0), offset: vector2 = (0.0, 0.0),
@ -148,7 +150,8 @@ class Polygon(Shape, metaclass=AutoSlots):
return poly return poly
@staticmethod @staticmethod
def rectangle(lx: float, def rectangle(
lx: float,
ly: float, ly: float,
*, *,
rotation: float = 0, rotation: float = 0,
@ -182,7 +185,8 @@ class Polygon(Shape, metaclass=AutoSlots):
return poly return poly
@staticmethod @staticmethod
def rect(*, def rect(
*,
xmin: Optional[float] = None, xmin: Optional[float] = None,
xctr: Optional[float] = None, xctr: Optional[float] = None,
xmax: Optional[float] = None, xmax: Optional[float] = None,
@ -282,7 +286,8 @@ class Polygon(Shape, metaclass=AutoSlots):
return poly return poly
@staticmethod @staticmethod
def octagon(*, def octagon(
*,
side_length: Optional[float] = None, side_length: Optional[float] = None,
inner_radius: Optional[float] = None, inner_radius: Optional[float] = None,
regular: bool = True, regular: bool = True,
@ -341,7 +346,8 @@ class Polygon(Shape, metaclass=AutoSlots):
return poly return poly
def to_polygons(self, def to_polygons(
self,
poly_num_points: int = None, # unused poly_num_points: int = None, # unused
poly_max_arclen: float = None, # unused poly_max_arclen: float = None, # unused
) -> List['Polygon']: ) -> List['Polygon']:

@ -47,7 +47,8 @@ class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable
--- Abstract methods --- Abstract methods
''' '''
@abstractmethod @abstractmethod
def to_polygons(self, def to_polygons(
self,
num_vertices: Optional[int] = None, num_vertices: Optional[int] = None,
max_arclen: Optional[float] = None, max_arclen: Optional[float] = None,
) -> List['Polygon']: ) -> List['Polygon']:
@ -93,7 +94,8 @@ class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable
''' '''
---- Non-abstract methods ---- Non-abstract methods
''' '''
def manhattanize_fast(self, def manhattanize_fast(
self,
grid_x: ArrayLike, grid_x: ArrayLike,
grid_y: ArrayLike, grid_y: ArrayLike,
) -> List['Polygon']: ) -> List['Polygon']:
@ -200,7 +202,8 @@ class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable
return manhattan_polygons return manhattan_polygons
def manhattanize(self, def manhattanize(
self,
grid_x: ArrayLike, grid_x: ArrayLike,
grid_y: ArrayLike, grid_y: ArrayLike,
) -> List['Polygon']: ) -> List['Polygon']:

@ -35,7 +35,7 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
return self._string return self._string
@string.setter @string.setter
def string(self, val: str): def string(self, val: str) -> None:
self._string = val self._string = val
# Height property # Height property
@ -44,7 +44,7 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
return self._height return self._height
@height.setter @height.setter
def height(self, val: float): def height(self, val: float) -> None:
if not is_scalar(val): if not is_scalar(val):
raise PatternError('Height must be a scalar') raise PatternError('Height must be a scalar')
self._height = val self._height = val
@ -55,12 +55,13 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
return self._mirrored return self._mirrored
@mirrored.setter @mirrored.setter
def mirrored(self, val: Sequence[bool]): def mirrored(self, val: Sequence[bool]) -> None:
if is_scalar(val): if is_scalar(val):
raise PatternError('Mirrored must be a 2-element list of booleans') raise PatternError('Mirrored must be a 2-element list of booleans')
self._mirrored = numpy.array(val, dtype=bool, copy=True) self._mirrored = numpy.array(val, dtype=bool, copy=True)
def __init__(self, def __init__(
self,
string: str, string: str,
height: float, height: float,
font_path: str, font_path: str,
@ -74,7 +75,7 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
annotations: Optional[annotations_t] = None, annotations: Optional[annotations_t] = None,
locked: bool = False, locked: bool = False,
raw: bool = False, raw: bool = False,
): ) -> None:
LockableImpl.unlock(self) LockableImpl.unlock(self)
self.identifier = () self.identifier = ()
if raw: if raw:
@ -109,7 +110,8 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
new.set_locked(self.locked) new.set_locked(self.locked)
return new return new
def to_polygons(self, def to_polygons(
self,
poly_num_points: Optional[int] = None, # unused poly_num_points: Optional[int] = None, # unused
poly_max_arclen: Optional[float] = None, # unused poly_max_arclen: Optional[float] = None, # unused
) -> List[Polygon]: ) -> List[Polygon]:
@ -166,7 +168,8 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
return bounds return bounds
def get_char_as_polygons(font_path: str, def get_char_as_polygons(
font_path: str,
char: str, char: str,
resolution: float = 48 * 64, resolution: float = 48 * 64,
) -> Tuple[List[List[List[float]]], float]: ) -> Tuple[List[List[List[float]]], float]:

@ -46,7 +46,8 @@ class SubPattern(PositionableImpl, DoseableImpl, RotatableImpl, ScalableImpl, Mi
identifier: Tuple[Any, ...] identifier: Tuple[Any, ...]
""" Arbitrary identifier, used internally by some `masque` functions. """ """ Arbitrary identifier, used internally by some `masque` functions. """
def __init__(self, def __init__(
self,
pattern: Optional['Pattern'], pattern: Optional['Pattern'],
*, *,
offset: vector2 = (0.0, 0.0), offset: vector2 = (0.0, 0.0),

Loading…
Cancel
Save