def add_skin_attachments_to_slot(graph: DAGraph, slot_parent: SpineNodeData, skin_attachment: List) -> None: for _id in skin_attachment: _data = skin_attachment[_id] attachment_data = SpineNodeData( node_data=_data, node_type=NodeType.ATTACHMENT, node_base_id=_id, ) if graph.get_node(attachment_data.node_id) is None: graph.add_node( node_type=attachment_data.node_type, node_id=attachment_data.node_id, node_data=attachment_data.node_data, ) image_id = _data.get("path") or _data.get("name") or _id image_node_data = SpineNodeData(node_data={}, node_type=NodeType.IMAGE, node_base_id=image_id) if graph.get_node(image_node_data.node_id) is None: graph.add_node( node_type=image_node_data.node_type, node_id=image_node_data.node_id, node_data=image_node_data.node_data, ) graph.add_edge(attachment_data.node_id, image_node_data.node_id) graph.add_edge(slot_parent.node_id, attachment_data.node_id)
def test_graph_create_from_json_data_not_implemented(self, node_factory): graph_parser = IGraphParser() with pytest.raises(NotImplementedError): graph_parser.create_from_json_data(None, node_factory) with pytest.raises(NotImplementedError): DAGraph.create_from_json_data(IGraphParser, {}, node_factory) with pytest.raises(TypeError): DAGraph.create_from_json_data(object, {}, node_factory)
def test_graph_create_from_json_file(self, node_factory): graph_parser = IGraphParser() with pytest.raises(NotImplementedError): DAGraph.create_from_json_file(IGraphParser, "PATH", node_factory) with pytest.raises(NotImplementedError): graph_parser.create_from_json_file(None, node_factory) with pytest.raises(TypeError): DAGraph.create_from_json_file(object, "PATH", node_factory)
def test_graph(graph_data: Dict[str, Any]) -> DAGraph: graph = DAGraph() node_types = graph_data.get("types", {}) for node_id in graph_data["nodes"]: graph.add_node(node_id=node_id, node_type=node_types.get(node_id)) [ graph.add_edge(parent_id=edge[0], child_id=edge[1]) for edge in graph_data["edges"] ] return graph
def test_graph_edges(self): graph = DAGraph() graph.add_node(node_id="0") graph.add_node(node_id="1") graph.add_edge(parent_id="0", child_id="1") with pytest.raises(TypeError) as excinfo: graph.add_edge(parent_id="0", child_id="wrong_id") assert PARENTSHIP_TO_NO_NODE.format("child") in str(excinfo.value) with pytest.raises(TypeError) as excinfo: graph.add_edge(parent_id="wrong_id", child_id="1") assert PARENTSHIP_TO_NO_NODE.format("parent") in str(excinfo.value)
def add_ik_to_graph(graph: DAGraph, ik_data: Dict[str, Any], idx: int) -> SpineNodeData: spine_ik_data = SpineNodeData( node_data=ik_data, node_type=NodeType.IK, node_base_id=ik_data["name"], idx=idx, ) graph.add_node( node_type=spine_ik_data.node_type, node_id=spine_ik_data.node_id, node_data=spine_ik_data.node_data, ) # Getting optional parents for ik for child_bone_id in ik_data["bones"]: child_id = SpineGraphParser._to_graph_id( node_type_name=NodeType.BONE.name, node_base_id=child_bone_id) child = graph.get_node(child_id) if child: graph.add_edge(spine_ik_data.node_id, child.id) target_bone = ik_data.get("target") if target_bone: parent_bone_id = SpineGraphParser._to_graph_id( node_type_name=NodeType.BONE.name, node_base_id=target_bone) parent_bone = graph.get_node(parent_bone_id) if parent_bone: graph.add_edge(parent_bone.id, spine_ik_data.node_id) return spine_ik_data
def create_from_json_data(cls, json_data: Dict[str, Any], node_factory: SpineNodeFactory) -> DAGraph: graph = DAGraph(node_factory) for idx, bone_data in enumerate(json_data["bones"]): cls.add_bone_to_graph(graph=graph, bone_data=bone_data, idx=idx) for idx, _slot_data in enumerate(json_data.get("slots", [])): node_slot = cls.add_slot_to_graph(graph=graph, slot_data=_slot_data, idx=idx) # Adding attachments as child to slots differentiating between versions: for data in json_data["skins"]: skin_data = data.get("attachments") if skin_data: slot_skinned = skin_data.get(_slot_data["name"], []) SpineGraphParser.add_skin_attachments_to_slot( graph=graph, slot_parent=node_slot, skin_attachment=slot_skinned, ) iks = json_data.get("ik", []) for idx, ik_data in enumerate(iks): cls.add_ik_to_graph(graph=graph, ik_data=ik_data, idx=idx) return graph
def test_graph_remove_node(self): graph = DAGraph() graph.add_node(node_id=DEFAULT_ID) graph.remove_node_by_id(node_id=DEFAULT_ID) # Trying to remove already removed with pytest.raises(ValueError) as excinfo: graph.remove_node_by_id(node_id=DEFAULT_ID) assert ID_NODE_NOT_FOUND.format(DEFAULT_ID) in str(excinfo.value)
def add_slot_to_graph(graph: DAGraph, slot_data: Dict[str, Any], idx: int): spine_slot_data = SpineNodeData( node_data=slot_data, node_type=NodeType.SLOT, node_base_id=slot_data["name"], idx=idx, ) graph.add_node( node_type=spine_slot_data.node_type, node_id=spine_slot_data.node_id, node_data=spine_slot_data.node_data, ) # Getting optional parents from slot parent_id = SpineGraphParser._to_graph_id( node_type_name=NodeType.BONE.name, node_base_id=slot_data.get("bone")) parent = graph.get_node(parent_id) if parent: graph.add_edge(parent.id, spine_slot_data.node_id) return spine_slot_data
def create_from_json_data(cls, json_data: Dict[str, Any], node_factory: SpineNodeFactory) -> DAGraph: graph = DAGraph(node_factory) for idx, bone_data in enumerate(json_data["bones"]): node_data = SpineNodeData( node_data=bone_data, node_type=NodeType.BONE, node_base_id=bone_data["name"], idx=idx, ) graph.add_node( node_type=node_data.node_type, node_id=node_data.node_id, node_data=node_data.node_data, ) # Getting optional parent from bone parent_id = SpineGraphParser._to_graph_id( node_type_name=NodeType.BONE.name, node_base_id=bone_data.get("parent")) parent = graph.get_node(parent_id) if parent: graph.add_edge(parent.id, node_data.node_id) slots_json_data = json_data.get("slots", []) for idx, _slot_data in enumerate(slots_json_data): spine_slot_data = SpineNodeData( node_data=_slot_data, node_type=NodeType.SLOT, node_base_id=_slot_data["name"], idx=idx, ) graph.add_node( node_type=spine_slot_data.node_type, node_id=spine_slot_data.node_id, node_data=spine_slot_data.node_data, ) def add_slot_skinned_to_graph(graph, slot_skinned): for _id in slot_skinned: _data = slot_skinned[_id] attachment_data = SpineNodeData( node_data=_data, node_type=NodeType.ATTACHMENT, node_base_id=_data.get("path") or _data.get("name") or _id, ) if graph.get_node(attachment_data.node_id) is None: graph.add_node( node_type=attachment_data.node_type, node_id=attachment_data.node_id, node_data=attachment_data.node_data, ) graph.add_edge(spine_slot_data.node_id, attachment_data.node_id) # Adding attachments as child to slots differentiating between versions: for data in json_data["skins"]: skin_data = data.get("attachments") if skin_data: slot_skinned = skin_data.get(_slot_data["name"], []) add_slot_skinned_to_graph(graph=graph, slot_skinned=slot_skinned) # Getting optional parents from slot parent_id = SpineGraphParser._to_graph_id( node_type_name=NodeType.BONE.name, node_base_id=_slot_data.get("bone")) parent = graph.get_node(parent_id) if parent: graph.add_edge(parent.id, spine_slot_data.node_id) iks = json_data.get("ik", []) for idx, ik_data in enumerate(iks): spine_ik_data = SpineNodeData( node_data=ik_data, node_type=NodeType.IK, node_base_id=ik_data["name"], idx=idx, ) graph.add_node( node_type=spine_ik_data.node_type, node_id=spine_ik_data.node_id, node_data=spine_ik_data.node_data, ) # Getting optional parents for ik for child_bone_id in ik_data["bones"]: child_id = SpineGraphParser._to_graph_id( node_type_name=NodeType.BONE.name, node_base_id=child_bone_id) child = graph.get_node(child_id) if child: graph.add_edge(spine_ik_data.node_id, child.id) target_bone = ik_data.get("target") if target_bone: parent_bone_id = SpineGraphParser._to_graph_id( node_type_name=NodeType.BONE.name, node_base_id=target_bone) parent_bone = graph.get_node(parent_bone_id) if parent_bone: graph.add_edge(parent_bone.id, spine_ik_data.node_id) return graph
def test_graph_nodes_creation(self, node_factory): graph = DAGraph(node_factory) node1 = graph.add_node(node_id=DEFAULT_ID) assert node1 is not None assert graph.get_node(node_id=DEFAULT_ID) is node1 with pytest.raises(ValueError) as excinfo: graph.add_node(node_id=DEFAULT_ID, node_data=None) assert UNIQUE_ID_ERROR_MESSAGE in str(excinfo.value) graph.add_node(node_id="1", node_data=None) NUM_NODES = 1000 for _ in range(0, NUM_NODES): id_ = graph.generate_unique_id() tmp_node = graph.add_node(node_id=id_) assert id_ is not DEFAULT_ID assert tmp_node is not None assert graph.get_node(node_id=id_) is tmp_node with pytest.raises(ValueError) as excinfo: graph.add_node(node_id=id_, node_data=None) assert UNIQUE_ID_ERROR_MESSAGE in str(excinfo.value) with pytest.raises(TypeError) as excinfo: graph.add_node(node_id=0) assert WRONG_NODE_ID_TYPE in str(excinfo.value) with pytest.raises(TypeError) as excinfo: graph.get_node(node_id=0) assert WRONG_NODE_ID_TYPE in str(excinfo.value)
def test_graph_multi_graphs(self, node_factory): graph1 = DAGraph(node_factory) graph2 = DAGraph(node_factory) id_ = graph1.generate_unique_id() node1 = graph1.add_node(node_id=id_) assert node1 is not None assert graph1.get_node(node_id=id_) is node1 # Checking if also in graph2 assert graph2.get_node(node_id=id_) is None # Creating two nodes with the same id in different graphs node2 = graph2.add_node(node_id=id_) assert node2 is not node1 with pytest.raises(ValueError) as excinfo: graph1.add_edge(parent_id=id_, child_id=id_) assert CIRCULAR_PARENTSHIP_NODE_ERROR.format("child") in str(excinfo.value)
def test_graph_forbidden_child_types(self, node_factory): graph = DAGraph(node_factory) graph.add_node(node_id=NODE_TYPE_BLOND, node_type=NODE_TYPE_BLOND) graph.add_node(node_id=NODE_TYPE_BROWN, node_type=NODE_TYPE_BROWN) graph.add_node(node_id=NODE_TYPE_BLACK, node_type=NODE_TYPE_BLACK) graph.add_edge(parent_id=NODE_TYPE_BLOND, child_id=NODE_TYPE_BROWN) graph.add_edge(parent_id=NODE_TYPE_BLACK, child_id=NODE_TYPE_BROWN) with pytest.raises(TypeError) as excinfo: graph.add_edge(parent_id=NODE_TYPE_BLACK, child_id=NODE_TYPE_BLOND) assert CHILD_TYPE_FORBIDDEN in str(excinfo.value) with pytest.raises(TypeError) as excinfo: graph.add_edge(parent_id=NODE_TYPE_BLOND, child_id=NODE_TYPE_BLACK) assert CHILD_TYPE_FORBIDDEN in str(excinfo.value)