class HasKey(Annotatable): classExpression: ClassExpression objectPropertyExpressions: Optional[ List[ObjectPropertyExpression]] = empty_list() dataPropertyExpressions: Optional[ List[DataPropertyExpression]] = empty_list() annotations: List[Annotation] = empty_list() def __init__(self, classExpression: ClassExpression, *exprs: Union[ObjectPropertyExpression, DataPropertyExpression], annotations: List[Annotation] = None): self.classExpression = classExpression self.objectPropertyExpressions = [] self.dataPropertyExpressions = [] for expr in exprs: if isinstance(expr, ObjectPropertyExpression): self.objectPropertyExpressions.append(expr) else: self.dataPropertyExpressions.append(expr) self.annotations = annotations or [] super().__init__() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots( w, lambda: ((w + self.classExpression + '(').iter( self.objectPropertyExpressions) + ')' + '(').iter( self.dataPropertyExpressions) + ')')
class DatatypeDefinition((Annotatable)): datatype: Datatype datarange: DataRange annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots(w, lambda: w + self.datatype + ' ' + self.datarange)
class DisjointClasses(Annotatable): classExpressions: List[ClassExpression] annotations: List[Annotation] = empty_list() def __init__(self, *classExpression: ClassExpression, annotations: List[Annotation] = None) -> None: self.classExpressions = list(classExpression) self.annotations = annotations or [] super().__init__() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: self.list_cardinality(self.classExpressions, 'classExpressions', 2) if len(self.classExpressions) == 2: return self.annots( w, lambda: w + self.classExpressions[0] + self. classExpressions[1]) else: return self.annots(w, lambda: w.iter(self.classExpressions)) def to_rdf(self, g: Graph) -> None: if len(self.classExpressions) == 2: self.add_triple(g, self.classExpressions[0].to_rdf(g), OWL.disjointWith, self.classExpressions[1].to_rdf(g)) else: subj = BNode() g.add((subj, RDF.type, OWL.ALLDisjointClasses)) g.add((subj, OWL.members, SEQ(g, self.classExpressions))) self.TANN(g, subj)
class DifferentIndividuals(Annotatable): individuals: List[Individual] annotations: List[Annotation] = empty_list() def __init__(self, *individuals: Individual, annotations: Optional[List[Annotation]] = None) -> None: self.individuals = list(individuals) self.annotations = annotations or [] super().__init__() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.list_cardinality(self.individuals, 'individuals', 2).\ annots(w, lambda: w.iter(self.individuals, f=lambda o: w + o, indent=False)) def to_rdf(self, g: Graph) -> None: if len(self.individuals) == 2: self.add_triple(g, self.individuals[0].to_rdf(g), OWL.differentFrom, self.individuals[1].to_rdf(g)) elif len(self.individuals) > 2: subj = BNode() g.add((subj, RDF.type, OWL.AllDifferent)) g.add((subj, OWL.memebers, SEQ(g, self.individuals))) self.TANN(g, subj) return None
class Foo(FunOwlBase): v: List[Foo2] = empty_list() def to_functional(self, wr: FunctionalWriter) -> FunctionalWriter: return wr.iter(self.v, f=lambda e: wr.hardbr() + e) def to_functional2(self, wr: FunctionalWriter) -> FunctionalWriter: return wr.hardbr().indent().iter(self.v).outdent()
class DataPropertyRange((Annotatable)): dataPropertyExpression: DataPropertyExpression dataRange: DataRange annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots( w, lambda: w + self.dataPropertyExpression + ' ' + self.dataRange)
class ObjectPropertyRange(Annotatable): objectPropertyExpression: ObjectPropertyExpression classExpression: ClassExpression annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots( w, lambda: w + self.objectPropertyExpression + self.classExpression)
class SubDataPropertyOf(Annotatable): subDataPropertyExpression: DataPropertyExpression superDataPropertyExpression: DataPropertyExpression annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots( w, lambda: w + self.subDataPropertyExpression + self. superDataPropertyExpression)
class DataPropertyDomain((Annotatable)): dataPropertyExpression: DataPropertyExpression classExpression: ClassExpression annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots( w, lambda: w + self.dataPropertyExpression + ' ' + self. classExpression)
class InverseFunctionalObjectProperty(Annotatable): objectPropertyExpression: ObjectPropertyExpression annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots(w, lambda: w + self.objectPropertyExpression) def to_rdf(self, g: Graph) -> None: g.add((self.objectPropertyExpression.to_rdf(g), RDF.type, OWL.InverseFunctionalProperty))
class ClassAssertion(Annotatable): expr: ClassExpression individual: Individual annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots(w, lambda: w + self.expr + self.individual) def to_rdf(self, g: Graph) -> None: self.add_triple(g, self.individual.to_rdf(g), RDF.type, self.expr.to_rdf(g))
class DataPropertyAssertion(Annotatable): expr: DataPropertyExpression sourceIndividual: Individual targetValue: Literal annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots( w, lambda: w + self.expr + self.sourceIndividual + self.targetValue) def to_rdf(self, g: Graph) -> None: self.add_triple(g, self.sourceIndividual.to_rdf(g), self.expr.to_rdf(g), self.targetValue.to_rdf(g))
class EquivalentDataProperties((Annotatable)): dataPropertyExpressions: List[DataPropertyExpression] annotations: List[Annotation] = empty_list() def __init__(self, *dataPropertyExpressions: DataPropertyExpression, annotations: List[Annotation] = None) -> None: self.dataPropertyExpressions = list(dataPropertyExpressions) self.annotations = annotations or [] super().__init__() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: self.list_cardinality(self.dataPropertyExpressions, 'exprs', 2) return self.annots(w, lambda: w.iter(self.dataPropertyExpressions))
class ObjectPropertyChain(Annotatable): objectPropertyExpressions: List[ObjectPropertyExpression] annotations: List[Annotation] = empty_list() def __init__(self, *objectPropertyExpressions: ObjectPropertyExpression, annotations: List[Annotation] = None): self.objectPropertyExpressions = list(objectPropertyExpressions) self.annotations = annotations if annotations else [] super().__init__() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return w.func(self, lambda: w.iter(self.objectPropertyExpressions)) def to_rdf(self, g: Graph) -> BNode: return SEQ(g, self.objectPropertyExpressions)
class EquivalentObjectProperties(Annotatable): objectPropertyExpressions: List[ObjectPropertyExpression] annotations: List[Annotation] = empty_list() def __init__(self, *objectPropertyExpressions: ObjectPropertyExpression, annotations: Optional[List[Annotation]] = None) -> None: self.objectPropertyExpressions = list(objectPropertyExpressions) self.annotations = annotations or [] super().__init__() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots(w, lambda: w.iter(self.objectPropertyExpressions)) def f(self, a, b, c, d=12, e=32): pass
class NegativeDataPropertyAssertion(Annotatable): expr: DataPropertyExpression sourceIndividual: Individual targetValue: Literal annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots( w, lambda: w + self.expr + self.sourceIndividual + self.targetValue) def to_rdf(self, g: Graph) -> None: subj = BNode() g.add((subj, RDF.type, OWL.NegativePropertyAssertion)) g.add((subj, OWL.sourceIndividual, self.sourceIndividual.to_rdf(g))) g.add((subj, OWL.assertionProperty, self.expr.to_rdf(g))) g.add((subj, OWL.targetValue, self.targetValue.to_rdf(g))) self.TANN(g, subj)
class SubClassOf(Annotatable): subClassExpression: ClassExpression superClassExpression: ClassExpression annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots( w, lambda: (w + self.subClassExpression + self.superClassExpression)) def to_rdf(self, g: Graph) -> None: """ Add subclass representation to graph :param g: Graph to add representation to :return: None - """ self.add_triple(g, self.subClassExpression.to_rdf(g), RDFS.subClassOf, self.superClassExpression.to_rdf(g))
class DisjointObjectProperties(Annotatable): objectPropertyExpressions: List[ObjectPropertyExpression] annotations: List[Annotation] = empty_list() def __init__(self, *objectPropertyExpressions: ObjectPropertyExpression, annotations: Optional[List[Annotation]] = None) -> None: self.objectPropertyExpressions = list(objectPropertyExpressions) self.annotations = annotations or [] super().__init__() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots(w, lambda: w.iter(self.objectPropertyExpressions)) def to_rdf(self, g: Graph) -> None: self.add_triple(g, self.objectPropertyExpressions[0].to_rdf(g), OWL.propertyDisjointWith, self.objectPropertyExpressions[1].to_rdf(g))
class InverseObjectProperties(Annotatable): objectPropertyExpressions: List[ObjectPropertyExpression] annotations: List[Annotation] = empty_list() def __init__(self, *objectPropertyExpressions: ObjectPropertyExpression, annotations: List[Annotation] = None) \ -> None: self.objectPropertyExpressions = list(objectPropertyExpressions) self.annotations = annotations or [] def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: self.list_cardinality(self.objectPropertyExpressions, 'expressions', 2, 2) return w.func( self, lambda: w + self.objectPropertyExpressions[0] + self. objectPropertyExpressions[1]) def to_rdf(self, g: Graph) -> None: g.add((self.objectPropertyExpressions[0].to_rdf(g), OWL.inverseOf, self.objectPropertyExpressions[1].to_rdf(g)))
class DisjointDataProperties((Annotatable)): dataPropertyExpressions: List[DataPropertyExpression] annotations: List[Annotation] = empty_list() def __init__(self, *dataPropertyExpressions: DataPropertyExpression, annotations: List[Annotation] = None) -> None: self.dataPropertyExpressions = list(dataPropertyExpressions) self.annotations = annotations or [] super().__init__() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: self.list_cardinality(self.dataPropertyExpressions, 'exprs', 2) return self.annots(w, lambda: w.iter(self.dataPropertyExpressions)) def to_rdf(self, g: Graph) -> None: self.add_triple(g, self.dataPropertyExpressions[0].to_rdf(g), OWL.propertyDisjointWith, self.dataPropertyExpressions[1].to_rdf(g))
class DisjointUnion(Annotatable): cls: Class disjointClassExpressions: List[ClassExpression] annotations: List[Annotation] = empty_list() def __init__(self, cls: Class, *disjointClassExpression: ClassExpression, annotations: List[Annotation] = None) -> None: self.cls = cls self.disjointClassExpressions = list(disjointClassExpression) self.annotations = annotations or [] super().__init__() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: self.list_cardinality(self.disjointClassExpressions, 'disjointClassExpressions', 2) return self.annots( w, lambda: (w + self.cls).iter(self.disjointClassExpressions))
class SameIndividual(Annotatable): individuals: List[Individual] annotations: List[Annotation] = empty_list() def __init__(self, *individuals: Individual, annotations: Optional[List[Annotation]] = None) -> None: self.individuals = list(individuals) self.annotations = annotations or [] super().__init__() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.list_cardinality(self.individuals, 'individuals', 2).\ annots(w, lambda: w.iter(self.individuals, f=lambda o: w + o, indent=False)) def to_rdf(self, g: Graph) -> None: for i in range(1, len(self.individuals)): self.add_triple(g, self.individuals[i - 1].to_rdf(g), OWL.sameAs, self.individuals[i].to_rdf(g))
class EquivalentClasses(Annotatable): classExpressions: List[ClassExpression] annotations: List[Annotation] = empty_list() def __init__(self, *classExpression: ClassExpression, annotations: List[Annotation] = None) -> None: self.classExpressions = list(classExpression) self.annotations = annotations or [] def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: self.list_cardinality(self.classExpressions, 'classExpressions', 2) return self.annots(w, lambda: w.iter(self.classExpressions)) def to_rdf(self, g: Graph) -> None: subj = self.classExpressions[0].to_rdf(g) for i in range(1, len(self.classExpressions)): obj = self.classExpressions[i].to_rdf(g) g.add((subj, OWL.equivalentClass, obj)) subj = obj
class SubObjectPropertyOf(Annotatable): subObjectPropertyExpression: SubObjectPropertyExpression.types() superObjectPropertyExpression: ObjectPropertyExpression.types() annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots( w, lambda: (w + self.subObjectPropertyExpression + self. superObjectPropertyExpression)) def to_rdf(self, g: Graph) -> None: if issubclass(type(self.subObjectPropertyExpression), ObjectPropertyChain): self.add_triple(g, self.superObjectPropertyExpression.to_rdf(g), OWL.propertyChainAxiom, self.subObjectPropertyExpression.to_rdf(g)) else: self.add_triple(g, self.subObjectPropertyExpression.to_rdf(g), RDF.subPropertyOf, self.superObjectPropertyExpression.to_rdf(g))
class ObjectPropertyAssertion(Annotatable): # Should be ObjectProperty instead of ObjectPropertyExpression expr: ObjectPropertyExpression sourceIndividual: Individual targetIndividual: Individual annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots( w, lambda: w + self.expr + self.sourceIndividual + self. targetIndividual) def to_rdf(self, g: Graph) -> None: # ObjectPropertyAssertion( OP a1 a2 ) T(a1) T(OP) T(a2) . # ObjectPropertyAssertion( ObjectInverseOf( OP ) a1 a2 ) T(a2) T(OP) T(a1) . if issubclass(type(self.expr), ObjectInverseOf): self.add_triple(g, self.targetIndividual.to_rdf(g), self.expr.v.v.to_rdf(g), self.sourceIndividual.to_rdf(g)) else: self.add_triple(g, self.sourceIndividual.to_rdf(g), self.expr.to_rdf(g), self.targetIndividual.to_rdf(g))
class Ontology(Annotatable): iri: Optional[IRI.types()] = None version: Optional[IRI.types()] = None directlyImportsDocuments: List[Import] = empty_list() axioms: List[Axiom] = empty_list() annotations: List[Annotation] = empty_list() def __init__(self, *args: Union[FunOwlBase, IRI.types()], **kwargs: Dict[str, FunOwlBase]) -> None: args = list(args) if args and isinstance(args[0], IRI) and not isinstance_(args[0], Axiom): self.iri = args.pop(0) if args and isinstance(args[0], IRI) and not isinstance_(args[0], Axiom): self.version = args.pop(0) self.directlyImportsDocuments = cast(List[Import], []) while args and isinstance(args[0], Import): self.directlyImportsDocuments.append(args.pop(0)) self.axioms = cast(List[Axiom], []) while args and isinstance_(args[0], Axiom): self.axioms.append(args.pop(0)) self.annotations = kwargs.get('annotations', []) for k, v in kwargs.items(): cur_v = getattr(self, k, MISSING) if cur_v is MISSING: raise ValueError(f"Unknown argument to Ontology: {k}") if cur_v is None: setattr(self, k, v) elif k != 'annotations': setattr(self, k, cur_v + v) if args: raise ValueError(f"Unrecognized arguments to Ontology: {args}") self._naxioms = 0 def add_arg(self, arg: [IRI.types(), Import, Axiom, Annotation]): if isinstance_(arg, Axiom): self.axioms.append(arg) self._naxioms += 1 if not self._naxioms % 100000: print('H') elif not self._naxioms % 10000: print('K') elif not self._naxioms % 1000: print('k', end='') sys.stdout.flush() elif not self._naxioms % 100: print('.', end='') sys.stdout.flush() elif isinstance(arg, IRI): if not self.iri: self.iri = arg elif not self.version: self.version = arg else: raise ValueError(f"Raw IRI is not a valid argument {arg}") elif isinstance(arg, Import): self.directlyImportsDocuments.append(arg) elif isinstance(arg, Annotation): self.annotations.append(arg) else: raise ValueError(f"Unrecognized argument to Ontology: {arg}") # ======================= # Syntactic sugar -- fill these in as needed # ======================= def annotation( self, prop: AnnotationProperty.types(), value: AnnotationValue.types() ) -> "Ontology": self.annotations.append(Annotation(prop, value)) return self def declarations(self, *declarations: Declaration.types()) -> "Ontology": for declaration in declarations: self.axioms.append(Declaration(declaration)) return self def subClassOf(self, sub: Class.types(), sup: Class.types()) -> "Ontology": if not issubclass(type(sub), Class) and isinstance(sub, Class): sub = Class(sub) if not issubclass(type(sup), Class) and isinstance(sup, Class): sup = Class(sup) self.axioms.append(SubClassOf(sub, sup)) return self def equivalentClasses(self, *classExpressions: ClassExpression) -> "Ontology": self.axioms.append(EquivalentClasses(*classExpressions)) return self def subObjectPropertyOf(self, sub: SubObjectPropertyExpression.types(), sup: ObjectPropertyExpression.types()) \ -> "Ontology": subp = SubObjectPropertyExpression(sub) supp = ObjectPropertyExpression(sup) self.axioms.append(SubObjectPropertyOf(subp, supp)) return self def inverseObjectProperties(self, exp1: ObjectPropertyExpression.types(), exp2: ObjectPropertyExpression.types()) \ -> "Ontology": exp1p = ObjectPropertyExpression(exp1) exp2p = ObjectPropertyExpression(exp2) self.axioms.append(InverseObjectProperties(exp1p, exp2p)) return self def functionalObjectProperty( self, ope: ObjectPropertyExpression.types()) -> "Ontology": opep = ObjectPropertyExpression(ope) self.axioms.append(FunctionalObjectProperty(opep)) return self def inverseFunctionalObjectProperty( self, ope: ObjectPropertyExpression.types()) -> "Ontology": opep = ObjectPropertyExpression(ope) self.axioms.append(InverseFunctionalObjectProperty(opep)) return self def objectPropertyDomain(self, ope: ObjectPropertyExpression.types(), ce: ClassExpression) -> "Ontology": self.axioms.append(ObjectPropertyDomain(ope, ce)) return self def objectPropertyRange(self, ope: ObjectPropertyExpression.types(), ce: ClassExpression) -> "Ontology": self.axioms.append(ObjectPropertyRange(ope, ce)) return self def imports(self, import_: Union["Ontology", str]) -> "Ontology": self.directlyImportsDocuments.append( Import(import_.iri if isinstance(import_, Ontology ) else IRI(str(import_)))) return self def namedIndividuals(self, *individuals: IRI.types()) -> "Ontology": for individual in individuals: self.axioms.append(NamedIndividual(individual)) return self def dataPropertyAssertion( self, expr: DataPropertyExpression.types(), sourceIndividual: Individual.types(), targetValue: Literal.types() ) -> "Ontology": self.axioms.append( DataPropertyAssertion(expr, sourceIndividual, targetValue)) return self # ==================== # Conversion functions # ==================== def to_functional(self, w: Optional[FunctionalWriter]) -> FunctionalWriter: """ Return a FunctionalWriter instance with the representation of the ontology in functional syntax """ if self.version and not self.iri: raise ValueError( f"Ontology cannot have a versionIRI ({self.version} without an ontologyIRI" ) w = w or FunctionalWriter() return w.func(self, lambda: w.opt(self.iri).opt(self.version).br( bool(self.directlyImportsDocuments) or bool( self.annotations) or bool(self.axioms)). iter(self.directlyImportsDocuments, indent=False).iter( self.annotations, indent=False).iter(self.axioms, indent=False), indent=False) def to_rdf(self, g: Graph) -> SUBJ: ontology_uri = self.iri.to_rdf(g) if self.iri else BNode() version_uri = self.version.to_rdf(g) if self.version else None g.add((ontology_uri, RDF.type, OWL.Ontology)) if self.version: g.add((ontology_uri, OWL.versionIRI, version_uri)) for imp in self.directlyImportsDocuments: g.add((ontology_uri, OWL.imports, imp.to_rdf(g))) for axiom in self.axioms: axiom.to_rdf(g) super().to_rdf(g) return ontology_uri
class OntologyDocument(FunOwlBase): """ prefixDeclarations are """ prefixDeclarations: List[Prefix] = empty_list() ontology: Ontology = None def __init__(self, default_prefix: FullIRI = None, ontology: Optional[Ontology] = None, **prefixes: FullIRI): self.prefixDeclarations = [] self.ontology = ontology if ontology is not None else Ontology() if default_prefix: self.prefixDeclarations.append(Prefix(None, default_prefix)) if prefixes: for k, v in prefixes.items(): self.prefixDeclarations.append(Prefix(k, v)) def prefixes(self, dflt: Optional[FullIRI], **prefixes: FullIRI) -> None: if dflt: self.prefixDeclarations.append(Prefix('', dflt)) for ns, iri in prefixes.items(): self.prefixDeclarations.append(Prefix(PrefixName(ns), iri)) def __setattr__(self, key: str, value) -> None: if key.startswith('_') or key in ('prefixDeclarations', 'ontology'): super().__setattr__(key, value) else: prefix = Prefix(PrefixName(key) if key else None, FullIRI(value)) self.prefixDeclarations.append(prefix) def __getattr__(self, item): # This gets called only when something isn't already in the dictionary if isinstance(item, PrefixName): for p in self.prefixDeclarations: if p.prefixName == item: return p.fullIRI return super().__getattribute__(item) def __str__(self) -> str: return self.to_functional().getvalue() def add_namespaces(self, g: Graph) -> Graph: for prefix in self.prefixDeclarations: g.namespace_manager.bind(str(prefix.prefixName or ''), str(prefix.fullIRI), True, True) return g def to_functional(self, w: Optional[FunctionalWriter] = None ) -> FunctionalWriter: """ Return a FunctionalWriter instance with the representation of the OntologyDocument in functional syntax """ w = w or FunctionalWriter() self.add_namespaces(w.g) return w.iter([Prefix(ns, uri) for ns, uri in w.g.namespaces()], indent=False).hardbr() +\ (self.ontology or Ontology()) def to_rdf(self, g: Graph) -> SUBJ: self.add_namespaces(g) return self.ontology.to_rdf(g)
class TransitiveObjectProperty(Annotatable): objectPropertyExpression: ObjectPropertyExpression annotations: List[Annotation] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return self.annots(w, lambda: w + self.objectPropertyExpression)
class C1(FunOwlBase): instnum: int foos: List["C1"] = empty_list() def to_functional(self, w: FunctionalWriter) -> FunctionalWriter: return w.func(self, lambda: w.br().indent().concat(self.instnum, ':', sep='').outdent().iter(self.foos))
class Foo(FunOwlBase): v: List[int] = empty_list()