Skip to content
Snippets Groups Projects
Commit 6eec0a75 authored by Lamm, Sascha's avatar Lamm, Sascha :cow2:
Browse files

Merge branch 'development' into 'main'

Unifying PraDDa and GdD Code Style

See merge request !8
parents b3bace71 9a8a9f5d
No related branches found
No related tags found
No related merge requests found
__pycache__/
\ No newline at end of file
No preview for this file type
{
"4265cc01":{
"item number":"4265cc01",
"item description":"wheel 14",
"category":"wheel",
"related items":59895,
"price [Euro]":0.02,
"mass [g]":0.5,
"delivery time [days]":5,
"data source":"https://www.bricklink.com/v2/catalog/catalogitem.page?P=4265cc01#T=C",
"diameter [mm]":14.0
"88517": {
"item number": "88517",
"item description": "Wheel 75",
"category": "wheel",
"price [Euro]": 1.09,
"mass [g]": 17.7,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=88517#T=S&O={%22iconly%22:0}",
"diameter [mm]": 75
},
"3482c01":{
"item number":"3482c01",
"item description":"wheel 24",
"category":"wheel",
"related items":3483,
"price [Euro]":0.01,
"mass [g]":3.0,
"delivery time [days]":5,
"data source":"https://www.bricklink.com/v2/catalog/catalogitem.page?P=3482c01#T=C",
"diameter [mm]":24.0
"11957": {
"item number": "11957",
"item description": "Tire 100.6",
"category": "wheel",
"price [Euro]": 2.86,
"mass [g]": 22,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=11957&idColor=11#T=P&C=11",
"diameter [mm]": 100.6
},
"56904c02":{
"item number":"56904c02",
"item description":"wheel 43,2",
"category":"wheel",
"related items":30699,
"price [Euro]":0.11,
"mass [g]":13.0,
"delivery time [days]":5,
"data source":"https://www.bricklink.com/v2/catalog/catalogitem.page?P=56904c02#T=C",
"diameter [mm]":43.2
"2903": {
"item number": "2903",
"item description": "Wheel 61.6",
"category": "wheel",
"price [Euro]": 0.56,
"mass [g]": 12.34,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=2903&name=Wheel%2061.6mm%20D.%20x%2013.6mm%20Motorcycle&category=%5BWheel%5D#T=P",
"diameter [mm]": 61.6
},
"41896c04":{
"item number":"41896c04",
"item description":"wheel 56",
"category":"wheel",
"related items":41897,
"price [Euro]":0.45,
"mass [g]":23.0,
"delivery time [days]":5,
"data source":"https://www.bricklink.com/v2/catalog/catalogitem.page?P=41896c04#T=C",
"diameter [mm]":56.0
"2902": {
"item number": "2902",
"item description": "Tire 81.6",
"category": "wheel",
"price [Euro]": 3.71,
"mass [g]": 19.34,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=2902&name=Tire%2081.6%20x%2015%20Motorcycle&category=%5BWheel,%20Tire%20&%20Tread%5D#T=P&C=11",
"diameter [mm]": 81.6
},
"2903c02":{
"item number":"2903c02",
"item description":"wheel 81,6",
"category":"wheel",
"related items":2902,
"price [Euro]":1.31,
"mass [g]":30.0,
"delivery time [days]":5,
"data source":"https://www.bricklink.com/v2/catalog/catalogitem.page?P=2903c02#T=C",
"diameter [mm]":81.6
"41896": {
"item number": "41896",
"item description": "Wheel 43.2",
"category": "wheel",
"price [Euro]": 0.79,
"mass [g]": 9.35,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=41896&name=Wheel%2043.2mm%20D.%20x%2026mm%20Technic%20Racing%20Small,%203%20Pin%20Holes&category=%5BWheel%5D#T=P",
"diameter [mm]": 43.2
},
"88517c01":{
"item number":"88517c01",
"item description":"wheel 100,6",
"category":"wheel",
"related items":11957,
"price [Euro]":1.25,
"mass [g]":40.0,
"delivery time [days]":5,
"data source":"https://www.bricklink.com/v2/catalog/catalogitem.page?P=88517c02#T=C",
"diameter [mm]":100.6
"41897": {
"item number": "41897",
"item description": "Tire 46",
"category": "wheel",
"price [Euro]": 2.05,
"mass [g]": 13.87,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=41897&name=Tire%2056%20x%2028%20ZR%20Street&category=%5BWheel,%20Tire%20&%20Tread%5D#T=P&C=11",
"diameter [mm]": 56
},
"56904": {
"item number": "56904",
"item description": "Wheel 30",
"category": "wheel",
"price [Euro]": 0.26,
"mass [g]": 4.1,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=56904&name=Wheel%2030mm%20D.%20x%2014mm&category=%5BWheel%5D#T=P",
"diameter [mm]": 30
},
"30699": {
"item number": "30699",
"item description": "Tire 43.2",
"category": "wheel",
"price [Euro]": 0.59,
"mass [g]": 8.25,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=30699&name=Tire%2043.2%20x%2014%20Solid&category=%5BWheel,%20Tire%20&%20Tread%5D#T=P&C=11",
"diameter [mm]": 43.2
},
"3482": {
"item number": "3482",
"item description": "Wheel 17.6",
"category": "wheel",
"price [Euro]": 0.04,
"mass [g]": 0.88,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=3482&name=Wheel%20with%20Split%20Axle%20Hole&category=%5BWheel%5D#T=P&C=1",
"diameter [mm]": 17.6
},
"3483": {
"item number": "3483",
"item description": "Tire 24",
"category": "wheel",
"price [Euro]": 0.06,
"mass [g]": 1.69,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=3483&name=Tire%2024mm%20D.%20x%208mm%20Offset%20Tread%20-%20Interior%20Ridges&category=%5BWheel,%20Tire%20&%20Tread%5D#T=P&C=11",
"diameter [mm]": 24
},
"59895": {
"item number": "59895",
"item description": "Wheel 14",
"category": "wheel",
"price [Euro]": 0.04,
"mass [g]": 0.42,
"delivery time [days]": 5,
"data source": "https://www.bricklink.com/v2/catalog/catalogitem.page?P=59895&name=Tire%2014mm%20D.%20x%204mm%20Smooth%20Small%20Single%20with%20Number%20Embossed%20on%20Side&category=%5BWheel,%20Tire%20&%20Tread%5D#T=P",
"diameter [mm]": 14
}
}
\ No newline at end of file
......@@ -2,18 +2,19 @@
File consists of several classes to model elements and assembly
layers of a composed device.
"""
from __future__ import annotations
import uuid
import json
import operator
from enum import Enum, auto
from typing import List, Dict, Optional
from typing import Any, Optional
from copy import deepcopy
class AggregationLayer(Enum):
"""Describes the levl of aggregation for the objects LegoComponent
and LegoAssembly and provides the 4 applicable layers.
"""Describes the level of aggregation for the objects LegoComponent and LegoAssembly
and provides the 4 applicable layers.
"""
SYSTEM = auto()
......@@ -23,62 +24,50 @@ class AggregationLayer(Enum):
class LegoComponent:
"""
A class for storing information about a single Lego component.
...
"""Information storage for a single Lego component.
Attributes
----------
uuid : UUID
A randomly generated unique identifier for the component.
parent : None | LegoAssembly
The parent of the component. Can be either None or a LegoAssembly object.
layer : AggregationLayer
An enumeration indicating the hierarchy level. For compoennts, this is
COMPONENT by default.
properties : dict
Dictionary that holds all properties of the component that can be saved
in a dictionary format.
uuid (uuid.UUID): A randomly generated unique identifier for the component.
parent (None | LegoAssembly): The parent of the component. None if the
component has no parent.
layer (AggregationLayer): An enumeration indicating the hierarchy level. For
components, this is COMPONENT by default.
properties (dict[str, Any]): dictionary that holds all properties of the
component that can be saved in a dictionary format.
Methods
-------
clone(new_label=None)
Returns a new instance of LegoComponent identical to the current instance.
get_root_assembly()
Returns the top-level assembly in which the component belongs.
to_dict()
Returns the current instance represented as a dictionary.
clone(new_label=None): Returns a new instance of LegoComponent identical to the
current instance.
get_root_assembly(): Returns the top-level assembly in which the component is
contained.
to_dict(): Returns the current instance represented as a dictionary.
"""
def __init__(
self,
label: Optional[str] = None,
datasheet: Optional[dict] = None,
datasheet: Optional[dict[str, Any]] = None,
*more_properties: dict,
**kwargs,
) -> None:
"""
Constructs all the necessary attributes for the LegoComponent object.
"""Create a LegoComponent object.
Parameters
----------
label : str, optional
The name of the component to add.
datasheet : dict, optional
Metadata describing the component, read from datasheet.
more_properties : tuple of dict, dict
Args:
label (str, optional): The name of the component to add. Defaults
to None.
datasheet (dict[str, Any], optional): Metadata describing the component,
read from datasheet. Defaults to None.
more_properties tuple of dict, dict
Additional dictionaries representing custom properties.
kwargs
Arbitrary keyword arguments representing custom properties.
Raises
------
ValueError
If the type of more_properties argument is not a dictionary.
Raises:
ValueError: If the type of more_properties argument is not a dictionary.
"""
self.uuid: uuid.UUID = uuid.uuid4()
self.parent: None | LegoAssembly = None
self._uuid: uuid.UUID = uuid.uuid4()
self._parent: None | LegoAssembly = None
self.layer: AggregationLayer = AggregationLayer.COMPONENT
self.properties: dict = {}
if label is not None:
......@@ -93,81 +82,126 @@ class LegoComponent:
for key, value in kwargs.items():
self.properties[key] = deepcopy(value)
@property
def uuid(self) -> uuid.UUID:
return self._uuid
@property
def parent(self) -> None | LegoAssembly:
return self._parent
def clone(self, new_label: Optional[str] = None) -> LegoComponent:
"""
Returns a new instance of LegoComponent identical to the current instance.
"""Return a new instance of LegoComponent identical to the current instance.
This method creates a new instance of LegoComponent that is identical to the
current instance with an optional different label.
The assigned uuid changes and elements are copied.
Parameters
----------
new_label : str, optional
A new label string to use. Defaults to None.
Returns
-------
LegoComponent
A new instance of LegoComponent that is identical to the current instance.
Args:
new_label (str, optional): A new label string to use. Defaults to None.
Returns:
LegoComponent: A new instance of LegoComponent that is identical to the
current instance.
"""
if new_label is None:
new_label = self.properties["label"]
clone = LegoComponent(None, None, deepcopy(self.properties))
clone.properties["label"] = new_label
return clone
def get_root_assembly(self):
def get_property(self, key: str, default: Any = None) -> Any:
"""Get a property from the component.
Args:
key (str): Property name.
default (Any, optional): What to return if key is not available in
properties. Defaults to None.
Returns:
Any: Property value.
"""
Returns the top-level assembly in which the component belongs.
if key == "uuid":
return self._uuid
if key == "layer":
return self._layer
return self.properties.get(key, default=default)
def get_root_assembly(self):
"""Return the top-level assembly in which the component belongs.
This method traverses the parent hierarchy of a LegoComponent object until it
finds the root-level LegoAssembly, returning it to the caller. A parent is
assigned when a LegoComponent or LegoItem is added to a LegoAssembly object.
Returns
-------
None | LegoAssembly
The root-level LegoAssembly or None if the component has no parent.
Returns:
None | LegoAssembly: The root-level LegoAssembly or None if the component
has no parent.
"""
if self.parent is None:
if self._parent is None:
return None
current_assembly = self.parent
while current_assembly.parent is not None:
current_assembly = current_assembly.parent
current_assembly = self._parent
while current_assembly._parent is not None:
current_assembly = current_assembly._parent
return current_assembly
def to_dict(self) -> Dict:
"""
Returns the current instance represented as a dictionary.
def to_dict(self) -> dict:
"""Return the current instance represented as a dictionary.
This method returns a dictionary representation of the LegoComponent object
suitable for serialization as JSON.
Returns
-------
dict
A dictionary representation of the object.
Returns:
dict[str, Any]: A dictionary representation of the object.
"""
dict_ = {
"uuid": self.uuid,
"uuid": self._uuid,
"properties": self.properties,
"layer": self.layer,
}
return {"component": dict_}
def __str__(self):
"""
Simple string representation of the object.
def __eq__(self, obj: object):
"""Check if provided object is equal to this component.
Args:
obj (object): Object to compare to.
Returns:
bool: True if UUID, properties, and layer match. False otherwise.
"""
return self.__repr__()
# in case of mismatching class
if not isinstance(obj, LegoComponent):
return False
if (
self._uuid == obj._uuid
and self.layer == obj.layer
and self.properties == obj.properties
):
return True
else:
return False
def __repr__(self):
"""Create a machine-readable representation of the instance.
Returns:
str: A string representing the LegoComponent instance.
"""
String representation of the object including the component label and UUID.
return f"LegoComponent({self.properties if self.properties else ""})"
def __str__(self):
"""Handle the conversion of LegoComponent objects to str objects.
Returns:
str: A string converted from the LegoComponent instance.
"""
return f"LegoComponent {self.properties['label']} [{self.uuid}]"
if self.properties.get("label") is None:
return f"LegoComponent [{self._uuid}]"
return f"LegoComponent {self.properties['label']} [{self._uuid}]"
class LegoAssembly:
......@@ -179,8 +213,8 @@ class LegoAssembly:
parent (LegoAssembly or None): The parent assembly containing this one, if any.
properties (dict): Optional properties for the assembly, such as a label.
layer (AggregationLayer): The aggregation layer of the assembly.
components (List[LegoComponent]): The list of contained components.
assemblies (List[LegoAssembly]): The list of contained subassemblies.
components (list[LegoComponent]): The list of contained components.
assemblies (list[LegoAssembly]): The list of contained subassemblies.
"""
def __init__(
......@@ -200,10 +234,10 @@ class LegoAssembly:
properties (dict): Optional properties for the assembly, such as a label.
**kwargs: Optional keyword arguments for additional properties.
"""
self.uuid: uuid.UUID = uuid.uuid4()
self.parent: None | LegoAssembly = None
self._uuid: uuid.UUID = uuid.uuid4()
self._parent: None | LegoAssembly = None
self.properties: dict = {}
self.layer: AggregationLayer = layer
self._layer: AggregationLayer = layer
if label is not None:
self.properties["label"] = label
for prop in properties:
......@@ -213,16 +247,36 @@ class LegoAssembly:
raise ValueError(f"Unexpected argument type: {type(properties)}")
for key, value in kwargs.items():
self.properties[key] = deepcopy(value)
self.components: List[LegoComponent] = []
self.assemblies: List[LegoAssembly] = []
self._components: list[LegoComponent] = []
self._assemblies: list[LegoAssembly] = []
@property
def uuid(self) -> uuid.UUID:
return self._uuid
def add_component(self, component: LegoComponent | List[LegoComponent]) -> None:
@property
def parent(self) -> None | LegoAssembly:
return self._parent
@property
def layer(self) -> AggregationLayer:
return self._layer
@property
def components(self) -> list[LegoComponent]:
return self._components
@property
def assemblies(self) -> list[LegoAssembly]:
return self._assemblies
def add_component(self, component: LegoComponent | list[LegoComponent]) -> None:
"""
Adds a Lego component to the current assembly.
Use add() to handle both components and assemblies.
Args:
component (LegoComponent or List[LegoComponent]):
component (LegoComponent or list[LegoComponent]):
The component or list of components to add.
Raises:
......@@ -242,22 +296,22 @@ class LegoAssembly:
f"got {type(component).__name__} instead."
)
if self.get_root_assembly().contains_uuid(component.uuid):
if self.get_root_assembly().contains_uuid(component._uuid):
raise AssertionError(
f"This assembly or a subassembly already contains "
f"the component with ID "
f"{component.uuid}."
f"{component._uuid}."
)
component.parent = self
self.components.append(component)
component._parent = self
self._components.append(component)
def add_assembly(self, assembly: LegoAssembly | List[LegoAssembly]) -> None:
def add_assembly(self, assembly: LegoAssembly | list[LegoAssembly]) -> None:
"""
Adds a subassembly to the current assembly.
Use add() to handle both components and assemblies.
Args:
assembly (LegoAssembly or List[LegoAssembly]):
assembly (LegoAssembly or list[LegoAssembly]):
The subassembly or list of subassemblies to add.
Raises:
......@@ -277,23 +331,23 @@ class LegoAssembly:
f"got {type(assembly).__name__} instead."
)
if self.get_root_assembly().contains_uuid(assembly.uuid):
if self.get_root_assembly().contains_uuid(assembly._uuid):
raise AssertionError(
f"This assembly or a subassembly already contains "
f"the assembly with ID {assembly.uuid}."
f"the assembly with ID {assembly._uuid}."
)
assembly.parent = self
self.assemblies.append(assembly)
assembly._parent = self
self._assemblies.append(assembly)
def add(
self, part: LegoAssembly | LegoComponent | List[LegoAssembly | LegoComponent]
self, part: LegoAssembly | LegoComponent | list[LegoAssembly | LegoComponent]
) -> None:
"""
Adds either a Lego component, a subassembly or a (mixed) list of them to the
current assembly. Uses internal functions add_component() and add_assembly().
Args:
part (LegoAssembly or LegoComponent or List[LegoAssembly or LegoComponent]):
part (LegoAssembly or LegoComponent or list[LegoAssembly or LegoComponent]):
The part or parts to add.
Raises:
......@@ -314,7 +368,7 @@ class LegoAssembly:
f"Got {type(part).__name__} instead."
)
def children(self) -> Dict[str, List[LegoComponent] | List[LegoAssembly]]:
def children(self) -> dict[str, list[LegoComponent] | list[LegoAssembly]]:
"""
Returns a dictionary of the assembly's children (components and
sub-assemblies), sorted by category.
......@@ -323,28 +377,45 @@ class LegoAssembly:
A dictionary with two keys - "components" and "assemblies" - and
corresponding lists of LegoComponents and LegoAssemblies as values.
"""
return {"components": self.components, "assemblies": self.assemblies}
return {"components": self._components, "assemblies": self._assemblies}
def get_component_list(self, max_depth: int = -1) -> List[LegoComponent]:
def get_component_list(self, max_depth: int = -1) -> list[LegoComponent]:
"""
Gets a full list of all components contained in the assembly or any of
its sub-assemblies.
Args:
max_depth: An integer indicating the maximum depth of recursion.
-1 means unlimited depth. 0 returns only direc children.
-1 means unlimited depth. 0 returns only direct children.
Returns:
A list of all LegoComponents contained in the current assembly or
its sub-assemblies.
"""
component_list = []
component_list.extend(self.components)
if max_depth > 0 or max_depth < 0:
for assembly in self.assemblies:
component_list.extend(self._components)
if not max_depth == 0:
for assembly in self._assemblies:
component_list.extend(assembly.get_component_list(max_depth - 1))
return component_list
def get_property(self, key: str, default: Any = None) -> Any:
"""Get a property from the assembly.
Args:
key (str): Property name.
default (Any, optional): What to return if key is not available in
properties. Defaults to None.
Returns:
Any: Property value.
"""
if key == "uuid":
return self._uuid
if key == "layer":
return self._layer
return self.properties.get(key, default=default)
def get_root_assembly(self) -> LegoAssembly:
"""
Returns the root LegoAssembly of the current assembly by recursively
......@@ -354,8 +425,8 @@ class LegoAssembly:
The root LegoAssembly of the current LegoAssembly instance.
"""
current_assembly = self
while current_assembly.parent is not None:
current_assembly = current_assembly.parent
while current_assembly._parent is not None:
current_assembly = current_assembly._parent
return current_assembly
def contains_uuid(self, uuid_: uuid.UUID):
......@@ -371,18 +442,18 @@ class LegoAssembly:
True if the UUID exists in the assembly or any of its sub-assemblies,
False otherwise.
"""
component_ids = list(map(lambda c: c.uuid, self.components))
component_ids = list(map(lambda c: c._uuid, self._components))
if uuid_ in component_ids:
return True
assembly_ids = list(map(lambda a: a.uuid, self.assemblies))
assembly_ids = list(map(lambda a: a._uuid, self._assemblies))
if uuid_ in assembly_ids:
return True
for assembly in self.assemblies:
for assembly in self._assemblies:
if assembly.contains_uuid(uuid_):
return True
return False
def to_dict(self) -> Dict:
def to_dict(self) -> dict:
"""
Serializes the current LegoAssembly instance and its descendants into a dict.
......@@ -391,20 +462,14 @@ class LegoAssembly:
of its component and sub-assembly children.
"""
dict_ = {
"uuid": self.uuid,
"uuid": self._uuid,
"properties": self.properties,
"layer": self.layer,
"layer": self._layer,
}
dict_["components"] = [component.to_dict() for component in self.components]
dict_["assemblies"] = [assembly.to_dict() for assembly in self.assemblies]
dict_["components"] = [component.to_dict() for component in self._components]
dict_["assemblies"] = [assembly.to_dict() for assembly in self._assemblies]
return {"assembly": dict_}
def __repr__(self):
"""
String representation of the object including the component label and UUID.
"""
return f"LegoAssembly {self.properties['label']} [{self.uuid}]"
def clone(self, label: Optional[str] = None) -> LegoAssembly:
"""
Creates a deep clone of the current LegoAssembly instance, including
......@@ -420,24 +485,55 @@ class LegoAssembly:
"""
if label is None:
label = self.properties["label"]
clone = LegoAssembly(self.layer, None, deepcopy(self.properties))
clone = LegoAssembly(self._layer, None, deepcopy(self.properties))
clone.properties["label"] = label
for component in self.components:
for component in self._components:
clone.add_component(component.clone())
for assembly in self.assemblies:
for assembly in self._assemblies:
clone.add_assembly(assembly.clone())
return clone
def __eq__(self, obj: object) -> bool:
"""Check if provided object is equal to this assembly.
Args:
obj (object): Object to compare to.
Returns:
bool: True if UUID, properties, layer, components and assemblies match.
False otherwise.
"""
# in case of mismatching class
if not isinstance(obj, LegoAssembly):
return False
if (
self._uuid == obj._uuid
and self.properties == obj.properties
and self._layer == obj._layer
and self._components == obj._components
and self._assemblies == obj._assemblies
):
return True
else:
return False
def __repr__(self):
"""
String representation of the object including the component label and UUID.
"""
return f"LegoAssembly {self.properties['label']} [{self._uuid}]"
def print_assembly_tree(root, levels=None):
def print_assembly_tree(root: LegoAssembly, levels: list[bool] = None) -> None:
"""
Prints the assembly tree starting from root with a visualization
implemented with text characters.
Args:
root (LegoAssembly): The root of the assembly tree to print.
levels (List[bool]): Internally used by recursion to know where
to print vertical connection. Defaults to an empty list.
levels (list[bool]): Internally used by recursion to know where
to print vertical connection. Defaults to None.
"""
if not isinstance(root, LegoAssembly):
raise TypeError(
......@@ -452,12 +548,12 @@ def print_assembly_tree(root, levels=None):
assembly_padding = "├── " if levels[-1] else "└── "
print(f"{connection_padding[:-4]}{assembly_padding}{root}")
""" Recursively print child components. """
for i, assembly in enumerate(root.assemblies):
is_last = i == len(root.assemblies) - 1 and len(root.components) == 0
for i, assembly in enumerate(root._assemblies):
is_last = i == len(root._assemblies) - 1 and len(root._components) == 0
print_assembly_tree(assembly, [*levels, not is_last])
""" Print the components. """
for i, component in enumerate(root.components):
component_padding = "├── " if i < len(root.components) - 1 else "└── "
for i, component in enumerate(root._components):
component_padding = "├── " if i < len(root._components) - 1 else "└── "
print(f"{connection_padding}{component_padding}{component}")
......@@ -482,11 +578,11 @@ def correct_aggregation_hierarchy(root: LegoAssembly, strict: bool = False):
higher_level = operator.le
if strict:
higher_level = operator.lt
for component in root.components:
if not higher_level(root.layer.value, component.layer.value):
for component in root._components:
if not higher_level(root._layer.value, component.layer.value):
return False
for assembly in root.assemblies:
if not higher_level(root.layer.value, assembly.layer.value):
for assembly in root._assemblies:
if not higher_level(root._layer.value, assembly._layer.value):
return False
if not correct_aggregation_hierarchy(assembly, strict):
return False
......@@ -498,12 +594,12 @@ class KPIEncoder(json.JSONEncoder):
JSON encoder that handles special class types for KPI serialization.
"""
def default(self, o):
def default(self, o: Any):
"""
Overrides default method to handle special conversion cases.
Args:
o : Object to be converted.
o (Any): Object to be converted.
Returns:
Converted object or super method if no applicable case is found.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment