Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of #46 #50

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions examples/demo-entity-relation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from __future__ import print_function

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

import pyyed

g = pyyed.Graph()
g.add_node('Person', shape_fill="#EEEEEE",
node_type="GenericNode",
ER={"attributes": ["name", "surname"]})

#This is an entity without any attribut, for which only name will be set
g.add_node('Role', shape_fill="#EEEEEE",
node_type="GenericNode",
ER={})

g.add_node('Kind', shape_fill="#EEEEEE",
node_type="GenericNode",
ER={'weak':'true'})

# g.add_node('ICar', shape_fill="#EEEEEE",
# node_type="UMLClassNode",
# UML={"stereotype": "interface",
# "attributes": "",
# "methods": "getModel()\ngetManufacturer()\ngetPrice()\nsetPrice()"})

#g.add_node('Vehicle', shape_fill="#EEEEEE", node_type="UMLClassNode")
#g.add_edge('Car', 'Vehicle', arrowhead="white_delta")
#g.add_edge('Car', 'ICar', arrowhead="white_delta", line_type="dashed")
#g.add_node('This is a note', shape_fill="#EEEEEE", node_type="UMLNoteNode")

# print(g.get_graph())

g.write_graph('demo-entity-relation.graphml')
60 changes: 54 additions & 6 deletions pyyed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ def __init__(self, node_name, label=None, label_alignment="center", shape="recta
shape_fill="#FF0000", transparent="false", border_color="#000000",
border_type="line", border_width="1.0", height=False, width=False, x=False,
y=False, node_type="ShapeNode", UML=False,
ER=False,
custom_properties=None, description="", url=""):

self.label = label
Expand All @@ -234,8 +235,14 @@ def __init__(self, node_name, label=None, label_alignment="center", shape="recta

self.node_name = node_name

# Entity node must be created as a GenericNode with a configuration attribute
self.node_type = node_type
self.UML = UML
# library defines the used yEd library. Currently, we support UML and Entity Relation
self.library = {}
if UML:
self.library['UML']=UML
elif ER:
self.library['ER']=ER

self.parent = None

Expand Down Expand Up @@ -324,19 +331,49 @@ def convert(self):
alignment=self.label_alignment)
label.text = self.label

ET.SubElement(shape, "y:Shape", type=self.shape)
subshape = ET.SubElement(shape, "y:Shape", type=self.shape)

if self.UML:
if 'UML' in self.library:
UML = ET.SubElement(shape, "y:UML")

attributes = ET.SubElement(UML, "y:AttributeLabel", type=self.shape)
attributes.text = self.UML["attributes"]
attributes.text = self.library['UML']["attributes"]

methods = ET.SubElement(UML, "y:MethodLabel", type=self.shape)
methods.text = self.UML["methods"]
methods.text = self.library['UML']["methods"]

stereotype = self.UML["stereotype"] if "stereotype" in self.UML else ""
stereotype = self.library['UML']["stereotype"] if "stereotype" in self.library['UML'] else ""
UML.set("stereotype", stereotype)
elif 'ER' in self.library:
shape.remove(subshape)
shape.set("configuration", "com.yworks.entityRelationship.big_entity")
label.set("configuration", "com.yworks.entityRelationship.label.name")
if 'attributes' in self.library['ER']:
attributes = ET.SubElement(shape, "y:NodeLabel", fontFamily=self.font_family,
fontSize=self.font_size,
underlinedText=self.underlined_text,
fontStyle=self.font_style,
alignment='left',
configuration="com.yworks.entityRelationship.label.attributes",
modelName='internal',
modelPostion='t')
attributes_param = self.library['ER']['attributes']
if isinstance(attributes_param, list):
attributes_param = "\n".join(attributes_param)
attributes.text = attributes_param
labelModel = ET.SubElement(attributes, "y:LabelModel")
modelParameter = ET.SubElement(attributes, "y:ModelParameter")
ET.SubElement(labelModel, "y:ErdAttributesNodeLabelModel")
ET.SubElement(modelParameter, "y:ErdAttributesNodeLabelModelParameter")

