[ports2data] deal with cycles better

This commit is contained in:
jan 2026-03-09 01:15:42 -07:00
commit a38c5bb085

View file

@ -57,11 +57,9 @@ def data_to_ports(
name: str | None = None, # Note: name optional, but arg order different from read(postprocess=) name: str | None = None, # Note: name optional, but arg order different from read(postprocess=)
max_depth: int = 0, max_depth: int = 0,
skip_subcells: bool = True, skip_subcells: bool = True,
# TODO missing ok? visited: set[int] | None = None,
) -> Pattern: ) -> Pattern:
""" """
# TODO fixup documentation in ports2data
# TODO move to utils.file?
Examine `pattern` for labels specifying port info, and use that info Examine `pattern` for labels specifying port info, and use that info
to fill out its `ports` attribute. to fill out its `ports` attribute.
@ -70,18 +68,28 @@ def data_to_ports(
Args: Args:
layers: Search for labels on all the given layers. layers: Search for labels on all the given layers.
library: Mapping from pattern names to patterns.
pattern: Pattern object to scan for labels. pattern: Pattern object to scan for labels.
max_depth: Maximum hierarcy depth to search. Default 999_999. name: Name of the pattern object.
max_depth: Maximum hierarcy depth to search. Default 0.
Reduce this to 0 to avoid ever searching subcells. Reduce this to 0 to avoid ever searching subcells.
skip_subcells: If port labels are found at a given hierarcy level, skip_subcells: If port labels are found at a given hierarcy level,
do not continue searching at deeper levels. This allows subcells do not continue searching at deeper levels. This allows subcells
to contain their own port info without interfering with supercells' to contain their own port info without interfering with supercells'
port data. port data.
Default True. Default True.
visited: Set of object IDs which have already been processed.
Returns: Returns:
The updated `pattern`. Port labels are not removed. The updated `pattern`. Port labels are not removed.
""" """
if visited is None:
visited = set()
if id(pattern) in visited:
return pattern
visited.add(id(pattern))
if pattern.ports: if pattern.ports:
logger.warning(f'Pattern {name if name else pattern} already had ports, skipping data_to_ports') logger.warning(f'Pattern {name if name else pattern} already had ports, skipping data_to_ports')
return pattern return pattern
@ -105,6 +113,7 @@ def data_to_ports(
name = target, name = target,
max_depth = max_depth - 1, max_depth = max_depth - 1,
skip_subcells = skip_subcells, skip_subcells = skip_subcells,
visited = visited,
) )
found_ports |= bool(pp.ports) found_ports |= bool(pp.ports)