Skip to content

Commit

Permalink
added two new MGraph__Export methods: to__dot_types and to__dot_schema
Browse files Browse the repository at this point in the history
couple more fixes to MGraph__Json__Edit so that now we cover all possible ways data can be added to a MGraph__Json document
  • Loading branch information
DinisCruz committed Jan 28, 2025
1 parent 0e5544e commit 2c483e0
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 30 deletions.
86 changes: 86 additions & 0 deletions mgraph_ai/mgraph/actions/MGraph__Export.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,92 @@ def to__dot(self) -> str:
lines.append('}')
return '\n'.join(lines)

def to__dot_types(self) -> str: # Export as DOT graph showing node structure
lines = ['digraph {',
' graph [fontname="Arial", ranksep=0.8]', # Basic graph styling
' node [fontname="Arial"]', # Default node font
' edge [fontname="Arial", fontsize=10]' # Edge styling
]

def fix_value(value: str) -> str:
return value.replace('Schema__MGraph__', '').replace('_', ' ')

with self.data() as _:
# Output nodes with their IDs and type labels
for node in _.nodes():
node_id = node.node_id
node_type = fix_value(node.node.data.node_type.__name__)

node_attrs = ['shape=box' , # Visual styling
'style="rounded,filled"' , # Enable both rounded corners and fill
'fillcolor=lightblue' , # Node color
f'label="{node_type}"' ] # Show both type and ID

if node.node_data: # Add node data if present
for field_name, field_value in node.node_data.__dict__.items():
node_attrs.append(f'{field_name}="{field_value}"')

attrs_str = f' [{", ".join(node_attrs)}]'
lines.append(f' "{node_id}"{attrs_str}')

for edge in _.edges(): # Output edges using node IDs
edge_id = edge.edge_id
edge_type = fix_value(edge.edge.data.edge_type.__name__)
from_id = edge.from_node_id()
to_id = edge.to_node_id()

lines.append(f' "{from_id}" -> "{to_id}" [label=" {edge_type}"]')

lines.append('}')
return '\n'.join(lines)

def to__dot_schema(self) -> str: # Export as DOT graph showing types
lines = ['digraph {',
' graph [fontname="Arial", ranksep=0.8]', # Basic graph styling
' node [fontname="Arial"]', # Default node font
' edge [fontname="Arial", fontsize=10]' # Edge styling
]

def fix_value(value: str) -> str:
return value.replace('Schema__MGraph__', '').replace('_', ' ')

# Track unique nodes and edges
unique_nodes = set()
unique_edges = set()

with self.data() as _:
# First pass: collect unique node types
for node in _.nodes():
node_type = fix_value(node.node.data.node_type.__name__)
if node_type not in unique_nodes:
unique_nodes.add(node_type)
node_attrs = ['shape=box', # Visual styling
'style="rounded,filled"', # Enable both rounded corners and fill
'fillcolor=lightblue'] # Node color

if node.node_data: # Add node data if present
for field_name, field_value in node.node_data.__dict__.items():
node_attrs.append(f'{field_name}="{field_value}"')

attrs_str = f' [{", ".join(node_attrs)}]'
lines.append(f' "{node_type}"{attrs_str}')

# Second pass: collect unique edge relationships
for edge in _.edges():
edge_type = fix_value(edge.edge.data.edge_type.__name__)
from_type = fix_value(edge.from_node().node.data.node_type.__name__)
to_type = fix_value(edge.to_node().node.data.node_type.__name__)

# Create a unique identifier for this type of connection
edge_key = (from_type, to_type, edge_type)

if edge_key not in unique_edges:
unique_edges.add(edge_key)
lines.append(f' "{from_type}" -> "{to_type}" [label=" {edge_type}"]')

lines.append('}')
return '\n'.join(lines)

def to__graphml(self) -> str: # Export as GraphML
graphml_ns = "http://graphml.graphdrawing.org/xmlns" # Define namespace

Expand Down
17 changes: 16 additions & 1 deletion mgraph_ai/providers/json/actions/MGraph__Json__Edit.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from mgraph_ai.providers.json.actions.MGraph__Json__Data import MGraph__Json__Data
from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__Dict import Schema__MGraph__Json__Node__Dict
from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__List import Schema__MGraph__Json__Node__List
from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__Property__Data import Schema__MGraph__Json__Node__Property__Data
from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__Value import Schema__MGraph__Json__Node__Value
from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__Value__Data import Schema__MGraph__Json__Node__Value__Data
Expand All @@ -9,8 +11,21 @@
class MGraph__Json__Edit(MGraph__Edit):
data_type : type[MGraph__Json__Data]