label.set('modelName', 'internal')
label.set('modelPosition', 't')
styledProperty = ET.SubElement(shape, "y:StyleProperties")
ET.SubElement(styledProperty, "y:Property", {'class':"java.lang.Boolean", 'name':"y.view.ShadowNodePainter.SHADOW_PAINTING", 'value':"true"})
weak = 'false'
if 'weak' in self.library['ER'] and self.library['ER']['weak']:
weak = 'true'
ET.SubElement(styledProperty, "y:Property", {'class':"java.lang.Boolean", 'name':"doubleBorder", 'value':weak})

if self.url:
url_node = ET.SubElement(node, "data", key="url_node")
Expand Down Expand Up @@ -565,6 +602,17 @@ def get_graph(self):
return ET.tostring(self.graphml, encoding='UTF-8').decode()

def add_node(self, node_name, **kwargs):
"""
Adds a node to the graph.

Parameters
----------
node_name : str
name of generated node
kwargs : dict, optional
contains a list of additionnal parameters.
Supported values are all parameters to Node constructor
"""
if node_name in self.existing_entities:
raise RuntimeWarning("Node %s already exists" % node_name)

Expand Down
10 changes: 5 additions & 5 deletions tests/test_pyyed.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ def test_uml_node_properties_are_set():
"attributes": expected_attributes,
"methods": expected_methods})

assert g.nodes["AbstractClass"].UML["stereotype"] == expected_stereotype
assert g.nodes["AbstractClass"].UML["attributes"] == expected_attributes
assert g.nodes["AbstractClass"].UML["methods"] == expected_methods
assert g.nodes["AbstractClass"].library['UML']["stereotype"] == expected_stereotype
assert g.nodes["AbstractClass"].library['UML']["attributes"] == expected_attributes
assert g.nodes["AbstractClass"].library['UML']["methods"] == expected_methods

graphml = g.get_graph()
assertUmlNode(graphml, expected_stereotype,
Expand All @@ -67,8 +67,8 @@ def test_uml_stereotype_is_optional():
UML={"attributes": expected_attributes,
"methods": expected_methods})

assert g.nodes["Class"].UML["methods"] == expected_methods
assert g.nodes["Class"].UML["attributes"] == expected_attributes
assert g.nodes["Class"].library['UML']["methods"] == expected_methods
assert g.nodes["Class"].library['UML']["attributes"] == expected_attributes

graphml = g.get_graph()
assertUmlNode(graphml, "", expected_attributes, expected_methods)
Expand Down
34 changes: 34 additions & 0 deletions tests/test_pyyed_entity_relationship.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import pyyed
import xml.etree.ElementTree as xml

import pytest


def test_er_node_properties_are_set():
expected_attributes = 'attribute 1\nattribute 2'

g = pyyed.Graph()

g.add_node('BigEntity', node_type="GenericNode",
ER={'attributes': expected_attributes})

assert g.nodes["BigEntity"].library['ER']["attributes"] == expected_attributes

graphml = g.get_graph()
# assertERNode(graphml,
# expected_attributes)


# def assertERNode(graphml, expected_stereotype, expected_attributes, expected_methods):
# doc = xml.fromstring(graphml)
# nsmap = {'g': 'http://graphml.graphdrawing.org/xmlns',
# 'y': 'http://www.yworks.com/xml/graphml'
# }
# ernode = doc.find(
# 'g:graph/g:node/g:data/y:UMLClassNode/y:UML', namespaces=nsmap)
# attributes = ernode.find('y:AttributeLabel', namespaces=nsmap)
# methods = ernode.find('y:MethodLabel', namespaces=nsmap)
#
# assert ernode.attrib['stereotype'] == expected_stereotype
# assert attributes.text == expected_attributes
# assert methods.text == expected_methods