Coverage for qpdk / helper.py: 67%

51 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-14 10:27 +0000

1"""Helper functions for the qpdk package.""" 

2 

3import warnings 

4from collections.abc import Callable, Sequence 

5from functools import wraps 

6from typing import Any, cast 

7 

8from gdsfactory import Component, ComponentAllAngle, LayerEnum, get_component 

9from gdsfactory.technology import LayerViews 

10from gdsfactory.typings import ComponentAllAngleSpec, ComponentSpec, Layer 

11 

12 

13def deprecated(msg: str | Callable | None = None) -> Any: 

14 """Decorator to mark functions as deprecated. 

15 

16 Can be used as @deprecated or @deprecated("custom message"). 

17 """ 

18 

19 def decorator(func: Callable) -> Callable: 

20 @wraps(func) 

21 def wrapper(*args: Any, **kwargs: Any) -> Any: 

22 m = ( 

23 msg 

24 if isinstance(msg, str) 

25 else f"{func.__name__} is deprecated and will be removed in a future version." 

26 ) 

27 warnings.warn(m, category=DeprecationWarning, stacklevel=2) 

28 return func(*args, **kwargs) 

29 

30 return wrapper 

31 

32 if callable(msg): 

33 f = msg 

34 msg = None 

35 return decorator(f) 

36 return decorator 

37 

38 

39def denest_layerviews_to_layer_tuples( 

40 layer_views: LayerViews, 

41) -> dict[str, tuple[int, int]]: 

42 """De-nest LayerViews into a flat dictionary of layer names to layer tuples. 

43 

44 Args: 

45 layer_views: LayerViews object containing the layer views. 

46 

47 Returns: 

48 Dictionary mapping layer names to their corresponding (layer, datatype) tuples. 

49 """ 

50 

51 def denest_layer_dict_recursive(items: dict) -> dict: 

52 """Recursively denest layer views to any depth. 

53 

54 Args: 

55 items: Dictionary of layer view items to process 

56 

57 Returns: 

58 Dictionary mapping layer names to layer objects 

59 """ 

60 layers = {} 

61 

62 for key, value in items.items(): 

63 if value.group_members: 

64 # Recursively process nested group members and merge results 

65 nested_layers = denest_layer_dict_recursive(value.group_members) 

66 layers.update(nested_layers) 

67 else: 

68 # Base case: add the layer to our dictionary 

69 if hasattr(value, "layer"): 

70 layers[key] = value.layer 

71 

72 return layers 

73 

74 # Start the recursive denesting process and return the result 

75 return denest_layer_dict_recursive(layer_views.layer_views) 

76 

77 

78def show_components( 

79 *args: ComponentSpec | ComponentAllAngleSpec, 

80 spacing: int = 200, 

81) -> Sequence[Component]: 

82 """Show sequence of components in a single layout in a line. 

83 

84 The components are spaced based on the maximum width and height of the components. 

85 

86 Args: 

87 *args: Component specifications to show. 

88 spacing: Extra spacing between components. 

89 

90 Returns: 

91 Components after :func:`gdsfactory.get_component`. 

92 """ 

93 from qpdk import PDK 

94 

95 PDK.activate() 

96 

97 components = [get_component(component_spec) for component_spec in args] 

98 any_all_angle = any( 

99 isinstance(component, ComponentAllAngle) for component in components 

100 ) 

101 

102 c = ComponentAllAngle() if any_all_angle else Component() 

103 

104 max_component_width = max(component.size_info.width for component in components) 

105 max_component_height = max(component.size_info.height for component in components) 

106 if max_component_width > max_component_height: 

107 shift = (0, max_component_height + spacing) 

108 else: 

109 shift = (max_component_width + spacing, 0) 

110 

111 for i, component in enumerate(components): 

112 (c << component).move( 

113 ( 

114 shift[0] * i, 

115 shift[1] * i, 

116 ) 

117 ) 

118 label_offset = ( 

119 shift[0] * i + (component.size_info.width / 2), 

120 shift[1] * i + (component.size_info.height / 2), 

121 ) 

122 label_text = component.name if hasattr(component, "name") else f"component_{i}" 

123 c.add_label( 

124 text=label_text, 

125 position=label_offset, 

126 layer=cast(LayerEnum, PDK.layers).TEXT, 

127 ) 

128 c.show() 

129 

130 return components 

131 

132 

133def layerenum_to_tuple(layerenum: LayerEnum) -> Layer: 

134 """Convert a LayerEnum object to a tuple containing layer and datatype values. 

135 

136 Args: 

137 layerenum: The LayerEnum object to convert. 

138 """ 

139 return layerenum.layer, layerenum.datatype