def add_dict(self, node_id=None): # todo: add check that node_id is either a property or a list
node_dict = Schema__MGraph__Json__Node__Dict()
new_node = self.add_node(node_dict)
if node_id:
self.new_edge(from_node_id=node_id, to_node_id= new_node.node_id)
return new_node

def add_list(self, node_id=None): # todo: add check that node_id is either a property or a list
node_dict = Schema__MGraph__Json__Node__List()
new_node = self.add_node(node_dict)
if node_id:
self.new_edge(from_node_id=node_id, to_node_id= new_node.node_id)
return new_node

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 = Schema__MGraph__Json__Node__Property (node_data = node_property_data)
new_node = self.add_node(node_property)
Expand Down
2 changes: 2 additions & 0 deletions mgraph_ai/providers/json/actions/MGraph__Json__Export.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ def process_dict_node(self, node_id: Obj_Id, index: MGraph__Index) -> Dict[str,
if value_edges:
value_node_id = index.edge_to_nodes()[value_edges[0]][1]
result[property_name] = self.process_node(value_node_id, index)
else:
result[property_name] = None
return result

def process_list_node(self, node_id: Obj_Id, index: MGraph__Index) -> List[Any]:
Expand Down
12 changes: 11 additions & 1 deletion mgraph_ai/providers/json/actions/MGraph__Json__Screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,17 @@ def dot(self):
return screenshot_bytes

def dot__just_ids(self):
dot_code = self.export().to__dot()
dot_code = self.export().to__dot()
screenshot_bytes = self.create_screenshot__from__dot_code(dot_code)
return screenshot_bytes

def dot__just_types(self):
dot_code = self.export().to__dot_types()
screenshot_bytes = self.create_screenshot__from__dot_code(dot_code)
return screenshot_bytes

def dot__schema(self):
dot_code = self.export().to__dot_schema()
screenshot_bytes = self.create_screenshot__from__dot_code(dot_code)
return screenshot_bytes

Expand Down
137 changes: 109 additions & 28 deletions tests/unit/providers/json/actions/test_MGraph__Json__Edit.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
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
from mgraph_ai.providers.json.models.Model__MGraph__Json__Node__Dict import Model__MGraph__Json__Node__Dict
from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__Dict import Schema__MGraph__Json__Node__Dict
from mgraph_ai.providers.json.MGraph__Json import MGraph__Json
from unittest import TestCase
from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__List import Schema__MGraph__Json__Node__List
from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__Property import Schema__MGraph__Json__Node__Property
from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__Value import Schema__MGraph__Json__Node__Value
from osbot_utils.utils.Json import json__equals__list_and_set
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
from mgraph_ai.providers.json.models.Model__MGraph__Json__Node__Dict import Model__MGraph__Json__Node__Dict
from mgraph_ai.providers.json.schemas.Schema__MGraph__Json__Node__Dict import Schema__MGraph__Json__Node__Dict
from mgraph_ai.providers.json.MGraph__Json import MGraph__Json


class test_MGraph__Json__Edit(TestCase):
Expand Down Expand Up @@ -48,31 +49,111 @@ def test_add_property(self):
assert type(new_property_2 ) is Domain__MGraph__Json__Node
assert type(value_node ) is Domain__MGraph__Json__Node


assert self.mgraph_json.export().to_dict() == {'1234': 'xyz', 'abc': '12345'} # confirm values set correctly

def test_add_property_to_property(self):
def test_add_list(self):
assert self.mgraph_json.export().to_dict() is None
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 )
new_property_1 = _.add_property('abc', node_id=root_property_node.node_id)
export__step_1 = self.mgraph_json.export().to_dict()

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())
new_list_1 = _.add_list(node_id=new_property_1.node_id )
export__step_2 = self.mgraph_json.export().to_dict()

new_value_1 = _.add_value(value='an_value', node_id=new_list_1.node_id)
export__step_3 = self.mgraph_json.export().to_dict()

new_list_2 = _.add_list(node_id=new_list_1.node_id )
export__step_4 = self.mgraph_json.export().to_dict()

new_dict_1 = _.add_dict(node_id=new_list_1.node_id )
export__step_5 = self.mgraph_json.export().to_dict()

new_property_2 = _.add_property('abc' , node_id=new_dict_1.node_id , value='a')
export__step_6 = self.mgraph_json.export().to_dict()

new_property_3 = _.add_property('def' , node_id=root_property_node.node_id )
export__step_7 = self.mgraph_json.export().to_dict()

new_dict_2 = _.add_dict(node_id=new_property_3.node_id)
export__step_8 = self.mgraph_json.export().to_dict()

root_node_id = _.data().root_node_id()
new_list_3 = _.add_list(node_id=root_node_id)

