From ab8355fc7199b6407d2be128939c91c8e2f637d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20Lamercerie?=
 <aurelien.lamercerie@tetras-libre.fr>
Date: Thu, 16 Feb 2023 23:26:54 +0100
Subject: [PATCH] Update new transduction rule

---
 tenet/febTransduction/net/net.py              |  71 ++++-
 .../phenomena_application_or.py               |  56 +---
 tenet/febTransduction/uriref_computer.py      |  33 +++
 tenet/tenet.log                               |   2 +-
 tests/test_rule.py                            | 137 ++++++----
 tests/test_semantic_net_1.py                  | 242 +++++++++++-------
 6 files changed, 334 insertions(+), 207 deletions(-)
 create mode 100644 tenet/febTransduction/uriref_computer.py

diff --git a/tenet/febTransduction/net/net.py b/tenet/febTransduction/net/net.py
index 78b76a69..6356bcad 100644
--- a/tenet/febTransduction/net/net.py
+++ b/tenet/febTransduction/net/net.py
@@ -21,7 +21,7 @@ from febTransduction.query_builder import generate_select_query
 
 class Net:
     """ Class to handle semantic net.
-    """
+    """    
     
     #--------------------------------------------------------------------------
     # Constructor
@@ -31,7 +31,7 @@ class Net:
         
         # -- Net Support
         self.support_graph = support_graph
-        self.referenceHandle = SemanticNetReferenceHandle() 
+        self.referenceHandle = SemanticNetReferenceHandle()
         
         # -- Net Type
         self.type_name = 'default'
@@ -47,6 +47,7 @@ class Net:
         
            
         # -- Net Attributes
+        self.attr_list = ['node', 'base_node', 'structure', 'naming']
         self._node = []
         self._base_node = None
         self._structure = None
@@ -142,7 +143,10 @@ class Net:
     @node.setter
     def node(self, new_value):
         if isinstance(self._node, list):
-            self._node.append(new_value)
+            if isinstance(new_value, list):
+                self._node += new_value
+            else:
+                self._node.append(new_value)
         else:
             self._node = new_value
         
@@ -154,7 +158,10 @@ class Net:
     @base_node.setter
     def base_node(self, new_value):
         if isinstance(self._base_node, list):
-            self._base_node.append(new_value)
+            if isinstance(new_value, list):
+                self._node += new_value
+            else:
+                self._node.append(new_value)
         else:
             self._base_node = new_value
         
@@ -166,7 +173,10 @@ class Net:
     @structure.setter
     def structure(self, new_value):
         if isinstance(self._structure, list):
-            self._structure.append(new_value)
+            if isinstance(new_value, list):
+                self._node += new_value
+            else:
+                self._node.append(new_value)
         else:
             self._structure = new_value
         
@@ -178,7 +188,10 @@ class Net:
     @naming.setter
     def naming(self, new_value):
         if isinstance(self._naming, list):
-            self._naming.append(new_value)
+            if isinstance(new_value, list):
+                self._node += new_value
+            else:
+                self._node.append(new_value)
         else:
             self._naming = new_value
         
@@ -220,9 +233,46 @@ class Net:
     # Triple Generation Method
     #--------------------------------------------------------------------------
     
-    def __generation_attribute_triple_definition(self):
+    def __define_triple(self, uri, predicate, value):
+        
+        triple = None
+        
+        if isinstance(value, rdflib.term.URIRef):
+            value = value.n3(self.support_graph.namespace_manager)
+            triple = f'{uri} {predicate} {value}'
+        elif isinstance(value, str):
+            triple = f'{uri} {predicate} "{value}"'
+            
+        return triple
+        
+    
+    def __define_triple_list(self, uri, attr_predicate, attr_value):
+        
+        triples = []
+        
+        if (isinstance(attr_value, rdflib.term.URIRef) or 
+            isinstance(attr_value, str)):
+            new_triple = self.__define_triple(uri, attr_predicate, attr_value)
+            if new_triple is not None: triples.append(new_triple)
+            
+        elif isinstance(attr_value, list):
+            for value in attr_value:
+                new_triple = self.__define_triple(uri, attr_predicate, value)
+                if new_triple is not None: triples.append(new_triple)
+            
+        return triples
+    
+    
+    def __generate_attribute_triples(self, uri):
+        assert (self.uri is not None), 'URI must be set'
+        
         triple_definition = []
-        pass # TODO
+        
+        for attr in self.attr_list:
+            attr_predicate = self.referenceHandle.get_predicate_uri(attr)
+            attr_value = eval(f'self._{attr}')
+            triple_definition += self.__define_triple_list(uri, attr_predicate, attr_value)
+        
         return triple_definition
     
     
@@ -230,8 +280,9 @@ class Net:
         
         triple_definition = []
         
-        if self.uri is not None:
+        uri = self.uri
+        if uri is not None:
             triple_definition.append(f'{self.uri} a {self.type_uri}.')
-            triple_definition += self.__generation_attribute_triple_definition()
+            triple_definition += self.__generate_attribute_triples(uri)
             
         return triple_definition
\ No newline at end of file
diff --git a/tenet/febTransduction/phenomena_application_or.py b/tenet/febTransduction/phenomena_application_or.py
index 9c4d881f..4cb1586e 100644
--- a/tenet/febTransduction/phenomena_application_or.py
+++ b/tenet/febTransduction/phenomena_application_or.py
@@ -200,59 +200,5 @@ def analyze_phenomena_or_2(graph):
         new_triple_list += new_triples
     
     return rule_label, new_triple_list
-            
-            
-    
-#==============================================================================
-# Development Test
-#==============================================================================
-    
-if __name__ == '__main__':
-    
-    print('\n' + ' *** Development Test ***')  
-    
-    print(f'\n -- Test Graph Loading')
-    graph = Graph()
-    graph.bind('net', Namespace('https://tenet.tetras-libre.fr/semantic-net#'))
-    graph.parse('testGraph1.ttl')
-    print(f"----- Graph Loaded ({len(graph)})")
-    
-    
-    print('\n -- Select Pattern Application 1')
-    query_code = __select_pattern_1()
-    print(query_code)
-    pattern_result_set = graph.query(query_code) 
-    print(f'\n ----- number of selection found: {len(pattern_result_set)}')
-    for selection in pattern_result_set: 
-        result_str = f'>>> '
-        result_str += f'{selection.property_net.n3(graph.namespace_manager)}'
-        result_str += f' {selection.class_net.n3(graph.namespace_manager)}'
-        result_str += f' {selection.phenomena_net.n3(graph.namespace_manager)}'
-        print(result_str) 
-        
-    
-    print('\n -- Select Pattern Application 2')
-    query_code = __select_pattern_2()
-    print(query_code)
-    pattern_result_set = graph.query(query_code) 
-    print(f'\n ----- number of selection found: {len(pattern_result_set)}')
-    for selection in pattern_result_set: 
-        result_str = f'>>> '
-        result_str += f'{selection.property_net.n3(graph.namespace_manager)}'
-        result_str += f' {selection.property_net_0.n3(graph.namespace_manager)}'
-        result_str += f' {selection.phenomena_net.n3(graph.namespace_manager)}'
-        print(result_str) 
-        
-    print('\n -- Rule Test')
-    rule_label, new_triple_list = analyze_phenomena_or_2(graph)
-    print(f' ----- label: {rule_label}')
-    print(f' ----- new_triple_list: {len(new_triple_list)}')
-    for new_triple in new_triple_list:
-        print(f'        | {new_triple}')
-        
-    
-    # num = 0
-    # for query_label, query in rule.query_list:
-    #     num += 1
-    #     print(f'*** query {num} - {query_label} ***\n{query}\n')
+
     
\ No newline at end of file
diff --git a/tenet/febTransduction/uriref_computer.py b/tenet/febTransduction/uriref_computer.py
new file mode 100644
index 00000000..7bf24cc6
--- /dev/null
+++ b/tenet/febTransduction/uriref_computer.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python3.10
+# -*-coding:Utf-8 -*
+
+#==============================================================================
+# TENET: Naming Computer
+#------------------------------------------------------------------------------
+# Class grouping methods to compute URI for semantic nets (and their 
+# attributes)
+#==============================================================================
+
+from urllib.parse import quote_plus
+
+from rdflib import URIRef, Graph, RDF, SDO
+from rdflib.term import _is_valid_uri
+
+
+class InvalidURIRef(Exception):
+    """Raise when URIs are invalid."""
+    pass
+
+
+def create_uriref(uri):
+    """Create a URIRef with the same validation func used by URIRef
+
+    Except here an InvalidURIRef exception is raised.
+
+    The RDFLib _is_valid_uri only checks for invalid characters. You can also add your
+    own validation checks.
+    """
+    if _is_valid_uri(uri):
+        return URIRef(uri)
+    raise InvalidURIRef(f'"{uri}" is not a valid URI.')
+    
\ No newline at end of file
diff --git a/tenet/tenet.log b/tenet/tenet.log
index 12fc6b53..b203d08e 100644
--- a/tenet/tenet.log
+++ b/tenet/tenet.log
@@ -1 +1 @@
-- DEBUG - handle_close[691355e6ad1411ed842d14abc581ea52]({'header': {'msg_id': '92e4b518-67db9b9669f0b8d6c0247971_4398_201', 'msg_type': 'comm_close', 'username': 'lamenji', 'session': '92e4b518-67db9b9669f0b8d6c0247971', 'date': datetime.datetime(2023, 2, 15, 23, 15, 46, 180154, tzinfo=tzutc()), 'version': '5.3'}, 'msg_id': '92e4b518-67db9b9669f0b8d6c0247971_4398_201', 'msg_type': 'comm_close', 'parent_header': {}, 'metadata': {}, 'content': {'comm_id': '691355e6ad1411ed842d14abc581ea52', 'data': {}}, 'buffers': []})
+- WARNING - <net:atomClass_sun_s2> does not look like a valid URI, trying to serialize this will break.
diff --git a/tests/test_rule.py b/tests/test_rule.py
index f21e6972..fdd76571 100644
--- a/tests/test_rule.py
+++ b/tests/test_rule.py
@@ -18,16 +18,28 @@ OUTPUT_DIR_PATH = f'{FILE_PATH}/output/'
 TEST_GRAPH = f'{INPUT_DIR_PATH}testGraph1.ttl'
 
 from context import tenet
-from tenet.febTransduction import phenomena_application_or
+from tenet.febTransduction import phenomena_application_or as test_rule
+from tenet.febTransduction import query_builder
 
 INDENT_STR = '            '
 
 
 
 #==============================================================================
-# In-Progress Development Method(s)
+# Useful Methods
 #==============================================================================
 
+def load_test_graph():
+    print(f'\n -- Test Graph Loading')
+    graph = Graph()
+    graph.bind('amr', Namespace('https://amr.tetras-libre.fr/rdf/schema#'))
+    graph.bind('net', Namespace('https://tenet.tetras-libre.fr/semantic-net#'))
+    graph.bind('base-out', Namespace('https://tenet.tetras-libre.fr/base-ontology#'))
+    graph.parse(TEST_GRAPH)
+    print(f" ----- Graph Loaded ({len(graph)})")
+    return graph
+
+
 def define_clause_list(composition_pattern_list):
     clause_list = []
     for (net_1, relation, net_2) in composition_pattern_list:
@@ -35,51 +47,84 @@ def define_clause_list(composition_pattern_list):
     return clause_list
 
 
+
+
 #==============================================================================
 # Development Test
 #==============================================================================
 
-print('\n *** Development Test ***')  
-
-print(f'\n -- Test Graph Loading')
-work_graph = Graph()
-work_graph.bind('net', Namespace('https://tenet.tetras-libre.fr/semantic-net#'))
-work_graph.parse(TEST_GRAPH)
-print(f"----- Graph Loaded ({len(work_graph)})")
-
-# print(f'\n -- Test Nets')
-# property_net = '?property_net'
-# class_net_0 = '?class_net_0'
-# phenomena_net = '?phenomena_net'
-
-print(f'\n -- Select Query Test')
-
-# select_data_list = [class_net_0, property_net, phenomena_net]
-# composition_pattern_list = []
-# composition_pattern_list.append((property_net, 'amr:role_ARG0', class_net_0))
-# composition_pattern_list.append((property_net, 'amr:role_ARG1', phenomena_net))
-# clause_list = define_clause_list(composition_pattern_list)
-# test_query = query_builder.generate_select_query(select_data_list, clause_list)
-# print(test_query)
-# query_result = work_graph.query(test_query)
-pattern_result_set = phenomena_application_or.apply_or_phenomena_pattern_1(work_graph)
-
-print(f'\n *** Select Result ***')
-for selection in pattern_result_set:
-    result_str = f'>>> '
-    result_str += f'{selection.class_net_0.n3(work_graph.namespace_manager)}'
-    result_str += f' {selection.property_net.n3(work_graph.namespace_manager)}'
-    result_str += f' {selection.phenomena_net.n3(work_graph.namespace_manager)}'
-    print(result_str) 
-
-print(f'\n -- Insert Query Test')
-triple_list = ['net:net1 a net:ClassNet.', 
-               'net:net2 a net:PropertyNet.',
-                'net:net3 a net:ClassNet.']
-test_query = query_builder.generate_insert_query(triple_list)
-print(test_query)
-work_graph.update(test_query)
-print(f"----- Graph Updated ({len(work_graph)})")
-  
-
-print('\n' + ' *** - ***')
\ No newline at end of file
+def devtest_select_pattern_application_1(graph):
+    print('\n -- Select Pattern Application 1')
+    query_code = test_rule.__select_pattern_1()
+    print(query_code)
+    pattern_result_set = graph.query(query_code) 
+    print(f'\n ----- number of selection found: {len(pattern_result_set)}')
+    for selection in pattern_result_set: 
+        result_str = f'>>> '
+        result_str += f'{selection.property_net.n3(graph.namespace_manager)}'
+        result_str += f' {selection.class_net.n3(graph.namespace_manager)}'
+        result_str += f' {selection.phenomena_net.n3(graph.namespace_manager)}'
+        print(result_str) 
+        
+
+def devtest_select_pattern_application_2(graph):
+    print('\n -- Select Pattern Application 2')
+    query_code = test_rule.__select_pattern_2()
+    print(query_code)
+    pattern_result_set = graph.query(query_code) 
+    print(f'\n ----- number of selection found: {len(pattern_result_set)}')
+    for selection in pattern_result_set: 
+        result_str = f'>>> '
+        result_str += f'{selection.property_net.n3(graph.namespace_manager)}'
+        result_str += f' {selection.property_net_0.n3(graph.namespace_manager)}'
+        result_str += f' {selection.phenomena_net.n3(graph.namespace_manager)}'
+        print(result_str) 
+           
+        
+def devtest_insert_query(graph):
+    print(f'\n -- Insert Query Test')
+    triple_list = ['net:net1 a net:ClassNet.', 
+                   'net:net2 a net:PropertyNet.',
+                    'net:net3 a net:ClassNet.']
+    test_query = query_builder.generate_insert_query(triple_list)
+    print(test_query)
+    graph.update(test_query)
+    print(f"----- Graph Updated ({len(graph)})")
+    
+    
+
+#==============================================================================
+# Unit Test
+#==============================================================================
+
+def unittest_rule_analyze_phenomena_or_2(graph):    
+    print('\n -- Rule Test')
+    rule_label, new_triple_list = test_rule.analyze_phenomena_or_2(graph)
+    print(f' ----- label: {rule_label}')
+    print(f' ----- new_triple_list: {len(new_triple_list)}')
+    for new_triple in new_triple_list:
+        print(f'        | {new_triple}')
+    
+
+
+#==============================================================================
+# Test Script
+#==============================================================================
+
+if __name__ == '__main__':
+      
+    print('\n *** Test Preparation ***')
+    graph = load_test_graph()
+    print('\n \n')
+    
+    print('\n *** Development Test ***')
+    devtest_select_pattern_application_1(graph)
+    devtest_select_pattern_application_2(graph)
+    devtest_insert_query(graph)
+    print('\n \n')
+    
+    print('\n *** Unit Test ***')
+    unittest_rule_analyze_phenomena_or_2(graph)
+    print('\n \n')
+
+    print('\n *** - ***')
\ No newline at end of file
diff --git a/tests/test_semantic_net_1.py b/tests/test_semantic_net_1.py
index 1bdc45a8..4f08b189 100644
--- a/tests/test_semantic_net_1.py
+++ b/tests/test_semantic_net_1.py
@@ -8,8 +8,9 @@
 #==============================================================================
 
 import subprocess, os
-from rdflib import Graph
-from rdflib import Namespace
+
+import rdflib
+from rdflib import Graph, Namespace, URIRef
 from rdflib.namespace import NamespaceManager
 
 FILE_PATH = f'{os.path.dirname(os.path.abspath(__file__))}'
@@ -40,9 +41,20 @@ from tenet.febTransduction.net import RestrictionNet
 
 
 #==============================================================================
-# Utilities
+# Useful Methods
 #==============================================================================
 
+def load_test_graph():
+    print(f'\n -- Test Graph Loading')
+    graph = Graph()
+    graph.bind('amr', Namespace('https://amr.tetras-libre.fr/rdf/schema#'))
+    graph.bind('net', Namespace('https://tenet.tetras-libre.fr/semantic-net#'))
+    graph.bind('base-out', Namespace('https://tenet.tetras-libre.fr/base-ontology#'))
+    graph.parse(TEST_GRAPH)
+    print(f" ----- Graph Loaded ({len(graph)})")
+    return graph
+
+
 def test_attribute_access(net, *attr_set):
     print(f'\n *** Net attributes ({net.type_id})) ***')
     for attr in attr_set:
@@ -54,96 +66,136 @@ def test_attribute_access(net, *attr_set):
 # Development Test
 #==============================================================================
 
-print('\n' + ' *** Development Test ***')
-print('\n *** TEST: Semantic Net Getters ***')
-
-print(f'\n -- Test Graph Loading')
-graph = Graph()
-graph.bind('net', Namespace('https://tenet.tetras-libre.fr/semantic-net#'))
-graph.parse(TEST_GRAPH)
-print(f" ----- Graph Loaded ({len(graph)})")
-
-print('\n -- Net')
-net_uri = 'https://tenet.tetras-libre.fr/semantic-net#atomClass_sun_s2'
-net = Net(graph, uri=net_uri)
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming')
-
-print('\n -- Class Net')
-net = ClassNet(graph, uri='net:atomClass_sun_s2')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.class_name')
-
-print('\n -- Atom Class Net')
-net = AtomClassNet(graph, uri='net:atomClass_sun_s2')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.class_name') 
-
-print('\n -- Composite Class Net (1)')
-net = CompositeClassNet(graph, uri='net:compositeClass_orbit-hasManner-conjunction-OR_o2')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.class_name',
-                      'net.mother_class_net', 'net.restriction', 'net.restriction01')
-
-print('\n -- Composite Class Net (2)')
-net = CompositeClassNet(graph, uri='net:compositeClass_system-hasPart-sun-and-object_s')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.class_name',
-                      'net.mother_class_net', 'net.restriction', 'net.restriction01')
-
-print('\n -- Property Net')
-net = PropertyNet(graph, uri='net:atomProperty_orbit_o2')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.property_name')
-
-print('\n -- Atom Property Net')
-net = AtomPropertyNet(graph, uri='net:atomProperty_orbit_o2')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.property_name',
-                      'net.core_role', 'net.target_argument_node', 'net.property_type',
-                      'net.property_name01', 'net.property_name10', 'net.property_name12')
-
-print('\n -- Composite Property Net')
-net = CompositePropertyNet(graph, uri='net:compositeProperty_not-direct_d2')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.property_name',
-                      'net.core_role', 'net.target_argument_node', 'net.property_type', 'net.restriction')
-
-print('\n -- Individual Net')
-net = IndividualNet(graph, uri='net:individual_system_SolarSystem')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.base_class_name', 'net.mother_class_net', 'net.individual_label')
-
-print('\n -- Value Net')
-net = ValueNet(graph, uri='net:value_SolarSystem_blankNode')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.value_label')
-
-print('\n -- Phenomena Net (1)')
-net = PhenomenaNet(graph, uri='net:phenomena_conjunction-AND_a')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.phenomena_type', 'net.phenomena_ref')
-
-print('\n -- Phenomena Net (1)')
-net = PhenomenaNet(graph, uri='net:phenomena_conjunction-OR_o3')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.phenomena_type', 'net.phenomena_ref')
-
-print('\n -- Restriction Net')
-net = RestrictionNet(graph, uri='net:restriction_hasPart_sun')
-test_attribute_access(net, 'net.uri', 
-                      'net.node', 'net.base_node', 'net.structure', 'net.naming',
-                      'net.target_node', 'net.restriction_property', 'net.restriction_net_value')
+def devtest_set_uri_attribute(graph):
+    print('\n -- Set URI attribute')
+    uri = 'https://tenet.tetras-libre.fr/semantic-net#atomClass_sun_s2'
+    print(f' ----- uri (1): {uri}')
+    if isinstance(uri, rdflib.term.URIRef):
+        uri = uri.n3(graph.namespace_manager)
+    elif isinstance(uri, str):
+        uri = URIRef(uri).n3(graph.namespace_manager)
+    print(f' ----- uri (1): {uri}')
     
-print('\n' + ' *** - ***')
\ No newline at end of file
+
+#==============================================================================
+# Unit Test
+#==============================================================================
+
+def unittest_get_attribute_net(graph, net_uri):
+    print('\n -- Net')
+    net_uri = 'https://tenet.tetras-libre.fr/semantic-net#atomClass_sun_s2'
+    net = Net(graph, uri=net_uri)
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming')
+
+def unittest_get_attribute_class_net(graph, net_uri):
+    print('\n -- Class Net')
+    net = ClassNet(graph, uri='net:atomClass_sun_s2')
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming',
+                          'net.class_name')
+
+def unittest_get_attribute_atom_class_net(graph, net_uri):    
+    print('\n -- Atom Class Net')
+    net = AtomClassNet(graph, uri='net:atomClass_sun_s2')
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming',
+                          'net.class_name') 
+
+def unittest_get_attribute_composite_class_net(graph, net_uri):    
+    print('\n -- Composite Class Net')
+    net = CompositeClassNet(graph, uri='net:compositeClass_orbit-hasManner-conjunction-OR_o2')
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming',
+                          'net.class_name',
+                          'net.mother_class_net', 'net.restriction', 'net.restriction01')
+
+def unittest_get_attribute_property_net(graph, net_uri):    
+    print('\n -- Property Net')
+    net = PropertyNet(graph, uri='net:atomProperty_orbit_o2')
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming',
+                          'net.property_name')
+ 
+def unittest_get_attribute_atom_property_net(graph, net_uri):   
+    print('\n -- Atom Property Net')
+    net = AtomPropertyNet(graph, uri='net:atomProperty_orbit_o2')
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming',
+                          'net.property_name',
+                          'net.core_role', 'net.target_argument_node', 'net.property_type',
+                          'net.property_name01', 'net.property_name10', 'net.property_name12')
+
+def unittest_get_attribute_composite_property_net(graph, net_uri):    
+    print('\n -- Composite Property Net')
+    net = CompositePropertyNet(graph, uri='net:compositeProperty_not-direct_d2')
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming',
+                          'net.property_name',
+                          'net.core_role', 'net.target_argument_node', 'net.property_type', 'net.restriction')
+
+def unittest_get_attribute_individual_net(graph, net_uri):    
+    print('\n -- Individual Net')
+    net = IndividualNet(graph, uri='net:individual_system_SolarSystem')
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming',
+                          'net.base_class_name', 'net.mother_class_net', 'net.individual_label')
+
+def unittest_get_attribute_value_net(graph, net_uri):    
+    print('\n -- Value Net')
+    net = ValueNet(graph, uri='net:value_SolarSystem_blankNode')
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming',
+                          'net.value_label')
+ 
+def unittest_get_attribute_phenomena_net(graph, net_uri):   
+    print('\n -- Phenomena Net')
+    net = PhenomenaNet(graph, uri='net:phenomena_conjunction-AND_a')
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming',
+                          'net.phenomena_type', 'net.phenomena_ref')
+
+def unittest_get_attribute_restriction_net(graph, net_uri):    
+    print('\n -- Restriction Net')
+    net = RestrictionNet(graph, uri='net:restriction_hasPart_sun')
+    test_attribute_access(net, 'net.uri', 
+                          'net.node', 'net.base_node', 'net.structure', 'net.naming',
+                          'net.target_node', 'net.restriction_property', 'net.restriction_net_value')
+
+
+#==============================================================================
+# Test Script
+#==============================================================================
+
+if __name__ == '__main__':
+      
+    print('\n *** Test Preparation ***')
+    graph = load_test_graph()
+    print('\n \n')
+    
+    print('\n *** Development Test ***')
+    devtest_set_uri_attribute(graph)
+    print('\n \n')
+    
+    print('\n *** Unit Test ***')
+    # unittest_get_attribute_net(graph, 'https://tenet.tetras-libre.fr/semantic-net#atomClass_sun_s2')
+
+    # unittest_get_attribute_class_net(graph, 'net:atomClass_sun_s2')
+    # unittest_get_attribute_atom_class_net(graph, 'net:atomClass_sun_s2')
+    # unittest_get_attribute_composite_class_net(graph, 'net:compositeClass_orbit-hasManner-conjunction-OR_o2')
+    # unittest_get_attribute_composite_class_net(graph, 'net:compositeClass_system-hasPart-sun-and-object_s')
+
+    # unittest_get_attribute_property_net(graph, 'net:atomProperty_orbit_o2')     
+    # unittest_get_attribute_atom_property_net(graph, 'net:atomProperty_orbit_o2')
+    # unittest_get_attribute_composite_property_net(graph, 'net:compositeProperty_not-direct_d2')
+    
+    # unittest_get_attribute_individual_net(graph, 'net:individual_system_SolarSystem')  
+
+    # unittest_get_attribute_value_net(graph, 'net:value_SolarSystem_blankNode')  
+     
+    # unittest_get_attribute_phenomena_net(graph, 'net:phenomena_conjunction-AND_a')
+    # unittest_get_attribute_phenomena_net(graph, 'net:phenomena_conjunction-OR_o3') 
+
+    # unittest_get_attribute_restriction_net(graph, 'net:restriction_hasPart_sun')  
+                      
+    print('\n \n')
\ No newline at end of file
-- 
GitLab