99@dataclass (slots = True )
1010class Component :
1111 """
12- A generic component with a name, cost, power, and optional children.
13-
14- This can represent items such as chassis, line cards, optic modules, etc.
12+ A generic component that can represent chassis, line cards, optics, etc.
13+ Components can have nested children, each with their own cost, power, etc.
1514
1615 Attributes:
1716 name (str): Name of the component (e.g., "SpineChassis" or "400G-LR4").
18- component_type (str): An optional string label ("chassis", "linecard", "optic", etc.).
19- cost (float): Base capex cost for the component.
20- power_watts (float): Power consumption of the component in watts.
17+ component_type (str): A string label (e.g., "chassis", "linecard", "optic").
18+ description (str): A human-readable description of this component.
19+ cost (float): Cost (capex) of a single instance of this component.
20+ power_watts (float): Typical/nominal power usage (watts) for one instance.
21+ power_watts_max (float): Maximum/peak power usage (watts) for one instance.
22+ capacity (float): A generic capacity measure (e.g., platform capacity).
2123 ports (int): Number of ports if relevant for this component.
22- children (Dict[str, Component]): Child components keyed by their names.
24+ count (int): How many identical copies of this component are present.
25+ attrs (Dict[str, Any]): Arbitrary key-value attributes for extra metadata.
26+ children (Dict[str, Component]): Nested child components (e.g., line cards
27+ inside a chassis), keyed by child name.
2328 """
2429
2530 name : str
2631 component_type : str = "generic"
32+ description : str = ""
2733 cost : float = 0.0
28- power_watts : float = 0.0
34+
35+ power_watts : float = 0.0 # Typical power usage
36+ power_watts_max : float = 0.0 # Peak power usage
37+
38+ capacity : float = 0.0
2939 ports : int = 0
40+ count : int = 1
41+
42+ attrs : Dict [str , Any ] = field (default_factory = dict )
3043 children : Dict [str , Component ] = field (default_factory = dict )
3144
3245 def total_cost (self ) -> float :
3346 """
34- Calculates the total cost including all nested children.
47+ Computes the total (recursive) cost of this component, including children,
48+ multiplied by this component's count.
3549
3650 Returns:
37- float: Recursive sum of costs for this component and its children .
51+ float: The total cost .
3852 """
39- total = self .cost
53+ single_instance_cost = self .cost
4054 for child in self .children .values ():
41- total += child .total_cost ()
42- return total
55+ single_instance_cost += child .total_cost ()
56+ return single_instance_cost * self . count
4357
4458 def total_power (self ) -> float :
4559 """
46- Calculates the total power consumption including all nested children.
60+ Computes the total *typical* (recursive) power usage of this component,
61+ including children, multiplied by this component's count.
62+
63+ Returns:
64+ float: The total typical power in watts.
65+ """
66+ single_instance_power = self .power_watts
67+ for child in self .children .values ():
68+ single_instance_power += child .total_power ()
69+ return single_instance_power * self .count
70+
71+ def total_power_max (self ) -> float :
72+ """
73+ Computes the total *peak* (recursive) power usage of this component,
74+ including children, multiplied by this component's count.
75+
76+ Returns:
77+ float: The total maximum (peak) power in watts.
78+ """
79+ single_instance_power_max = self .power_watts_max
80+ for child in self .children .values ():
81+ single_instance_power_max += child .total_power_max ()
82+ return single_instance_power_max * self .count
83+
84+ def total_capacity (self ) -> float :
85+ """
86+ Computes the total (recursive) capacity of this component,
87+ including children, multiplied by this component's count.
4788
4889 Returns:
49- float: Recursive sum of power for this component and its children .
90+ float: The total capacity (dimensionless or user-defined units) .
5091 """
51- total = self .power_watts
92+ single_instance_capacity = self .capacity
5293 for child in self .children .values ():
53- total += child .total_power ()
54- return total
94+ single_instance_capacity += child .total_capacity ()
95+ return single_instance_capacity * self .count
96+
97+ def as_dict (self , include_children : bool = True ) -> Dict [str , Any ]:
98+ """
99+ Returns a dictionary containing all properties of this component.
100+
101+ Args:
102+ include_children (bool): If True, recursively includes children.
103+
104+ Returns:
105+ Dict[str, Any]: Dictionary representation of this component.
106+ """
107+ data = {
108+ "name" : self .name ,
109+ "component_type" : self .component_type ,
110+ "description" : self .description ,
111+ "cost" : self .cost ,
112+ "power_watts" : self .power_watts ,
113+ "power_watts_max" : self .power_watts_max ,
114+ "capacity" : self .capacity ,
115+ "ports" : self .ports ,
116+ "count" : self .count ,
117+ "attrs" : dict (self .attrs ), # shallow copy
118+ }
119+ if include_children :
120+ data ["children" ] = {
121+ child_name : child .as_dict (True )
122+ for child_name , child in self .children .items ()
123+ }
124+ return data
55125
56126
57127@dataclass (slots = True )
58128class ComponentsLibrary :
59129 """
60130 Holds a collection of named Components. Each entry is a top-level "template"
61- that can be referenced for cost/power lookups, possibly with nested children.
131+ that can be referenced for cost/power/capacity lookups, possibly with nested children.
62132
63- Example:
133+ Example (YAML-like) :
64134 components:
65135 BigSwitch:
66136 component_type: chassis
67137 cost: 20000
68- power_watts: 1000
138+ power_watts: 1750
139+ capacity: 25600
69140 children:
70- LC-48x10G :
141+ PIM16Q-16x200G :
71142 component_type: linecard
72- cost: 5000
73- power_watts: 300
74- ports: 48
75- 400G-LR4:
143+ cost: 1000
144+ power_watts: 10
145+ ports: 16
146+ count: 8
147+ 200G-FR4:
76148 component_type: optic
77149 cost: 2000
78- power_watts: 15
79-
80- Attributes:
81- components (Dict[str, Component]): A dictionary of component name -> Component.
150+ power_watts: 6
151+ power_watts_max: 6.5
82152 """
83153
84154 components : Dict [str , Component ] = field (default_factory = dict )
85155
86156 def get (self , name : str ) -> Optional [Component ]:
87157 """
88- Retrieves a Component by its name.
158+ Retrieves a Component by its name from the library .
89159
90160 Args:
91161 name (str): Name of the component.
@@ -104,7 +174,7 @@ def merge(
104174
105175 Args:
106176 other (ComponentsLibrary): Another library to merge into this one.
107- override (bool): Whether components in `other` override existing ones.
177+ override (bool): If True, components in `other` override existing ones.
108178
109179 Returns:
110180 ComponentsLibrary: This instance, updated in place.
@@ -154,19 +224,45 @@ def _build_component(cls, name: str, definition_data: Dict[str, Any]) -> Compone
154224 comp_type = definition_data .get ("component_type" , "generic" )
155225 cost = float (definition_data .get ("cost" , 0.0 ))
156226 power = float (definition_data .get ("power_watts" , 0.0 ))
227+ power_max = float (definition_data .get ("power_watts_max" , 0.0 ))
228+ capacity = float (definition_data .get ("capacity" , 0.0 ))
157229 ports = int (definition_data .get ("ports" , 0 ))
230+ count = int (definition_data .get ("count" , 1 ))
158231
159- children_map : Dict [str , Component ] = {}
160232 child_definitions = definition_data .get ("children" , {})
233+ children_map : Dict [str , Component ] = {}
161234 for child_name , child_data in child_definitions .items ():
162235 children_map [child_name ] = cls ._build_component (child_name , child_data )
163236
237+ recognized_keys = {
238+ "component_type" ,
239+ "cost" ,
240+ "power_watts" ,
241+ "power_watts_max" ,
242+ "capacity" ,
243+ "ports" ,
244+ "children" ,
245+ "attrs" ,
246+ "count" ,
247+ "description" ,
248+ }
249+ attrs : Dict [str , Any ] = dict (definition_data .get ("attrs" , {}))
250+ leftover_keys = {
251+ k : v for k , v in definition_data .items () if k not in recognized_keys
252+ }
253+ attrs .update (leftover_keys )
254+
164255 return Component (
165256 name = name ,
166257 component_type = comp_type ,
258+ description = definition_data .get ("description" , "" ),
167259 cost = cost ,
168260 power_watts = power ,
261+ power_watts_max = power_max ,
262+ capacity = capacity ,
169263 ports = ports ,
264+ count = count ,
265+ attrs = attrs ,
170266 children = children_map ,
171267 )
172268
@@ -175,7 +271,7 @@ def from_yaml(cls, yaml_str: str) -> ComponentsLibrary:
175271 """
176272 Constructs a ComponentsLibrary from a YAML string. If the YAML contains
177273 a top-level 'components' key, that key is used; otherwise the entire
178- top-level of the YAML is treated as component definitions.
274+ top-level is treated as component definitions.
179275
180276 Args:
181277 yaml_str (str): A YAML-formatted string of component definitions.
0 commit comments