From 81a141fa37bfb0a83711a823aaf07d70223ba0db Mon Sep 17 00:00:00 2001 From: Codex Autonomy Date: Thu, 11 Jun 2026 13:12:12 +0530 Subject: [PATCH] Parse datatype complements Signed-off-by: Codex Autonomy --- base.py | 3 +-- class_construct.py | 16 +++++++++++++--- namespace.py | 1 + test/regtest.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/base.py b/base.py index b1eb385..d20375d 100644 --- a/base.py +++ b/base.py @@ -210,6 +210,7 @@ def declare_datatype(datatype, iri, parser, unparser): owl_annotatedproperty = _universal_abbrev("http://www.w3.org/2002/07/owl#annotatedProperty") owl_annotatedtarget = _universal_abbrev("http://www.w3.org/2002/07/owl#annotatedTarget") owl_complementof = _universal_abbrev("http://www.w3.org/2002/07/owl#complementOf") +owl_datatypecomplementof = _universal_abbrev("http://www.w3.org/2002/07/owl#datatypeComplementOf") owl_disjointwith = _universal_abbrev("http://www.w3.org/2002/07/owl#disjointWith") owl_propdisjointwith = _universal_abbrev("http://www.w3.org/2002/07/owl#propertyDisjointWith") rdfs_datatype = _universal_abbrev("http://www.w3.org/2000/01/rdf-schema#Datatype") @@ -279,5 +280,3 @@ def declare_datatype(datatype, iri, parser, unparser): issubclass_python = issubclass - - diff --git a/class_construct.py b/class_construct.py index f374b82..49708c6 100644 --- a/class_construct.py +++ b/class_construct.py @@ -112,7 +112,11 @@ def __repr__(self): return "Not(%s)" % (self.Class) def __getattr__(self, attr): if attr == "Class": - self.__dict__["Class"] = C = self.ontology._to_python(self.ontology._get_obj_triple_sp_o(self.storid, owl_complementof), default_to_none = True) + o = self.ontology._get_obj_triple_sp_o(self.storid, owl_complementof) + if o is None: o = self.ontology._get_obj_triple_sp_o(self.storid, owl_datatypecomplementof) + if o is None: C = None + else: C = self.ontology._to_python(o, default_to_none = True) + self.__dict__["Class"] = C return C return super().__getattribute__(attr) @@ -130,8 +134,14 @@ def __setattr__(self, attr, value): def _create_triples(self, ontology): ClassConstruct._create_triples(self, ontology) - ontology._set_obj_triple_spo(self.storid, rdf_type, owl_class) - ontology._set_obj_triple_spo(self.storid, owl_complementof, self.Class.storid) + if self.Class in _universal_datatype_2_abbrev: + ontology._set_obj_triple_spo(self.storid, rdf_type, rdfs_datatype) + ontology._del_obj_triple_spo(self.storid, owl_complementof, None) + ontology._set_obj_triple_spo(self.storid, owl_datatypecomplementof, _universal_datatype_2_abbrev[self.Class]) + else: + ontology._set_obj_triple_spo(self.storid, rdf_type, owl_class) + ontology._del_obj_triple_spo(self.storid, owl_datatypecomplementof, None) + ontology._set_obj_triple_spo(self.storid, owl_complementof, self.Class.storid) def _satisfied_by(self, x): return not self.Class._satisfied_by(x) diff --git a/namespace.py b/namespace.py index 723c925..48896ba 100644 --- a/namespace.py +++ b/namespace.py @@ -1000,6 +1000,7 @@ def _parse_bnode(self, bnode): return self.world._parse_bnode(bnode) for pred, obj in preds_objs: if pred == owl_complementof: r = Not (None, self, bnode); break # will parse the rest on demand + elif pred == owl_datatypecomplementof: r = Not (None, self, bnode); break # will parse the rest on demand elif pred == owl_unionof: r = Or (obj , self, bnode); break elif pred == owl_intersectionof: r = And (obj , self, bnode); break #elif pred == owl_disjointunion: r = DisjointUnion(obj , self, bnode); break diff --git a/test/regtest.py b/test/regtest.py index 74c0301..8aef63a 100644 --- a/test/regtest.py +++ b/test/regtest.py @@ -2686,6 +2686,50 @@ class C3(Thing): namespace = n self.assert_triple(NOT.storid, rdf_type, owl_class) self.assert_triple(NOT.storid, owl_complementof, C1.storid) self.assert_triple(C2.storid, rdfs_subclassof, NOT.storid) + + def test_construct_not_datatype(self): + n = self.new_ontology() + + NOT = Not(int) + NOT._set_ontology(n) + + self.assert_triple(NOT.storid, rdf_type, rdfs_datatype) + self.assert_triple(NOT.storid, owl_datatypecomplementof, _universal_datatype_2_abbrev[int]) + self.assert_not_triple(NOT.storid, owl_complementof, _universal_datatype_2_abbrev[int]) + + def test_parse_datatype_complement_of(self): + n = self.new_ontology() + datatype_complement = n.world.new_blank_node() + + n._add_obj_triple_spo(datatype_complement, rdf_type, rdfs_datatype) + n._add_obj_triple_spo(datatype_complement, owl_datatypecomplementof, _universal_datatype_2_abbrev[int]) + + parsed = n._parse_bnode(datatype_complement) + + assert isinstance(parsed, Not) + assert parsed.Class is int + + def test_parse_datatype_intersection_with_complement(self): + n = self.new_ontology() + datatype_complement = n.world.new_blank_node() + intersection = n.world.new_blank_node() + list_bnode = n.world.new_blank_node() + + n._add_obj_triple_spo(datatype_complement, rdf_type, rdfs_datatype) + n._add_obj_triple_spo(datatype_complement, owl_datatypecomplementof, _universal_datatype_2_abbrev[int]) + n._add_obj_triple_spo(intersection, rdf_type, rdfs_datatype) + n._add_obj_triple_spo(intersection, owl_intersectionof, list_bnode) + n._set_list_as_rdf(list_bnode, [ + (_universal_datatype_2_abbrev[float], None), + (datatype_complement, None), + ]) + + parsed = n._parse_bnode(intersection) + + assert isinstance(parsed, And) + assert parsed.Classes[0] is float + assert isinstance(parsed.Classes[1], Not) + assert parsed.Classes[1].Class is int def test_construct_restriction_1(self): n = get_ontology("http://www.semanticweb.org/jiba/ontologies/2017/0/test")