diff --git a/sbol_factory/sbol_factory.py b/sbol_factory/sbol_factory.py index 9a63d27..c00f3fd 100644 --- a/sbol_factory/sbol_factory.py +++ b/sbol_factory/sbol_factory.py @@ -75,14 +75,19 @@ class SBOLFactory(): # Prefixes are used to automatically generate module names namespace_to_prefix = {} + for ns, prefix in graph.namespaces(): + namespace_to_prefix[str(ns)] = prefix def __new__(cls, module_name, ontology_path, ontology_namespace, verbose=False): if verbose is False: logging.disable('INFO') SBOLFactory.graph.parse(ontology_path, format=rdflib.util.guess_format(ontology_path)) for prefix, ns in SBOLFactory.graph.namespaces(): - SBOLFactory.namespace_to_prefix[str(ns)] = prefix + # Skip default prefixes + if ns in SBOLFactory.namespace_to_prefix: + continue # TODO: handle namespace with conflicting prefixes + SBOLFactory.namespace_to_prefix[str(ns)] = prefix # Use ontology prefix as module name ontology_namespace = ontology_namespace diff --git a/sbol_factory/uml_factory.py b/sbol_factory/uml_factory.py index 679fdc9..de3bc59 100644 --- a/sbol_factory/uml_factory.py +++ b/sbol_factory/uml_factory.py @@ -40,6 +40,7 @@ def generate(self, output_path): class_name = sbol.utils.parse_class_name(class_uri) dot = graphviz.Digraph(class_name) # dot.graph_attr['splines'] = 'ortho' + dot.graph_attr['dpi'] = '300' superclass_uri = self.query.query_superclass(class_uri) create_inheritance(dot, superclass_uri, class_uri) @@ -54,6 +55,8 @@ def generate(self, output_path): source = graphviz.Source(dot_source_sanitized) outfile = f'{class_name}_abstraction_hierarchy' source.render(os.path.join(output_path, outfile)) + source = graphviz.Source(dot_source_sanitized, format='png') + source.render(os.path.join(output_path, outfile)) outfile += '.pdf' width = 470 # default \textwidth of LaTeX document with open(os.path.join(output_path, outfile), 'rb') as pdf: diff --git a/test/test_files/Activity_abstraction_hierarchy.dot b/test/test_files/Activity_abstraction_hierarchy.dot new file mode 100644 index 0000000..4699346 --- /dev/null +++ b/test/test_files/Activity_abstraction_hierarchy.dot @@ -0,0 +1,8 @@ +digraph Activity { + graph [dpi=300] + prov_Activity -> uml_Activity [arrowtail=empty dir=back fontname="Bitstream Vera Sans" fontsize=8] + prov_Activity [label="{prov:Activity|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] + uml_Activity [label="{uml:Activity|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] + uml_Activity -> paml_BehaviorExecution [arrowtail=empty dir=back fontname="Bitstream Vera Sans" fontsize=8] + paml_BehaviorExecution [label="{paml:BehaviorExecution|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] +} diff --git a/test/test_files/Base_abstraction_hierarchy.dot b/test/test_files/Base_abstraction_hierarchy.dot new file mode 100644 index 0000000..ce542d4 --- /dev/null +++ b/test/test_files/Base_abstraction_hierarchy.dot @@ -0,0 +1,16 @@ +digraph Base { + graph [dpi=300] + sbol_TopLevel -> test_Base [arrowtail=empty dir=back fontname="Bitstream Vera Sans" fontsize=8] + sbol_TopLevel [label="{sbol:TopLevel|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] + test_Base [label="{test:Base|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] + test_Base -> test_Derived1 [arrowtail=empty dir=back fontname="Bitstream Vera Sans" fontsize=8] + test_Derived1 [label="{test:Derived1|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] + test_Base -> test_Derived2 [arrowtail=empty dir=back fontname="Bitstream Vera Sans" fontsize=8] + test_Derived2 [label="{test:Derived2|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] + test_Derived2 -> test_Child [arrowhead=vee arrowtail=diamond dir=both fontname="Bitstream Vera Sans" fontsize=8 xlabel="test:hasChild [0..*]"] + test_Child [label="{test:Child|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] + test_Child -> test_ChildDerived1 [arrowtail=empty dir=back fontname="Bitstream Vera Sans" fontsize=8] + test_ChildDerived1 [label="{test:ChildDerived1|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] + test_Child -> test_ChildDerived2 [arrowtail=empty dir=back fontname="Bitstream Vera Sans" fontsize=8] + test_ChildDerived2 [label="{test:ChildDerived2|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] +} diff --git a/test/test_files/test-minimal-ontology.ttl b/test/test_files/test-minimal-ontology.ttl new file mode 100644 index 0000000..2c7517d --- /dev/null +++ b/test/test_files/test-minimal-ontology.ttl @@ -0,0 +1,32 @@ +@prefix om: . +@prefix owl: . +@prefix rdf: . +@prefix xsd: . +@prefix rdfs: . +@prefix sbol: . +@prefix test: . +@base . + +test:Base rdf:type owl:Class ; + rdfs:subClassOf sbol:TopLevel . + +test:Derived1 rdf:type owl:Class ; + rdfs:subClassOf test:Base . + +test:Derived2 rdf:type owl:Class ; + rdfs:subClassOf test:Base . + +test:Child rdf:type owl:Class ; + rdfs:subClassOf sbol:Identified . + +test:ChildDerived1 rdf:type owl:Class ; + rdfs:subClassOf test:Child . + +test:ChildDerived2 rdf:type owl:Class ; + rdfs:subClassOf test:Child . + +test:hasChild rdf:type owl:ObjectProperty ; + rdfs:subPropertyOf sbol:directlyComprises ; + rdfs:label "has_child" ; + rdfs:domain test:Derived2 ; + rdfs:range test:Child . diff --git a/test/test_files/test-uml.ttl b/test/test_files/test-uml.ttl new file mode 100644 index 0000000..d3e7c20 --- /dev/null +++ b/test/test_files/test-uml.ttl @@ -0,0 +1,25 @@ +@prefix paml: . +@prefix opil: . +@prefix uml: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix xsd: . +@prefix sbol: . +@prefix prov: . +@base . + +paml:SubClass rdf:type owl:Class ; + rdfs:subClassOf paml:SuperClass . + +paml:SuperClass rdf:type owl:Class ; + rdfs:subClassOf sbol:TopLevel . + +paml:Child rdf:type owl:Class ; + rdfs:subClassOf sbol:Identified . + +paml:child rdf:type owl:ObjectProperty ; + rdfs:subPropertyOf opil:compositionalProperty ; + rdfs:domain paml:SubClass ; + rdfs:range paml:Child ; + rdfs:label "child" . diff --git a/test/test_modules.py b/test/test_modules.py index 6d75313..3704e43 100644 --- a/test/test_modules.py +++ b/test/test_modules.py @@ -15,39 +15,59 @@ def tearDown(self): SBOLFactory.clear() def test_ontology_to_module(self): + self.assertTrue(check_namespaces()) SBOLFactory('uml', os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_files/test-modules.ttl'), 'http://bioprotocols.org/uml#') self.assertTrue('uml' in sys.modules) + self.assertTrue(check_namespaces()) SBOLFactory('paml', os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_files/test-modules.ttl'), 'http://bioprotocols.org/paml#') self.assertTrue('paml' in sys.modules) + self.assertTrue(check_namespaces()) import uml import paml uml.Activity('http://test.org/umlact') paml.BehaviorExecution('http://test.org/BX') -# def test_figure_generation(self): -# path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_files/test-modules.ttl') -# SBOLFactory('uml', path,'http://bioprotocols.org/uml#') -# figure_maker = UMLFactory(path,'http://bioprotocols.org/uml#') -# # TODO: check whether generated figure is correct -# tmp = tempfile.mkdtemp() -# print(f'Exporting test figures into {tmp}') -# figure_maker.generate(tmp) -# dot_source_actual = '' -# with open(os.path.join(tmp, 'Activity_abstraction_hierarchy')) as dot_file: -# dot_source_actual = dot_file.read() -# dot_source_expected = '''digraph Activity { -# prov_Activity -> uml_Activity [arrowtail=empty dir=back fontname="Bitstream Vera Sans" fontsize=8] -# prov_Activity [label="{prov:Activity|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] -# uml_Activity [label="{uml:Activity|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] -# uml_Activity -> paml_BehaviorExecution [arrowtail=empty dir=back fontname="Bitstream Vera Sans" fontsize=8] -# paml_BehaviorExecution [label="{paml:BehaviorExecution|}" fontname="Bitstream Vera Sans" fontsize=8 shape=record] -#}\n''' -# self.assertEqual(dot_source_actual, dot_source_expected) + def test_figure_generation(self): + path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_files') + SBOLFactory('uml', os.path.join(path, 'test-modules.ttl'), 'http://bioprotocols.org/uml#') + figure_maker = UMLFactory(os.path.join(path, 'test-modules.ttl'), 'http://bioprotocols.org/uml#') + # TODO: check whether generated figure is correct + tmp = tempfile.mkdtemp() + print(f'Exporting test figures into {tmp}') + figure_maker.generate(tmp) + dot_source_actual = '' + with open(os.path.join(tmp, 'Activity_abstraction_hierarchy')) as dot_file: + dot_source_actual = dot_file.read().replace(' ', '') + with open(os.path.join(path, 'Activity_abstraction_hierarchy.dot')) as dot_file: + dot_source_expected = dot_file.read().replace(' ', '') + self.assertEqual(dot_source_actual, dot_source_expected) + def test_figure_generation2(self): + # This figure includes compositional properties + path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_files') + SBOLFactory('minimal', os.path.join(path, 'test-minimal-ontology.ttl'), 'http://bioprotocols.org/test#') + figure_maker = UMLFactory(os.path.join(path, 'test-minimal-ontology.ttl'), 'http://bioprotocols.org/test#') + # TODO: check whether generated figure is correct + tmp = tempfile.mkdtemp() + print(f'Exporting test figures into {tmp}') + figure_maker.generate(tmp) + dot_source_actual = '' + with open(os.path.join(tmp, 'Base_abstraction_hierarchy')) as dot_file: + dot_source_actual = dot_file.read().replace(' ', '') + with open(os.path.join(path, 'Base_abstraction_hierarchy.dot')) as dot_file: + dot_source_expected = dot_file.read().replace(' ', '') + self.assertEqual(dot_source_actual, dot_source_expected) + +def check_namespaces(): + prefixes = [p for p, ns in SBOLFactory.graph.namespaces()] + if 'default1' in prefixes: + print(prefixes) + return False + return True if __name__ == '__main__': unittest.main()