# -*- coding: utf-8 -*- import datetime import EditorialModel from EditorialModel.classtypes import EmClassType from EditorialModel.types import EmType from EditorialModel.fields import EmField from Lodel.utils.mlstring import MlString from EditorialModel.backend.dummy_backend import EmBackendDummy class EmBackendGraphviz(EmBackendDummy): ## @brief Constructor # @param dot_fname str : The filename where we want to save the dot repr of the EM def __init__(self, dot_fname): self.edges = "" self.dot_fname = dot_fname #with open(dot_file, 'w+') as dot_fp: ## @brief Not implementend # @warning Not implemented def load(self): raise NotImplementedError(self.__class__.__name__+' cannot load an EM') ## @brief Save an EM in a dot file # @param em model : The EM to save # @warning hardcoded classtype def save(self, em): self.edges = "" with open(self.dot_fname, 'w') as dotfp: dotfp.write("digraph G {\n\trankdir = BT\n") dotfp.write('subgraph cluster_classtype {\nstyle="invis"\n') for ct in [ 'entity', 'entry', 'person' ]: dotfp.write('\n\nct%s [ label="classtype %s" shape="tripleoctagon" ]\n'%(ct, ct)) dotfp.write("}\n") dotfp.write('subgraph cluster_class {\nstyle="invis"\n') for c in em.classes(): dotfp.write(self._component_node(c, em)) cn = c.__class__.__name__ cid = self._component_id(c) self.edges += cid+' -> ct%s [ style="dashed" ]\n'%c.classtype dotfp.write("}\n") #dotfp.write('subgraph cluster_type {\nstyle="invis"\n') for c in em.components(EmType): dotfp.write(self._component_node(c, em)) cn = c.__class__.__name__ cid = self._component_id(c) self.edges += cid+' -> '+self._component_id(c.em_class)+' [ style="dotted" ]\n' for nat, sups in c.superiors().items(): for sup in sups: self.edges += cid+' -> '+self._component_id(sup)+' [ label="%s" color="green" ]'%nat #dotfp.write("}\n") for rf in [ f for f in em.components(EmField) if f.fieldtype == 'rel2type']: dotfp.write(self._component_node(rf, em)) cid = self._component_id(rf) self.edges += cid+' -> '+self._component_id(rf.em_class)+'\n' self.edges += cid+' -> '+self._component_id(em.component(rf.rel_to_type_id))+'\n' dotfp.write(self.edges) dotfp.write("\n}") pass @staticmethod def _component_id(c): return 'emcomp%d'%c.uid def _component_node(self, c, em): #ret = 'emcomp%d '%c.uid ret = "\t"+EmBackendGraphviz._component_id(c) cn = c.__class__.__name__ rel_field = "" if cn == 'EmClass': ret += '[ label="%s", shape="%s" ]'%(c.name.replace('"','\\"'), 'doubleoctagon') elif cn == 'EmField': str_def = '[ label="Rel2Type {fname}|{{{records}}}", shape="record"]' records = ' | '.join([f.name for f in em.components('EmField') if f.rel_field_id == c.uid]) ret += str_def.format(fname=c.name.replace('"','\\"'), records=records) elif cn == 'EmType': ret += '[ label="%s %s '%(cn, c.name.replace('"','\\"')) cntref = 0 first = True for f in [ f for f in c.fields() if f.name not in c.em_class.default_fields_list().keys()]: if cn == 'EmType' and f.rel_field_id is None: #if not (f.rel_to_type_id is None): if isinstance(f, EditorialModel.fieldtypes.rel2type.EmFieldType): rel_node_id = '%s%s'%(EmBackendGraphviz._component_id(c), EmBackendGraphviz._component_id(em.component(f.rel_to_type_id))) rel_node = '\t%s [ label="rel_to_type'%rel_node_id if len(f.rel_to_type_fields()) > 0: #rel_node += '| {' first = True for rf in f.rel_to_type_fields(): rel_node += ' | ' if first: rel_node += '{ ' first = False rel_node += rf.name rel_node += '}" shape="record" style="dashed"]\n' rel_field += rel_node ref_node = EmBackendGraphviz._component_id(em.component(f.rel_to_type_id)) self.edges += '%s:f%d -> %s [ color="purple" ]\n'%(EmBackendGraphviz._component_id(c), cntref, rel_node_id) self.edges += '%s -> %s [color="purple"]\n'%(rel_node_id, ref_node) ret += '|' if first: ret += ' { ' first = False #if not (f.rel_to_type_id is None): if isinstance(f, EditorialModel.fieldtypes.rel2type.EmFieldType): ret += ' '%cntref cntref += 1 ret += f.name ret += '}" shape="record" color="%s" ]'%('blue' if cn == 'EmType' else 'red') else: return "" ret +="\n"+rel_field return ret