# with self.mgraph_json.index() as _:
# _.print()
export__step_9 = self.mgraph_json.export().to_dict() # this will have no effect on the output
new_value_2 = _.add_value('a', node_id=root_node_id)

export__step_10 = self.mgraph_json.export().to_dict() # this will have no effect on the output (I just wanted to have a full schema :) )

#self.mgraph_json.screenshot().save().dot__just_ids()
#self.mgraph_json.screenshot().save().dot()
assert type(root_property_node ) is Domain__MGraph__Json__Node__Dict
assert type(new_property_1.node.data) is Schema__MGraph__Json__Node__Property
assert type(new_list_1.node.data ) is Schema__MGraph__Json__Node__List
assert type(new_value_1.node.data ) is Schema__MGraph__Json__Node__Value
assert type(new_list_2.node.data ) is Schema__MGraph__Json__Node__List
assert type(new_dict_1.node.data ) is Schema__MGraph__Json__Node__Dict
assert type(new_property_2.node.data) is Schema__MGraph__Json__Node__Property
assert type(new_property_3.node.data) is Schema__MGraph__Json__Node__Property
assert type(new_dict_2.node.data ) is Schema__MGraph__Json__Node__Dict
assert type(new_list_3.node.data ) is Schema__MGraph__Json__Node__List
assert type(new_value_2.node.data ) is Schema__MGraph__Json__Node__Value

assert self.mgraph_json.export().to_dict() == {'parent': None} # BUG should be {'parent': { 'child': None }}
assert export__step_1 == {'abc': None}
assert export__step_2 == {'abc': []}
assert export__step_3 == {'abc': ['an_value']}
assert json__equals__list_and_set(export__step_4, {'abc': ['an_value', [] ] }) is True
assert json__equals__list_and_set(export__step_5, {'abc': ['an_value', [], {} ] }) is True
assert json__equals__list_and_set(export__step_6, {'abc': ['an_value', [], {'abc': 'a' }] }) is True
assert json__equals__list_and_set(export__step_7, {'abc': ['an_value', [], {'abc': 'a' }], 'def': None}) is True
assert json__equals__list_and_set(export__step_8, {'abc': ['an_value', [], {'abc': 'a' }], 'def': {} }) is True
assert export__step_8 == export__step_9
assert export__step_9 == export__step_10

#pprint(self.mgraph_json.export().to_dict())


def test_add_property__just_one(self):
with self.mgraph_json.edit() as _:
root_property_node = _.add_root_property_node()
new_property_1 = _.add_property('abc' , node_id=root_property_node.node_id ) # add property with no value

assert type(new_property_1) is Domain__MGraph__Json__Node

assert self.mgraph_json.export().to_dict() == {'abc': None}

def test_add_dict_to_property(self):
with self.mgraph_json.edit() as _:
root_property_node = _.add_root_property_node()
export__step_1 = self.mgraph_json.export().to_dict()
new_property_1 = _.add_property('parent' , node_id=root_property_node.node_id)
export__step_2 = self.mgraph_json.export().to_dict()
new_dict_1 = _.add_dict (node_id=new_property_1.node_id )
export__step_3 = self.mgraph_json.export().to_dict()
new_property_2 = _.add_property('without_value', node_id=new_dict_1.node_id )
export__step_4 = self.mgraph_json.export().to_dict()
new_property_3 = _.add_property('with_value' , node_id=new_dict_1.node_id , value='an-value')
export__step_5 = self.mgraph_json.export().to_dict()

assert type(new_property_1) == Domain__MGraph__Json__Node
assert type(new_property_2) == Domain__MGraph__Json__Node
assert type(new_property_3) == Domain__MGraph__Json__Node

assert export__step_1 == {}
assert export__step_2 == {'parent': None }
assert export__step_3 == {'parent': {} }
assert export__step_4 == {'parent': {'without_value': None }}
assert export__step_5 == {'parent': {'with_value' : 'an-value', 'without_value': None }}

assert self.mgraph_json.export().to_dict() == {'parent': {'with_value' : 'an-value',
'without_value': None }}

# self.mgraph_json.screenshot().save().dot__just_ids ()
# self.mgraph_json.screenshot().save().dot__just_types()
# self.mgraph_json.screenshot().save().dot__schema()
# self.mgraph_json.screenshot().save().dot()

# def test_show(self):
# test_data = {'a': {'b':123}}
# self.mgraph_json.load().from_data(test_data)
# self.mgraph_json.screenshot().save().dot__just_types()
# assert self.mgraph_json.export().to_dict() == test_data

0 comments on commit 2c483e0

Please sign in to comment.