diff --git a/mgraph_ai/providers/json/actions/MGraph__Json__Edit.py b/mgraph_ai/providers/json/actions/MGraph__Json__Edit.py index c21414f..0d7c223 100644 --- a/mgraph_ai/providers/json/actions/MGraph__Json__Edit.py +++ b/mgraph_ai/providers/json/actions/MGraph__Json__Edit.py @@ -11,7 +11,7 @@ class MGraph__Json__Edit(MGraph__Edit): def add_property(self, property_name, value=None, node_id=None): print() - node_property_data = Schema__MGraph__Json__Node__Property__Data(name = property_name ) + node_property_data = Schema__MGraph__Json__Node__Property__Data(name = property_name ) node_property = Schema__MGraph__Json__Node__Property (node_data = node_property_data) new_node = self.add_node(node_property) diff --git a/mgraph_ai/providers/json/actions/MGraph__Json__Export.py b/mgraph_ai/providers/json/actions/MGraph__Json__Export.py index b4fee7b..513f25a 100644 --- a/mgraph_ai/providers/json/actions/MGraph__Json__Export.py +++ b/mgraph_ai/providers/json/actions/MGraph__Json__Export.py @@ -1,6 +1,10 @@ from typing import Union, Dict, List, Optional, Any from mgraph_ai.providers.json.actions.exporters.MGraph__Export__Json__Dot import MGraph__Export__Json__Dot from mgraph_ai.providers.json.actions.exporters.MGraph__Export__Json__Mermaid import MGraph__Export__Json__Mermaid +from mgraph_ai.providers.json.models.Model__MGraph__Json__Node__Dict import Model__MGraph__Json__Node__Dict +from mgraph_ai.providers.json.models.Model__MGraph__Json__Node__List import Model__MGraph__Json__Node__List +from mgraph_ai.providers.json.models.Model__MGraph__Json__Node__Value import Model__MGraph__Json__Node__Value +from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__Value import Schema__MGraph__Json__Node__Value from osbot_utils.utils.Files import file_save from osbot_utils.utils.Json import json_dumps from mgraph_ai.providers.json.domain.Domain__MGraph__Json__Node__Dict import Domain__MGraph__Json__Node__Dict @@ -8,35 +12,73 @@ from mgraph_ai.providers.json.domain.Domain__MGraph__Json__Node__Value import Domain__MGraph__Json__Node__Value from mgraph_ai.providers.json.domain.Domain__MGraph__Json__Graph import Domain__MGraph__Json__Graph from mgraph_ai.mgraph.actions.MGraph__Export import MGraph__Export +from mgraph_ai.mgraph.index.MGraph__Index import MGraph__Index +from osbot_utils.helpers.Obj_Id import Obj_Id -class MGraph__Json__Export(MGraph__Export): # JSON export handler +class MGraph__Json__Export(MGraph__Export): graph: Domain__MGraph__Json__Graph - def to_dict(self) -> Union[Dict, List, Any]: # Export to Python object + def process_value_node(self, node_id: Obj_Id) -> Any: + domain_node = self.graph.node(node_id) + model_node = domain_node.node + if isinstance(model_node, Model__MGraph__Json__Node__Value): + return model_node.value + return None + + def process_dict_node(self, node_id: Obj_Id, index: MGraph__Index) -> Dict[str, Any]: + result = {} + for edge_id in index.edges_ids__from__node_id(node_id): + property_id = index.edge_to_nodes()[edge_id][1] + property_node = self.graph.node(property_id) + + if property_node: + property_name = property_node.node_data.name + value_edges = index.edges_ids__from__node_id(property_id) + if value_edges: + value_node_id = index.edge_to_nodes()[value_edges[0]][1] + result[property_name] = self.process_node(value_node_id, index) + return result + + def process_list_node(self, node_id: Obj_Id, index: MGraph__Index) -> List[Any]: + result = [] + for edge_id in index.edges_ids__from__node_id(node_id): + item_id = index.edge_to_nodes()[edge_id][1] + item_value = self.process_node(item_id, index) + result.append(item_value) + return result + + def process_node(self, node_id: Obj_Id, index: MGraph__Index) -> Any: + domain_node = self.graph.node(node_id) + model_node = domain_node.node + if not domain_node: + return None + + if isinstance(model_node, Model__MGraph__Json__Node__Value): return self.process_value_node(node_id) + elif isinstance(model_node, Model__MGraph__Json__Node__Dict ): return self.process_dict_node (node_id, index) + elif isinstance(model_node, Model__MGraph__Json__Node__List ): return self.process_list_node (node_id, index) + return None + + def to_dict(self) -> Union[Dict, List, Any]: root_content = self.graph.root_content() if not root_content: return None - if isinstance(root_content, Domain__MGraph__Json__Node__Dict): - return root_content.properties() - elif isinstance(root_content, Domain__MGraph__Json__Node__List): - return root_content.items() - elif isinstance(root_content, Domain__MGraph__Json__Node__Value): - return root_content.value + index = MGraph__Index.from_graph(self.graph) # todo: replace with index = self.data().index() + return self.process_node(root_content.node_id, index) - def to_string(self, indent: Optional[int] = None) -> str: # Export to JSON string + def to_string(self, indent: Optional[int] = None) -> str: data = self.to_dict() return json_dumps(data, indent=indent) - def to_dot(self): - return MGraph__Export__Json__Dot(graph=self.graph) - - def to_file(self, file_path: str, indent: Optional[int] = None) -> bool: # Export to JSON file + def to_file(self, file_path: str, indent: Optional[int] = None) -> bool: file_contents = self.to_string(indent=indent) if file_contents: file_save(contents=file_contents, path=file_path) return True return False + def to_dot(self): + return MGraph__Export__Json__Dot(graph=self.graph) + def to_mermaid(self) -> MGraph__Export__Json__Mermaid: - return MGraph__Export__Json__Mermaid(graph=self.graph) + return MGraph__Export__Json__Mermaid(graph=self.graph) \ No newline at end of file diff --git a/mgraph_ai/providers/json/domain/Domain__MGraph__Json__Node__Dict.py b/mgraph_ai/providers/json/domain/Domain__MGraph__Json__Node__Dict.py index f6ab5dd..9babc36 100644 --- a/mgraph_ai/providers/json/domain/Domain__MGraph__Json__Node__Dict.py +++ b/mgraph_ai/providers/json/domain/Domain__MGraph__Json__Node__Dict.py @@ -22,7 +22,7 @@ def properties(self) -> Dict[str, Any]: if value_edge.from_node_id() == property_node.node_id: value_node = self.graph.node(value_edge.to_node_id()) if value_node.data.node_type == Schema__MGraph__Json__Node__Value: # todo: there is an interest case here, what happens if there is more than one Schema__MGraph__Json__Node__Value per Schema__MGraph__Json__Node__Property - result[property_name] = value_node.data.node_data.value # todo: solve issue of value not being recognized here + result[property_name] = value_node.data.node_data.value # todo: solve issue of value not being recognized here break elif value_node.data.node_type == Schema__MGraph__Json__Node__List: from mgraph_ai.providers.json.domain.Domain__MGraph__Json__Node__List import Domain__MGraph__Json__Node__List diff --git a/tests/unit/providers/json/_performance/test_Perf_Test__MGraph_Json.py b/tests/unit/providers/json/_performance/test_Perf_Test__MGraph_Json.py index 659dfe9..22353aa 100644 --- a/tests/unit/providers/json/_performance/test_Perf_Test__MGraph_Json.py +++ b/tests/unit/providers/json/_performance/test_Perf_Test__MGraph_Json.py @@ -1,6 +1,6 @@ import pytest from unittest import TestCase -from osbot_utils.utils.Json import json_file_load +from osbot_utils.utils.Json import json_file_load, json__equals__list_and_set from osbot_utils.context_managers.print_duration import print_duration from osbot_utils.utils.Http import current_host_offline from mgraph_ai.providers.json.MGraph__Json import MGraph__Json @@ -69,7 +69,7 @@ def test_trace(self): dot_code = mgraph_json.export().to_dot().to_string() #pprint(round_trip) #print(dot_code) - assert target_json == round_trip + assert json__equals__list_and_set(target_json, round_trip) diff --git a/tests/unit/providers/json/actions/exporters/test_MGraph__Export__Json__Dot.py b/tests/unit/providers/json/actions/exporters/test_MGraph__Export__Json__Dot.py index ff0d664..50a2be3 100644 --- a/tests/unit/providers/json/actions/exporters/test_MGraph__Export__Json__Dot.py +++ b/tests/unit/providers/json/actions/exporters/test_MGraph__Export__Json__Dot.py @@ -1,5 +1,5 @@ from unittest import TestCase -from osbot_utils.utils.Json import json_loads +from osbot_utils.utils.Json import json_loads, json__equals__list_and_set from mgraph_ai.providers.json.MGraph__Json import MGraph__Json from mgraph_ai.providers.json.actions.exporters.MGraph__Export__Json__Dot import MGraph__Export__Json__Dot from mgraph_ai.providers.json.actions.exporters.MGraph__Json__Export__Base import Export__Json__Node_Type, \ @@ -175,7 +175,7 @@ def test_nested_structure(self): # Test } } self.mgraph.load().from_data(nested_data) - assert json_loads(self.mgraph.export().to_string()) == nested_data # BUG + assert json__equals__list_and_set(json_loads(self.mgraph.export().to_string()), nested_data) # BUG dot = self.exporter.to_string() assert dot == """\ digraph { diff --git a/tests/unit/providers/json/actions/exporters/test_MGraph__Export__Json__Mermaid.py b/tests/unit/providers/json/actions/exporters/test_MGraph__Export__Json__Mermaid.py index 73bf634..263fb3b 100644 --- a/tests/unit/providers/json/actions/exporters/test_MGraph__Export__Json__Mermaid.py +++ b/tests/unit/providers/json/actions/exporters/test_MGraph__Export__Json__Mermaid.py @@ -1,5 +1,5 @@ from unittest import TestCase -from osbot_utils.utils.Json import json_loads +from osbot_utils.utils.Json import json_loads, json__equals__list_and_set from mgraph_ai.providers.json.MGraph__Json import MGraph__Json from mgraph_ai.providers.json.actions.exporters.MGraph__Export__Json__Mermaid import MGraph__Export__Json__Mermaid from mgraph_ai.providers.json.actions.exporters.MGraph__Json__Export__Base import Export__Json__Node_Type, Export__Json__Relation_Type @@ -144,7 +144,7 @@ def test_nested_structure(self): } } self.mgraph.load().from_data(nested_data) - assert json_loads(self.mgraph.export().to_string()) == nested_data + assert json__equals__list_and_set(json_loads(self.mgraph.export().to_string()), nested_data) mermaid = self.exporter.to_string() assert mermaid == """\ flowchart LR diff --git a/tests/unit/providers/json/actions/test_MGraph__Json__Edit.py b/tests/unit/providers/json/actions/test_MGraph__Json__Edit.py index a367477..d925bf2 100644 --- a/tests/unit/providers/json/actions/test_MGraph__Json__Edit.py +++ b/tests/unit/providers/json/actions/test_MGraph__Json__Edit.py @@ -1,4 +1,7 @@ from unittest import TestCase + +from osbot_utils.utils.Dev import pprint + from osbot_utils.helpers.Obj_Id import Obj_Id from mgraph_ai.providers.json.domain.Domain__MGraph__Json__Node import Domain__MGraph__Json__Node from mgraph_ai.providers.json.domain.Domain__MGraph__Json__Node__Dict import Domain__MGraph__Json__Node__Dict @@ -31,8 +34,6 @@ def test_add_root_property_node(self): def test_add_property(self): assert self.mgraph_json.export().to_dict() is None - with self.mgraph_json.data() as _: - root_property_id = _.root_property_id() with self.mgraph_json.edit() as _: root_property_node = _.add_root_property_node() @@ -50,5 +51,28 @@ def test_add_property(self): assert self.mgraph_json.export().to_dict() == {'1234': 'xyz', 'abc': '12345'} # confirm values set correctly - #self.mgraph_json.screenshot().save().dot__just_ids() - #self.mgraph_json.screenshot().save().dot() \ No newline at end of file + def test_add_property_to_property(self): + with self.mgraph_json.edit() as _: + root_property_node = _.add_root_property_node() + new_property_1 = _.add_property('parent', node_id=root_property_node.node_id) + new_property_2 = _.add_property('child' , node_id=new_property_1.node_id ) + + assert type(new_property_1) == Domain__MGraph__Json__Node + assert type(new_property_2) == Domain__MGraph__Json__Node + # print() + # print('root_property_node', root_property_node.node_id) + # print('new_property_1 ', new_property_1.node_id ) + # print('new_property_2 ', new_property_2.node_id ) + # pprint(new_property_1.node.json()) + pprint(new_property_2.node.json()) + + # with self.mgraph_json.index() as _: + # _.print() + + + self.mgraph_json.screenshot().save().dot__just_ids() + #self.mgraph_json.screenshot().save().dot() + + #assert self.mgraph_json.export().to_dict() == {'parent': None} + + pprint(self.mgraph_json.export().to_dict()) \ No newline at end of file diff --git a/tests/unit/providers/json/actions/test_MGraph__Json__Export.py b/tests/unit/providers/json/actions/test_MGraph__Json__Export.py index 8410cde..4c5f6f6 100644 --- a/tests/unit/providers/json/actions/test_MGraph__Json__Export.py +++ b/tests/unit/providers/json/actions/test_MGraph__Json__Export.py @@ -1,6 +1,6 @@ from unittest import TestCase from osbot_utils.utils.Files import file_exists, file_delete -from osbot_utils.utils.Json import json_loads +from osbot_utils.utils.Json import json_loads, json__equals__list_and_set from mgraph_ai.providers.json.MGraph__Json import MGraph__Json @@ -23,12 +23,12 @@ def test_export_formats(self): str_export_indented = self.mgraph.export().to_string(indent=2) # Test string export with indent assert type(dict_export) is dict - assert dict_export == self.test_data - assert type(str_export) is str - assert json_loads(str_export) == self.test_data - assert type(str_export_indented) is str - assert json_loads(str_export_indented) == self.test_data - assert len(str_export_indented) > len(str_export) + assert json__equals__list_and_set(dict_export , self.test_data) is True + assert type(str_export) is str + assert json__equals__list_and_set(json_loads(str_export) ,self.test_data) is True + assert type(str_export_indented) is str + assert json__equals__list_and_set(json_loads(str_export_indented), self.test_data) is True + assert len(str_export_indented) > len(str_export) def test_file_operations(self): # Test file import/export file_path = "test.json" @@ -38,9 +38,9 @@ def test_file_operations(self): new_graph = MGraph__Json() # Test import from file imported = new_graph.load().from_file(str(file_path)) - assert imported.root_content() is not None - assert new_graph.export().to_dict() == self.test_data - assert file_delete(file_path) is True + assert imported.root_content() is not None + assert json__equals__list_and_set(new_graph.export().to_dict(), self.test_data) is True + assert file_delete(file_path) is True def test_error_handling(self): # Test error conditions assert self.mgraph.load().from_string("{invalid json}") is None diff --git a/tests/unit/providers/json/actions/test_MGraph__Json__Load.py b/tests/unit/providers/json/actions/test_MGraph__Json__Load.py index 2d447ba..75e06cc 100644 --- a/tests/unit/providers/json/actions/test_MGraph__Json__Load.py +++ b/tests/unit/providers/json/actions/test_MGraph__Json__Load.py @@ -1,7 +1,7 @@ from unittest import TestCase from mgraph_ai.providers.json.domain.Domain__MGraph__Json__Node__List import Domain__MGraph__Json__Node__List from mgraph_ai.providers.json.domain.Domain__MGraph__Json__Node__Value import Domain__MGraph__Json__Node__Value -from osbot_utils.utils.Json import json_loads +from osbot_utils.utils.Json import json_loads, json__equals__list_and_set from mgraph_ai.providers.json.MGraph__Json import MGraph__Json from mgraph_ai.providers.json.domain.Domain__MGraph__Json__Node__Dict import Domain__MGraph__Json__Node__Dict @@ -35,18 +35,18 @@ def test_import_from_string(self): def test_export_to_dict(self): # Test exporting to dict self.mgraph.load().from_data(self.test_data) exported = self.mgraph.export().to_dict() - assert exported == self.test_data - assert exported["string" ] == "value" - assert exported["number" ] == 42 - assert exported["boolean"] is True - assert exported["null" ] is None - assert exported["array" ] == [1, 2, 3] - assert exported["object" ] == {"key": "value"} + assert json__equals__list_and_set(exported, self.test_data) is True + assert exported["string" ] == "value" + assert exported["number" ] == 42 + assert exported["boolean"] is True + assert exported["null" ] is None + assert json__equals__list_and_set(exported["array" ], [1, 2, 3]) is True + assert exported["object" ] == {"key": "value"} def test_export_to_string(self): # Test exporting to JSON string self.mgraph.load().from_data(self.test_data) exported = self.mgraph.export().to_string() - assert json_loads(exported) == self.test_data + assert json__equals__list_and_set(json_loads(exported), self.test_data) is True def test_primitive_values(self): # Test handling primitive values values = ["string", 42, 3.14, True, False, None ] @@ -67,7 +67,7 @@ def test_array_handling(self): assert items[1] == "two" assert items[2] == {"three": 3} assert items[3] == [4, 5] - assert self.mgraph.export().to_dict() == array_data + assert json__equals__list_and_set(self.mgraph.export().to_dict(), array_data) def test_nested_structures(self): # Test nested JSON structures nested_data = {"level1": {"level2": {"level3": {"array": [1, 2, {"key": "value"}], @@ -75,7 +75,7 @@ def test_nested_structures(self): graph = self.mgraph.load().from_data(nested_data) root_content = graph.root_content() assert isinstance(root_content, Domain__MGraph__Json__Node__Dict) - assert self.mgraph.export().to_dict() == nested_data + assert json__equals__list_and_set(self.mgraph.export().to_dict(), nested_data) is True def test_empty_structures(self): # Test empty JSON structures empty_data = { "empty_object" : {} , diff --git a/tests/unit/query/actions/test_MGraph__Query__Export__View.py b/tests/unit/query/actions/test_MGraph__Query__Export__View.py index 7d50ee0..e9be298 100644 --- a/tests/unit/query/actions/test_MGraph__Query__Export__View.py +++ b/tests/unit/query/actions/test_MGraph__Query__Export__View.py @@ -7,6 +7,7 @@ from mgraph_ai.providers.json.models.Model__MGraph__Json__Graph import Model__MGraph__Json__Graph from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Graph import Schema__MGraph__Json__Graph from mgraph_ai.query.models.Model__MGraph__Query__View import Model__MGraph__Query__View +from osbot_utils.utils.Json import json__equals__list_and_set class test_MGraph__Query__Export__View(TestCase): @@ -71,8 +72,9 @@ def test__create_dot__no_filter(self): property_2 = _.add_property('1234', node_id=root_property_id, value='xyz') _.add_value ('12345', node_id=property_1.node_id) - assert self.mgraph_json.export().to_dict() == {'1234': 'xyz', 'abc': '12345' , - ** self.test_data} + expected_dict = {'1234': 'xyz', 'abc': '12345' , + ** self.test_data} + assert json__equals__list_and_set(self.mgraph_json.export().to_dict(),expected_dict) #edge_1 = _.new_edge(from_node_id=root_property_id, to_node_id=property_node.node_id)